Annotation of docbook2mdoc/statistics.c, Revision 1.41
1.41 ! schwarze 1: /* $Id: statistics.c,v 1.40 2019/05/01 12:52:05 schwarze Exp $ */
1.1 schwarze 2: /*
3: * Copyright (c) 2019 Ingo Schwarze <schwarze@openbsd.org>
4: *
5: * Permission to use, copy, modify, and distribute this software for any
6: * purpose with or without fee is hereby granted, provided that the above
7: * copyright notice and this permission notice appear in all copies.
8: *
9: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
10: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
12: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16: */
1.37 schwarze 17: #include <sys/types.h>
18:
1.1 schwarze 19: #include <assert.h>
20: #include <ctype.h>
21: #include <err.h>
22: #include <fcntl.h>
1.2 schwarze 23: #include <getopt.h>
1.1 schwarze 24: #include <stdio.h>
25: #include <stdlib.h>
26: #include <string.h>
27: #include <unistd.h>
28:
1.37 schwarze 29: #include "xmalloc.h"
30:
1.1 schwarze 31: /*
32: * Count parent-child element relations in a corpus of DocBook documents.
33: *
34: * Read absolute or relative input file names from standard input,
35: * one per line.
36: * For each parent-child relation, print the total number of occurrences,
37: * the parent name, and the child name, separated by tab characters
38: * and followed by a newline character.
39: *
40: * Typical usage:
41: * statistics < filenames.txt | sort -n
42: * statistics < filenames.txt | grep '\<listitem\>' | sort -n
1.4 schwarze 43: *
44: * Relations already fully implemented are excluded by default.
45: * The option -a shows all relations.
46: *
47: * If two arguments (parent and child) are given, a histogram
48: * of the number of children of the kind in each parent is given
49: * in addition to the normal output.
50: *
51: * Example usage:
52: * statistics tgroup colspec < filenames.txt | grep colspec
1.25 schwarze 53: *
54: * Synchronized with parse.c up to rev. 1.42.
1.1 schwarze 55: */
56:
57: struct entry {
58: char *parent;
59: char *child;
60: int count;
61: };
62:
63: static struct entry *table;
64: static size_t tablesz;
65: static size_t tablei;
66:
67: static char **stack;
68: static size_t stacksz;
69: static size_t stacki;
70:
1.4 schwarze 71: static const int nchildsz = 8;
72: struct nchild {
73: char *parent;
74: char *child;
75: int freq[nchildsz];
76: int count;
77: };
78:
79: static struct nchild nchild;
80: static char *fname;
81:
1.1 schwarze 82:
83: /*
84: * Count one instance of a parent-child relation.
1.2 schwarze 85: * Before the special call table_add(NULL, NULL),
86: * mark relations to not be counted;
87: * in that phase, child can be NULL as a wildcard.
1.1 schwarze 88: */
89: static void
90: table_add(const char *parent, const char *child)
91: {
1.2 schwarze 92: static int init_done;
93: size_t i;
94:
95: if (parent == NULL && child == NULL) {
96: init_done = 1;
97: return;
98: }
1.1 schwarze 99:
1.4 schwarze 100: /* Optional parent-child histogram. */
101:
102: if (init_done && parent != NULL && child != NULL &&
103: nchild.parent != NULL && nchild.child != NULL &&
104: strcmp(parent, nchild.parent) == 0 &&
105: strcmp(child, nchild.child) == 0) {
106: if (nchild.count < nchildsz) {
107: nchild.freq[nchild.count]++;
108: if (nchild.count > 0)
109: nchild.freq[nchild.count - 1]--;
110: } else if (nchild.count == nchildsz)
111: puts(fname);
112: nchild.count++;
113: }
114:
1.1 schwarze 115: /* If the table entry already exists, increment its count. */
116:
117: for (i = 0; i < tablei; i++) {
118: if (strcmp(parent, table[i].parent) == 0 &&
1.2 schwarze 119: (child == NULL || table[i].child == NULL ||
120: strcmp(child, table[i].child) == 0)) {
121: assert(init_done);
122: if (table[i].count != -1)
123: table[i].count++;
1.1 schwarze 124: return;
125: }
126: }
127:
128: /* If the table is full, make room. */
129:
130: if (tablei == tablesz) {
131: tablesz += 64;
1.37 schwarze 132: table = xreallocarray(table, tablesz, sizeof(*table));
1.1 schwarze 133: }
134:
135: /* Add a new entry to the table. */
136:
1.37 schwarze 137: table[tablei].parent = xstrdup(parent);
138: table[tablei].child = child == NULL ? NULL : xstrdup(child);
1.2 schwarze 139: table[tablei++].count = init_done ? 1 : -1;
1.1 schwarze 140: }
141:
142: /*
143: * Enter an element.
144: */
145: static void
146: stack_push(const char *name)
147: {
1.4 schwarze 148: if (nchild.parent != NULL && strcmp(name, nchild.parent) == 0)
149: nchild.count = 0;
150:
1.1 schwarze 151: if (stacki == stacksz) {
152: stacksz += 8;
1.37 schwarze 153: stack = xreallocarray(stack, stacksz, sizeof(*stack));
1.1 schwarze 154: }
1.37 schwarze 155: stack[stacki++] = xstrdup(name);
1.1 schwarze 156: }
157:
158: /*
159: * Exit an element.
160: */
161: static void
162: stack_pop(const char *name)
163: {
164: if (stacki > 0 && (name == NULL ||
165: strcmp(name, stack[stacki - 1]) == 0))
166: free(stack[--stacki]);
167: }
168:
169: /*
170: * Simplified version from parse.c.
171: */
172: static int
173: advance(char *b, size_t rlen, size_t *pend, const char *charset)
174: {
175: int space;
176:
177: if (*charset == ' ') {
178: space = 1;
179: charset++;
180: } else
181: space = 0;
182:
183: while (*pend < rlen) {
184: if (space && isspace((unsigned char)b[*pend]))
185: break;
186: if (strchr(charset, b[*pend]) != NULL)
187: break;
188: ++*pend;
189: }
190: if (*pend == rlen) {
191: b[rlen] = '\0';
192: return 1;
193: } else
194: return 0;
195: }
196:
197: /*
198: * Simplified version from parse.c.
199: */
200: static void
201: parse_file(int fd, char *fname)
202: {
203: char b[4096];
1.3 schwarze 204: char *cp;
1.1 schwarze 205: ssize_t rsz; /* Return value from read(2). */
206: size_t rlen; /* Number of bytes in b[]. */
207: size_t poff; /* Parse offset in b[]. */
208: size_t pend; /* Offset of the end of the current word. */
1.26 schwarze 209: int in_tag, in_arg, in_quotes, in_doctype, elem_end;
1.1 schwarze 210:
211: rlen = 0;
1.26 schwarze 212: in_tag = in_arg = in_quotes = in_doctype = 0;
1.1 schwarze 213: while ((rsz = read(fd, b + rlen, sizeof(b) - rlen - 1)) >= 0) {
214: if ((rlen += rsz) == 0)
215: break;
216: pend = 0;
217: for (;;) {
218: if ((poff = pend) == rlen)
219: break;
220: if (isspace((unsigned char)b[pend])) {
221: pend++;
222: continue;
223: }
224: if (in_arg) {
1.5 schwarze 225: if (in_quotes == 0 &&
226: (b[pend] == '\'' || b[pend] == '"')) {
227: in_quotes = b[pend] == '"' ? 2 : 1;
1.1 schwarze 228: pend++;
229: continue;
230: }
231: if (advance(b, rlen, &pend,
1.5 schwarze 232: in_quotes == 2 ? "\"" :
233: in_quotes == 1 ? "'" : " >") && rsz > 0)
1.1 schwarze 234: break;
235: in_arg = in_quotes = elem_end = 0;
236: if (b[pend] == '>') {
237: in_tag = 0;
238: if (pend > 0 && b[pend - 1] == '/') {
239: b[pend - 1] = '\0';
240: elem_end = 1;
241: }
242: }
243: b[pend] = '\0';
244: if (pend < rlen)
245: pend++;
246: if (elem_end)
247: stack_pop(NULL);
248: } else if (in_tag) {
1.26 schwarze 249: if (in_doctype && b[pend] == '[') {
250: in_tag = in_doctype = 0;
251: pend++;
252: continue;
253: }
1.1 schwarze 254: if (advance(b, rlen, &pend, " =>") && rsz > 0)
255: break;
256: elem_end = 0;
257: switch (b[pend]) {
258: case '>':
259: in_tag = 0;
260: if (pend > 0 && b[pend - 1] == '/') {
261: b[pend - 1] = '\0';
262: elem_end = 1;
263: }
264: break;
265: case '=':
266: in_arg = 1;
267: break;
268: default:
269: break;
270: }
271: b[pend] = '\0';
272: if (pend < rlen)
273: pend++;
274: if (elem_end)
275: stack_pop(NULL);
276: } else if (b[poff] == '<') {
277: if (advance(b, rlen, &pend, " >") && rsz > 0)
278: break;
1.3 schwarze 279: if (pend > poff + 3 &&
280: strncmp(b + poff, "<!--", 4) == 0) {
281: /* Skip a comment. */
282: cp = strstr(b + pend - 2, "-->");
283: if (cp == NULL) {
284: pend = rlen;
285: if (rsz > 0)
286: break;
287: } else
288: pend = cp + 3 - b;
289: continue;
290: }
1.1 schwarze 291: elem_end = 0;
292: if (b[pend] != '>')
293: in_tag = 1;
294: else if (pend > 0 && b[pend - 1] == '/') {
295: b[pend - 1] = '\0';
296: elem_end = 1;
297: }
298: b[pend] = '\0';
299: if (pend < rlen)
300: pend++;
301: if (b[++poff] == '/') {
302: elem_end = 1;
303: poff++;
1.26 schwarze 304: } else if (strcasecmp(b + poff,
305: "!DOCTYPE") == 0) {
306: in_doctype = 1;
1.1 schwarze 307: } else if (b[poff] != '!' && b[poff] != '?') {
308: table_add(stacki > 0 ?
1.2 schwarze 309: stack[stacki - 1] : "ROOT",
1.1 schwarze 310: b + poff);
311: stack_push(b + poff);
1.25 schwarze 312: if (strcmp(b + poff, "sbr") == 0)
313: elem_end = 1;
1.1 schwarze 314: }
315: if (elem_end)
316: stack_pop(b + poff);
317: } else {
318: advance(b, rlen, &pend, "<");
319: if (stacki > 0)
320: table_add(stack[stacki - 1], "TEXT");
321: }
322: }
323: assert(poff > 0);
324: rlen -= poff;
1.25 schwarze 325: memmove(b, b + poff, rlen);
1.1 schwarze 326: }
327: if (rsz < 0)
328: perror(fname);
329: }
330:
331: int
332: main(int argc, char *argv[])
333: {
334: size_t fsz, i;
335: ssize_t rsz;
1.2 schwarze 336: int ch, fd, show_all;
337:
338: show_all = 0;
339: while ((ch = getopt(argc, argv, "a")) != -1) {
340: switch (ch) {
341: case 'a':
342: show_all = 1;
343: break;
344: default:
345: return 1;
346: }
347: }
1.4 schwarze 348: argc -= optind;
349: argv += optind;
350:
351: if (argc > 1) {
352: nchild.parent = argv[0];
353: nchild.child = argv[1];
354: }
1.1 schwarze 355:
1.2 schwarze 356: /* Exclude relations that are already fully implemented. */
357: if (show_all == 0) {
1.33 schwarze 358: table_add("ROOT", "appendix");
1.27 schwarze 359: table_add("ROOT", "article");
360: table_add("ROOT", "book");
361: table_add("ROOT", "chapter");
1.33 schwarze 362: table_add("ROOT", "glossary");
363: table_add("ROOT", "part");
364: table_add("ROOT", "preface");
1.11 schwarze 365: table_add("ROOT", "refentry");
1.36 schwarze 366: table_add("ROOT", "reference");
1.33 schwarze 367: table_add("ROOT", "sect1");
368: table_add("ROOT", "sect2");
1.38 schwarze 369: table_add("abstract", NULL);
1.12 schwarze 370: table_add("acronym", "TEXT");
1.41 ! schwarze 371: table_add("affiliation", "jobtitle");
1.27 schwarze 372: table_add("affiliation", "orgdiv");
373: table_add("affiliation", "orgname");
1.18 schwarze 374: table_add("appendix", NULL);
1.24 schwarze 375: table_add("application", "TEXT");
376: table_add("arg", "option");
1.18 schwarze 377: table_add("article", NULL);
1.38 schwarze 378: table_add("articleinfo", "abstract");
1.27 schwarze 379: table_add("articleinfo", "author");
380: table_add("articleinfo", "authorgroup");
381: table_add("articleinfo", "copyright");
1.24 schwarze 382: table_add("articleinfo", "date");
1.27 schwarze 383: table_add("articleinfo", "legalnotice");
1.21 schwarze 384: table_add("articleinfo", "pubdate");
1.27 schwarze 385: table_add("articleinfo", "releaseinfo");
386: table_add("articleinfo", "subtitle");
1.21 schwarze 387: table_add("articleinfo", "title");
1.27 schwarze 388: table_add("author", "affiliation");
1.20 schwarze 389: table_add("author", "contrib");
390: table_add("author", "email");
391: table_add("author", "firstname");
392: table_add("author", "othername");
393: table_add("author", "surname");
1.27 schwarze 394: table_add("author", "TEXT");
1.23 schwarze 395: table_add("authorgroup", "author");
1.27 schwarze 396: table_add("authorgroup", "editor");
1.23 schwarze 397: table_add("authorgroup", "othercredit");
1.16 schwarze 398: table_add("blockquote", NULL);
1.18 schwarze 399: table_add("book", NULL);
1.38 schwarze 400: table_add("bookinfo", "abstract");
1.23 schwarze 401: table_add("bookinfo", "authorgroup");
1.27 schwarze 402: table_add("bookinfo", "copyright");
1.23 schwarze 403: table_add("bookinfo", "legalnotice");
1.21 schwarze 404: table_add("bookinfo", "pubdate");
1.27 schwarze 405: table_add("bookinfo", "releaseinfo");
406: table_add("bookinfo", "subtitle");
1.21 schwarze 407: table_add("bookinfo", "title");
1.32 schwarze 408: table_add("caption", "TEXT");
1.9 schwarze 409: table_add("chapter", NULL);
1.23 schwarze 410: table_add("citerefentry", "manvolnum");
411: table_add("citerefentry", "refentrytitle");
1.24 schwarze 412: table_add("citetitle", "TEXT");
413: table_add("cmdsynopsis", "arg");
414: table_add("cmdsynopsis", "command");
415: table_add("cmdsynopsis", "group");
1.33 schwarze 416: table_add("cmdsynopsis", "sbr");
1.12 schwarze 417: table_add("code", "TEXT");
1.24 schwarze 418: table_add("command", "TEXT");
1.19 schwarze 419: table_add("computeroutput", "TEXT");
1.10 schwarze 420: table_add("constant", "TEXT");
1.27 schwarze 421: table_add("contrib", "TEXT");
422: table_add("copyright", "holder");
423: table_add("copyright", "year");
1.21 schwarze 424: table_add("date", "TEXT");
1.27 schwarze 425: table_add("editor", "affiliation");
426: table_add("editor", "firstname");
427: table_add("editor", "surname");
1.24 schwarze 428: table_add("email", "TEXT");
1.29 schwarze 429: table_add("emphasis", "errorname");
430: table_add("emphasis", "function");
1.8 schwarze 431: table_add("emphasis", "TEXT");
1.6 schwarze 432: table_add("entry", NULL);
1.12 schwarze 433: table_add("errorname", "TEXT");
1.32 schwarze 434: table_add("figure", "mediaobject");
1.33 schwarze 435: table_add("figure", "title");
1.12 schwarze 436: table_add("filename", "TEXT");
1.24 schwarze 437: table_add("firstname", "TEXT");
438: table_add("firstterm", "TEXT");
1.31 schwarze 439: table_add("footnote", "para");
1.8 schwarze 440: table_add("funcdef", "function");
441: table_add("funcdef", "TEXT");
1.40 schwarze 442: table_add("funcparams", "TEXT");
1.8 schwarze 443: table_add("funcprototype", "funcdef");
444: table_add("funcprototype", "paramdef");
1.40 schwarze 445: table_add("funcprototype", "void");
1.12 schwarze 446: table_add("funcsynopsis", "funcprototype");
447: table_add("funcsynopsis", "funcsynopsisinfo");
448: table_add("funcsynopsisinfo", "TEXT");
1.29 schwarze 449: table_add("function", "replaceable");
1.8 schwarze 450: table_add("function", "TEXT");
1.17 schwarze 451: table_add("glossary", "glossdiv");
452: table_add("glossary", "glossentry");
453: table_add("glossdef", "para");
454: table_add("glossdiv", "glossentry");
455: table_add("glossentry", "glossdef");
456: table_add("glossentry", "glossterm");
457: table_add("glossentry", "indexterm");
458: table_add("glosslist", "glossentry");
1.33 schwarze 459: table_add("glossterm", "emphasis");
1.17 schwarze 460: table_add("glossterm", "TEXT");
1.24 schwarze 461: table_add("group", "arg");
1.27 schwarze 462: table_add("holder", "TEXT");
1.32 schwarze 463: table_add("imageobject", "imagedata");
1.9 schwarze 464: table_add("indexterm", "primary");
465: table_add("indexterm", "secondary");
1.6 schwarze 466: table_add("informaltable", "tgroup");
1.7 schwarze 467: table_add("itemizedlist", "listitem");
1.41 ! schwarze 468: table_add("jobtitle", "TEXT");
1.24 schwarze 469: table_add("keycap", "TEXT");
470: table_add("keycode", "TEXT");
1.39 schwarze 471: table_add("keycombo", "keycap");
1.24 schwarze 472: table_add("keysym", "TEXT");
1.18 schwarze 473: table_add("legalnotice", NULL);
1.15 schwarze 474: table_add("link", NULL);
1.7 schwarze 475: table_add("listitem", NULL);
1.12 schwarze 476: table_add("literal", "TEXT");
1.10 schwarze 477: table_add("literallayout", NULL);
1.23 schwarze 478: table_add("manvolnum", "TEXT");
1.19 schwarze 479: table_add("markup", "TEXT");
1.32 schwarze 480: table_add("mediaobject", "caption");
481: table_add("mediaobject", "imageobject");
1.30 schwarze 482: table_add("member", "constant");
483: table_add("member", "emphasis");
484: table_add("member", "function");
485: table_add("member", "property");
486: table_add("member", "symbol");
1.13 schwarze 487: table_add("member", "TEXT");
1.18 schwarze 488: table_add("note", NULL);
1.34 schwarze 489: table_add("olink", "citetitle");
490: table_add("olink", "function");
491: table_add("olink", "TEXT");
1.29 schwarze 492: table_add("option", "parameter");
493: table_add("option", "replaceable");
1.24 schwarze 494: table_add("option", "TEXT");
1.7 schwarze 495: table_add("orderedlist", "listitem");
1.27 schwarze 496: table_add("orgdiv", "TEXT");
497: table_add("orgname", "TEXT");
498: table_add("othercredit", "affiliation");
1.20 schwarze 499: table_add("othercredit", "contrib");
500: table_add("othercredit", "email");
501: table_add("othercredit", "firstname");
502: table_add("othercredit", "othername");
503: table_add("othercredit", "surname");
1.24 schwarze 504: table_add("othername", "TEXT");
1.2 schwarze 505: table_add("para", NULL);
1.40 schwarze 506: table_add("paramdef", "funcparams");
1.9 schwarze 507: table_add("paramdef", "parameter");
508: table_add("paramdef", "TEXT");
509: table_add("parameter", "TEXT");
1.27 schwarze 510: table_add("part", NULL);
1.24 schwarze 511: table_add("personname", "firstname");
512: table_add("personname", "surname");
1.27 schwarze 513: table_add("phrase", "TEXT");
514: table_add("preface", NULL);
1.9 schwarze 515: table_add("primary", NULL);
1.35 schwarze 516: table_add("productname", "TEXT");
1.10 schwarze 517: table_add("programlisting", NULL);
1.24 schwarze 518: table_add("property", "TEXT");
1.21 schwarze 519: table_add("pubdate", "TEXT");
1.29 schwarze 520: table_add("quote", "command");
1.33 schwarze 521: table_add("quote", "filename");
1.28 schwarze 522: table_add("quote", "literal");
1.24 schwarze 523: table_add("quote", "TEXT");
1.23 schwarze 524: table_add("refentry", "refentryinfo");
1.11 schwarze 525: table_add("refentry", "refmeta");
526: table_add("refentry", "refnamediv");
527: table_add("refentry", "refsect1");
528: table_add("refentry", "refsynopsisdiv");
1.27 schwarze 529: table_add("refentryinfo", "author");
1.33 schwarze 530: table_add("refentryinfo", "authorgroup");
1.27 schwarze 531: table_add("refentryinfo", "copyright");
1.24 schwarze 532: table_add("refentryinfo", "date");
1.35 schwarze 533: table_add("refentryinfo", "productname");
1.23 schwarze 534: table_add("refentrytitle", "TEXT");
1.36 schwarze 535: table_add("reference", "refentry");
1.11 schwarze 536: table_add("refmeta", "manvolnum");
537: table_add("refmeta", "refentrytitle");
1.23 schwarze 538: table_add("refmeta", "refmiscinfo");
539: table_add("refmiscinfo", "TEXT");
1.11 schwarze 540: table_add("refname", "TEXT");
541: table_add("refnamediv", "refname");
542: table_add("refnamediv", "refpurpose");
543: table_add("refpurpose", "TEXT");
1.9 schwarze 544: table_add("refsect1", NULL);
545: table_add("refsect2", NULL);
1.24 schwarze 546: table_add("refsynopsisdiv", "cmdsynopsis");
1.11 schwarze 547: table_add("refsynopsisdiv", "funcsynopsis");
1.27 schwarze 548: table_add("releaseinfo", "TEXT");
1.24 schwarze 549: table_add("replaceable", "TEXT");
550: table_add("returnvalue", "TEXT");
1.6 schwarze 551: table_add("row", "entry");
1.10 schwarze 552: table_add("screen", NULL);
1.9 schwarze 553: table_add("secondary", NULL);
554: table_add("section", NULL);
555: table_add("sect1", NULL);
556: table_add("sect2", NULL);
557: table_add("sect3", NULL);
558: table_add("sect4", NULL);
1.12 schwarze 559: table_add("sgmltag", "TEXT");
1.14 schwarze 560: table_add("simpara", NULL);
1.13 schwarze 561: table_add("simplelist", "member");
1.27 schwarze 562: table_add("simplesect", NULL);
1.12 schwarze 563: table_add("structfield", "TEXT");
564: table_add("structname", "TEXT");
1.30 schwarze 565: table_add("subscript", "TEXT");
1.27 schwarze 566: table_add("subtitle", "TEXT");
1.30 schwarze 567: table_add("superscript", "emphasis");
568: table_add("superscript", "TEXT");
1.24 schwarze 569: table_add("surname", "TEXT");
1.10 schwarze 570: table_add("symbol", "TEXT");
1.33 schwarze 571: table_add("synopsis", "function");
572: table_add("synopsis", "parameter");
573: table_add("synopsis", "type");
1.24 schwarze 574: table_add("synopsis", "TEXT");
1.22 schwarze 575: table_add("systemitem", "TEXT");
1.6 schwarze 576: table_add("table", "tgroup");
577: table_add("table", "title");
578: table_add("tbody", "row");
1.7 schwarze 579: table_add("term", NULL);
1.6 schwarze 580: table_add("tgroup", "colspec");
581: table_add("tgroup", "tbody");
582: table_add("tgroup", "thead");
583: table_add("thead", "row");
1.29 schwarze 584: table_add("title", "acronym");
585: table_add("title", "emphasis");
586: table_add("title", "errorname");
587: table_add("title", "function");
588: table_add("title", "literal");
589: table_add("title", "quote");
590: table_add("title", "trademark");
591: table_add("title", "type");
1.6 schwarze 592: table_add("title", "TEXT");
1.27 schwarze 593: table_add("trademark", "TEXT");
1.12 schwarze 594: table_add("type", "TEXT");
1.15 schwarze 595: table_add("ulink", NULL);
1.12 schwarze 596: table_add("userinput", "TEXT");
1.7 schwarze 597: table_add("variablelist", "varlistentry");
598: table_add("varlistentry", "listitem");
599: table_add("varlistentry", "term");
1.24 schwarze 600: table_add("varname", "TEXT");
1.27 schwarze 601: table_add("warning", NULL);
602: table_add("year", "TEXT");
1.2 schwarze 603: }
604: table_add(NULL, NULL);
605:
606: /* Loop over input files. */
1.1 schwarze 607: fd = -1;
608: fname = NULL;
609: while ((rsz = getline(&fname, &fsz, stdin)) != -1) {
610: if (fname[rsz - 1] == '\n')
611: fname[--rsz] = '\0';
612: if ((fd = open(fname, O_RDONLY, 0)) == -1)
613: err(1, "%s", fname);
614: parse_file(fd, fname);
615: close(fd);
616: }
617:
618: /* Cleanup and error handling. */
619: free(fname);
620: if (ferror(stdin))
621: err(1, "standard input");
622: if (fd == -1)
623: errx(1, "No input file names found on standard input");
624:
625: /* Dump results. */
626: for (i = 0; i < tablei; i++)
1.2 schwarze 627: if (table[i].count != -1)
628: printf("%d\t%s\t%s\n", table[i].count,
629: table[i].parent, table[i].child);
1.4 schwarze 630:
631: /* Optional parent-child histogram. */
632: if (nchild.parent != NULL) {
633: printf("%s %s", nchild.parent, nchild.child);
634: for (i = 0; i < nchildsz; i++)
635: printf(" %d", nchild.freq[i]);
636: putchar('\n');
637: }
1.1 schwarze 638: return 0;
639: }
CVSweb