diff options
author | unknown <unknown@unknown> | 2009-10-23 04:29:39 +0000 |
---|---|---|
committer | unknown <unknown@unknown> | 2009-10-23 04:29:39 +0000 |
commit | ddf5c42f67757000d6ec7686b92a667c2a252dca (patch) | |
tree | e070b352fab4b285b7a4ea547d0cbfff9b7fb4d1 /tools/ikslint.c | |
download | iksemel-ddf5c42f67757000d6ec7686b92a667c2a252dca.tar.gz iksemel-ddf5c42f67757000d6ec7686b92a667c2a252dca.tar.xz iksemel-ddf5c42f67757000d6ec7686b92a667c2a252dca.zip |
Imported from iksemel-1.3.tar.gz.
Diffstat (limited to 'tools/ikslint.c')
-rw-r--r-- | tools/ikslint.c | 283 |
1 files changed, 283 insertions, 0 deletions
diff --git a/tools/ikslint.c b/tools/ikslint.c new file mode 100644 index 0000000..0b655d2 --- /dev/null +++ b/tools/ikslint.c @@ -0,0 +1,283 @@ +/* iksemel (XML parser for Jabber) +** Copyright (C) 2000-2003 Gurer Ozen <madcat@e-kolay.net> +** This code is free software; you can redistribute it and/or +** modify it under the terms of GNU Lesser General Public License. +*/ + +#include "common.h" +#include "iksemel.h" + +struct hash_s; +typedef struct hash_s hash; + +hash *hash_new (unsigned int table_size); +char *hash_insert (hash *table, const char *name); +void hash_print (hash *h, char *title_fmt, char *line_fmt); +void hash_delete (hash *table); + +#include <sys/stat.h> + +#ifdef HAVE_GETOPT_LONG +#include <getopt.h> +#endif + +#ifdef HAVE_GETOPT_LONG +static struct option longopts[] = { + { "stats", 0, 0, 's' }, + { "histogram", 0, 0, 't' }, + { "help", 0, 0, 'h' }, + { "version", 0, 0, 'V' }, + { 0, 0, 0, 0 } +}; +#endif + +static char *shortopts = "sthV"; + +static void +print_usage (void) +{ + puts ("Usage: ikslint [OPTIONS] FILE\n" + "This tool checks the well-formedness of an XML document.\n" + " -s, --stats Print statistics.\n" + " -t, --histogram Print tag histogram.\n" + " -h, --help Print this text and exit.\n" + " -V, --version Print version and exit.\n" +#ifndef HAVE_GETOPT_LONG + "(long options are not supported on your system)\n" +#endif + "Report bugs to <iksemel-dev@jabberstudio.org>."); +} + +/* calculate and print statistics */ +int lint_pr_stats = 0; + +/* print tag histogram */ +int lint_pr_hist = 0; + +hash *tag_table; + +char **tag_list; +int tag_size, tag_pos; + +void +tag_push (const char *name) +{ + if (!tag_list) { + tag_size = 128; + tag_list = malloc (sizeof (char *) * tag_size); + if (!tag_list) exit (2); + } + tag_list[tag_pos] = hash_insert (tag_table, name); + if (!tag_list[tag_pos]) exit (2); + tag_pos++; + if (tag_pos == tag_size) { + char **tmp; + tmp = malloc (sizeof (char *) * tag_size * 2); + if (!tmp) exit (2); + memcpy (tmp, tag_list, sizeof (char *) * tag_size); + free (tag_list); + tag_list = tmp; + tag_size *= 2; + } +} + +char * +tag_pull (void) +{ + tag_pos--; + return tag_list[tag_pos]; +} + +struct stats { + unsigned int level; + unsigned int max_depth; + unsigned int nr_tags; + unsigned int nr_stags; + unsigned int cdata_size; +}; + +int +tagHook (void *udata, char *name, char **atts, int type) +{ + struct stats *st = (struct stats *) udata; + char *tmp; + + switch (type) { + case IKS_OPEN: + tag_push (name); + st->level++; + if (st->level > st->max_depth) st->max_depth = st->level; + break; + case IKS_CLOSE: + tmp = tag_pull (); + if (iks_strcmp (tmp, name) != 0) { + fprintf (stderr, "Tag mismatch, expecting '%s', got '%s'.\n", + tmp, name); + return IKS_HOOK; + } + st->level--; + st->nr_tags++; + break; + case IKS_SINGLE: + if (NULL == hash_insert (tag_table, name)) exit (2); + st->nr_stags++; + break; + } + return IKS_OK; +} + +int +cdataHook (void *udata, char *data, size_t len) +{ + struct stats *st = (struct stats *) udata; + + st->cdata_size += len; + return IKS_OK; +} + +void +check_file (char *fname) +{ + iksparser *prs; + struct stats st; + FILE *f; + char *buf; + struct stat fs; + size_t sz, blk, ret, pos; + enum ikserror err; + int done; + + memset (&st, 0, sizeof (struct stats)); + prs = iks_sax_new (&st, tagHook, cdataHook); + if (NULL == prs) exit (2); + + if (fname) { + if (stat (fname, &fs) != 0) { + fprintf (stderr, "Cannot access file '%s'.\n", fname); + exit (1); + } + sz = fs.st_size; +#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE + blk = fs.st_blksize; +#else + blk = 4096; +#endif + f = fopen (fname, "r"); + if (!f) { + fprintf (stderr, "Cannot open file '%s'.\n", fname); + exit (1); + } + buf = malloc (blk); + if (!buf) { + fclose (f); + fprintf (stderr, "Cannot allocate %d bytes.\n", blk); + exit (2); + } + } else { + f = stdin; + blk = 4096; + sz = 0; + buf = malloc (blk); + if (!buf) exit (2); + } + + tag_table = hash_new (367); + if (!tag_table) exit (2); + + pos = 0; + done = 0; + while (0 == done) { + ret = fread (buf, 1, blk, f); + pos += ret; + if (feof (f)) { + done = 1; + } else { + if (ret != blk) { + if (fname) + fprintf (stderr, "Read error in file '%s'.\n", fname); + else + fprintf (stderr, "Read error in stream.\n"); + exit (1); + } + } + err = iks_parse (prs, buf, ret, done); + switch (err) { + case IKS_OK: + break; + case IKS_NOMEM: + exit (2); + case IKS_BADXML: + if (fname) + fprintf (stderr, "Invalid xml at byte %ld, line %ld in file '%s'.\n", + iks_nr_bytes (prs), iks_nr_lines (prs), fname); + else + fprintf (stderr, "Invalid xml at byte %ld, line %ld in stream.\n", + iks_nr_bytes (prs), iks_nr_lines (prs)); + exit (1); + case IKS_HOOK: + if (fname) + fprintf (stderr, "Byte %ld, line %ld in file '%s'.\n", + iks_nr_bytes (prs), iks_nr_lines (prs), fname); + else + fprintf (stderr, "Byte %ld, line %ld in stream.\n", + iks_nr_bytes (prs), iks_nr_lines (prs)); + exit (1); + } + } + + free (buf); + if (fname) fclose (f); + + if (fname && (lint_pr_stats || lint_pr_hist)) { + printf ("File '%s' (%d bytes):\n", fname, sz); + } + if (lint_pr_stats) { + printf ("Tags: %d pairs, %d single, %d max depth.\n", st.nr_tags, st.nr_stags, st.max_depth); + printf ("Total size of character data: %d bytes.\n", st.cdata_size); + } + if (lint_pr_hist) { + hash_print (tag_table, + "Histogram of %d unique tags:\n", + "<%s> %d times.\n"); + } + hash_delete (tag_table); + + iks_parser_delete (prs); +} + +int +main (int argc, char *argv[]) +{ + int c; + +#ifdef HAVE_GETOPT_LONG + int i; + while ((c = getopt_long (argc, argv, shortopts, longopts, &i)) != -1) { +#else + while ((c = getopt (argc, argv, shortopts)) != -1) { +#endif + switch (c) { + case 's': + lint_pr_stats = 1; + break; + case 't': + lint_pr_hist = 1; + break; + case 'h': + print_usage (); + exit (0); + case 'V': + puts ("ikslint (iksemel) "VERSION); + exit (0); + } + } + if (!argv[optind]) { + check_file (NULL); + } else { + for (; optind < argc; optind++) { + check_file (argv[optind]); + } + } + + return 0; +} |