source: abnfparser/bap/main.c

Last change on this file was 2749, checked in by julian.reschke@…, 4 years ago

bap: experimental support for RFC 7405

  • Property svn:eol-style set to native
File size: 20.3 KB
Line 
1/*
2 * Bill's ABNF Parser
3 * Copyright 2002-2006 William C. Fenner <fenner@research.att.com>
4 *  All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the author nor the names of contributors
15 *    may be used to endorse or promote products derived from this software
16 *    without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY WILLIAM C. FENNER ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
20 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WILLIAM C. FENNER OR HIS
22 * BROTHER B1FF BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
26 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
28 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
29 * DAMAGE.
30 */
31
32#include "config.h"
33#include <stdio.h>
34#include <stdlib.h>
35#include <search.h>
36#include <unistd.h>
37#include <ctype.h>
38#include <string.h>
39#include "common.h"
40
41static const char rcsid[] =
42  "$Id: main.c,v 1.3 2008-05-30 12:33:45 jre Exp $";
43static const char versionstring[] = PACKAGE_VERSION;
44
45static void printobjasxml(object *, int);
46static void printobj_r(object *, int, int);
47static void printobjasxml_r(object *, int, int);
48static void canonify(struct rule *);
49static void canonify_r(struct object **);
50static void parse_from(char *filename);
51static void predefine(fn_list *ifile);
52static int summary(void);
53
54#define MAXRULE         1000    /* XXX */
55
56#define local_printf(format, args...)                           \
57  if (!olenlimit) {                                             \
58    printf( format, ## args );                                  \
59  } else {                                                      \
60    int prevcount = charcount;  \
61    charcount += sprintf((charbuf+charcount), format, ## args); \
62    if (charcount > olenlimit) {                                \
63      char x[1000];  \
64      sprintf(x, format, ## args ); \
65      if (*x == '<') { /* prose rule? */  \
66        charcut = charbuf + prevcount - 1; /* wrap all of it */ \
67        charcount = olenlimit + strlen(x) + 1;  \
68      } \
69      else { \
70        charcut = charbuf+olenlimit;                            \
71        while (*charcut != ' ' && charcut >= charbuf) {         \
72                charcut--;                                              \
73                charcount++;                                            \
74        }                                                               \
75      } \
76      if (charcut != charbuf) {                                 \
77        *charcut++ = 0;                                         \
78        printf("%s\n", charbuf);                                \
79        if (*charbuf == ';') {                                  \
80          memmove(charbuf+2, charcut, charcount - olenlimit);   \
81          *(charbuf+1) = ' ';                                   \
82          charcount -= (olenlimit-1);                           \
83        } else {                                                \
84          memmove(charbuf+1, charcut, charcount - olenlimit);   \
85          *charbuf = ' ';                                       \
86          charcount -= olenlimit;                               \
87        }                                                       \
88      }                                                         \
89    }                                                           \
90    /* flush the line when EOL present */ \
91    charcut = strchr(charbuf, '\n');                            \
92    if (charcut) {                                              \
93      printf("%s", charbuf);                                    \
94      charcount = 0;                                            \
95    }                                                           \
96  }
97   
98
99char *charbuf = NULL;
100char *charcut = NULL;
101int charcount = 0;
102
103struct rule *rules = NULL;
104char *input_file; /* of current input file */
105
106char *top_rule_name = "ABNF";
107
108int cflag = 0;          /* include line number comments */
109int c2flag = 0;         /* include comments for printable constants */
110int tflag = 0;          /* print type info */
111int permissive = 1;     /* Be permissive (e.g. accept '|') */
112int rfc7405 = 0;        /* Support RFC 7405 (%s/%i) */
113int qflag = 0;          /* quiet */
114int canon = 1;          /* canonify */
115int asxml = 0;    /* output XML */
116int olenlimit = 0;   /* 0 for unlimited, might be any other value */
117
118int yyparse(void);
119
120void
121usage(void)
122{
123  fprintf(stderr, "Bill's ABNF Parser version %s\n", versionstring);
124  fprintf(stderr, " (with extensions from <https://svn.tools.ietf.org/svn/wg/httpbis/abnfparser/bap/>)\n", versionstring);
125  fprintf(stderr, "usage: bap [-cknqtx][-i rules][-l num][-S name][-X ext][file]\n");
126  fprintf(stderr, " parse ABNF grammar from file or stdin\n");
127  fprintf(stderr, " Input options:\n");
128  fprintf(stderr, "  -c       include rule definition line # in comment\n");
129  fprintf(stderr, "  -i file  read predefined rules from \"file\"\n");
130  fprintf(stderr, "  -S name  name rule as production start\n");
131  fprintf(stderr, "  -X ext   comma-separated list of allowed extensions\n");
132  fprintf(stderr, "           (only value currently supported is rfc7405)\n");
133  fprintf(stderr, " Output options:\n");
134  fprintf(stderr, "  -k       add comments for printable characters specified as %%x\n");
135  fprintf(stderr, "  -l num   limit the length of each line to \"num\" characters\n");
136  fprintf(stderr, "  -n       don't \"canonify\" result\n");
137  fprintf(stderr, "  -q       don't print parsed grammar\n");
138  fprintf(stderr, "  -t       include type info in result\n");
139  fprintf(stderr, "  -x       output XML\n");
140  exit(1);
141}
142
143int
144main(int argc, char **argv)
145{
146  int ch;
147  int rc = 0;
148  struct rule *r;
149  fn_list *pre_input = NULL;
150 
151#ifdef YYDEBUG
152  extern int yydebug;
153
154  yydebug = 0;
155#endif
156  hcreate(MAXRULE);
157
158  while ((ch = getopt(argc, argv, "cdi:kntqS:xl:X:")) != -1) {
159    switch (ch) {
160    case 'c':
161      cflag++;
162      break;
163
164    case 'd':
165#ifdef YYDEBUG
166      yydebug = 1;
167#else
168      fprintf(stderr, "Rebuild with -DYYDEBUG to use -d.\n");
169#endif
170      break;
171
172    case 'k':
173      c2flag++;
174      break;
175
176    case 'n':
177      canon = 0;
178      break;
179
180    case 'i': {
181      fn_list *ifile = calloc(sizeof(fn_list), 1);
182      ifile->filename = optarg;
183      ifile->next = pre_input;
184      pre_input = ifile;
185      break;
186    }
187     
188    case 't':
189      tflag++;
190      break;
191
192    case 'p':
193      permissive = 0;
194      break;
195
196    case 'q':
197      qflag++;
198      break;
199
200    case 'S': 
201      top_rule_name = optarg;
202      break;
203     
204    case 'X': {
205        char *x = strtok(optarg, ",");
206        while (x != NULL) {
207          if (0 == strcmp(x, "rfc7405")) {
208            rfc7405 = 1;
209          }
210          else {
211            fprintf(stderr, "unknown extension: %s\n", x);
212            exit(2);
213          }
214          x = strtok(NULL, ",");
215        }
216      }
217      break;
218
219    case 'x':
220      asxml = 1;
221      break;
222
223    case 'l':
224      olenlimit = atoi(optarg);
225      break;
226
227    default:
228      usage();
229    }
230  }
231  argc -= optind;
232  argv += optind;
233
234  if (argc > 1)
235    usage();
236
237  if (olenlimit) {
238    charbuf = (char *) calloc (8192, sizeof(char));
239  }
240  predefine(pre_input);   
241 
242  /* Parse the grammar, perhaps spouting errors. */
243  parse_from((argc > 0)? argv[0] : NULL);
244
245  /* If we're not quiet, then output the grammar again. */
246  if (!qflag) {
247    if (canon)
248      canonify(rules);
249    if (!asxml) {
250      for (r = rules; r; r = r->next) {
251        if (r->predefined) {
252          /* do not output */
253        }
254        else if (r->rule) {
255          local_printf("%s = ", r->name);
256          printobj(r->rule, tflag);
257          if (cflag)
258            local_printf(" ; line %d", r->line);
259          local_printf("\n");
260        } else {
261          local_printf("; %s UNDEFINED\n", r->name);
262        }
263        if (r->next == rules)
264          break;
265      }
266      for (r = rules; r; r = r->next) {
267        if (r->used == 0 
268            && r->predefined == 0 
269            && r->rule
270            && strcmp(r->name, top_rule_name))
271          local_printf("; %s defined but not used\n", r->name);
272        if (r->next == rules)
273          break;
274      }
275    }
276    else {
277      local_printf("<abnf xmlns='tag:greenbytes.de,2008:abnf'>\n");
278      for (r = rules; r; r = r->next) {
279        if (r->predefined) {
280          /* do not output */
281        }
282        else if (r->rule) {
283          local_printf("  <rule name='%s'", r->name);
284          if (cflag)
285            local_printf(" line='%d'", r->line);
286          local_printf(">");
287          printobjasxml(r->rule, 2);
288          local_printf("\n  </rule>\n");
289        } else {
290          local_printf("  <undefined name='%s'/>\n", r->name);
291        }
292        if (r->next == rules)
293          break;
294      }
295      local_printf("</abnf>\n");
296    }
297  }
298 
299  rc = summary();
300  hdestroy();
301  exit(rc);
302}
303
304void
305canonify(struct rule *rules)
306{
307  struct rule *r;
308
309  for (r = rules; r; r = r->next) {
310    if (r->rule)
311      canonify_r(&r->rule);
312    if (r->next == rules)
313      break;
314  }
315}
316
317/* XXX may need to modify in the future? */
318void
319canonify_r(struct object **op)
320{
321  struct object *o = *op;
322  while (o) {
323    switch (o->type) {
324    case T_ALTERNATION:
325      canonify_r(&o->u.alternation.left);
326      canonify_r(&o->u.alternation.right);
327      break;
328    case T_RULE:
329      /* nothing to do */
330      break;
331    case T_GROUP:
332      canonify_r(&o->u.e.e.group);
333      break;
334    case T_TERMSTR:
335      while (o->next && o->next->type == T_TERMSTR &&
336             o->u.e.repetition.lo == 1 && o->u.e.repetition.hi == 1 &&
337             o->next->u.e.repetition.lo == 1 && o->next->u.e.repetition.hi == 1 &&
338             ((o->u.e.e.termstr.flags & F_CASESENSITIVE) ==
339              (o->next->u.e.e.termstr.flags & F_CASESENSITIVE))) {
340        int len = strlen(o->u.e.e.termstr.str) + strlen(o->next->u.e.e.termstr.str);
341        char *p = malloc(len + 1);
342        strcpy(p, o->u.e.e.termstr.str);
343        strcat(p, o->next->u.e.e.termstr.str);
344        free(o->u.e.e.termstr.str);
345        o->u.e.e.termstr.str = p;
346        /* XXX leak o->next */
347        o->next = o->next->next;
348      }
349      if (o->u.e.e.termstr.flags & F_CASESENSITIVE) {
350        int anybad = 0;
351        char *p;
352        for (p = o->u.e.e.termstr.str; *p; p++) {
353          if (isalpha(*p) || *p == '"' || !isprint(*p)) {
354            anybad = 1;
355            break;
356          }
357        }
358        if (anybad == 0)
359          o->u.e.e.termstr.flags &= ~F_CASESENSITIVE;
360      }
361    case T_TERMRANGE:
362    case T_PROSE:
363    default:
364      /* nothing to do */
365      break;
366    }
367    o = o->next;
368  }
369}
370
371void
372printrep(struct range *rep)
373{
374  if (rep->lo == 1 && rep->hi == 1)
375    return;
376  if (rep->lo > 0)
377    local_printf("%d", rep->lo);
378  if (rep->lo == rep->hi) {
379    if (rep->lo == 0)
380      local_printf("0");
381    return;
382  }
383  local_printf("*");
384  if (rep->hi != -1)
385    local_printf("%d", rep->hi);
386}
387
388void
389printobj(object *o, int tflag)
390{
391  /* T_GROUP means don't put grouping characters
392   * around the top level. */
393  printobj_r(o, T_GROUP, tflag);
394}
395
396void
397printobjasxml(object *o, int indent)
398{
399  /* T_GROUP means don't put grouping characters
400   * around the top level. */
401  printobjasxml_r(o, T_GROUP, indent);
402}
403
404/*
405 * No paren needed around a group that's:
406 * - not concatenation (no next)
407 * - not an ALTERNATION
408 * - got a repeat count of 1
409 */
410#define NOPAREN(o)      ((o->next == NULL) && (o->type != T_ALTERNATION) && (o->u.e.repetition.lo == 1 && o->u.e.repetition.hi == 1))
411
412/*
413 * No brackets needed around a group that
414 * contains a single element that has a
415 * possible repetition of 0.
416 */
417#define NOBRACKET(o)    ((o->next == NULL) && (o->u.e.repetition.lo == 0))
418
419static void
420printobj_r(object *o, int parenttype, int tflag)
421{
422  int iterating = 0;
423
424  /* Put parenthesis around concatenations */
425  if (parenttype != T_GROUP && o->next) {
426    iterating = 1;
427    local_printf("( ");
428  }
429  while (o) {
430    switch (o->type) {
431    case T_ALTERNATION:
432      if (tflag)
433        local_printf("{ALTERNATION}");
434      if (o->next)
435        local_printf("( ");
436      printobj_r(o->u.alternation.left, o->type, tflag);
437      local_printf(" / ");
438      printobj_r(o->u.alternation.right, o->type, tflag);
439      if (o->next)
440        local_printf(" )");
441      break;
442    case T_RULE: /* identation to delimit the code change */
443      if (tflag)
444        local_printf("{RULE}");
445      if (o->u.e.islist) {
446        if (o->u.e.repetition.lo == 0) {
447          local_printf("[ ( \",\" / ");
448          if (o->u.e.e.rule.rule) {
449            local_printf("%s", o->u.e.e.rule.rule->name);
450            o->u.e.e.rule.rule->used = 1;
451          } else {
452            local_printf("%s", o->u.e.e.rule.name);
453          }
454          local_printf(" ) *( OWS \",\" [ OWS ");
455          local_printf("%s", (o->u.e.e.rule.rule) ? 
456                 o->u.e.e.rule.rule->name : 
457                 o->u.e.e.rule.name);
458          local_printf(" ] ) ]");
459        } else if (o->u.e.repetition.lo == 1) {
460          local_printf(" *( \",\" OWS ) ");
461          if (o->u.e.e.rule.rule) {
462            local_printf("%s", o->u.e.e.rule.rule->name);
463            o->u.e.e.rule.rule->used = 1;
464          } else {
465            local_printf("%s", o->u.e.e.rule.name);
466          }
467          local_printf(" *( OWS \",\" [ OWS ");
468          local_printf("%s", (o->u.e.e.rule.rule) ? 
469                 o->u.e.e.rule.rule->name : 
470                 o->u.e.e.rule.name);
471          local_printf(" ] )");
472        }
473        else {
474          local_printf("TODO: something is wrong");
475        } 
476      } else {
477        printrep(&o->u.e.repetition);
478        if (o->u.e.e.rule.rule) {
479          local_printf("%s", o->u.e.e.rule.rule->name);
480          o->u.e.e.rule.rule->used = 1;
481        }
482        else {
483          local_printf("%s", o->u.e.e.rule.name);
484        }
485      }
486      break;
487    case T_GROUP:
488      if (tflag)
489        local_printf("{GROUP}");
490      if (o->u.e.islist) {
491        if (o->u.e.repetition.lo == 0) {
492          local_printf("[ ( \",\" / ( ");
493          printobj_r(o->u.e.e.group, o->type, tflag);
494          local_printf(" ) ) *( OWS \",\" [ OWS ( ");
495          printobj_r(o->u.e.e.group, o->type, tflag);
496          local_printf(" ) ] ) ]");
497        }
498        else if (o->u.e.repetition.lo == 1) {
499          local_printf("*( \",\" OWS ) ( ");
500          printobj_r(o->u.e.e.group, o->type, tflag);
501          local_printf(" ) *( OWS \",\" [ OWS ( ");
502          printobj_r(o->u.e.e.group, o->type, tflag);
503          local_printf(" ) ] )");
504        }
505        else {
506          local_printf("TODO: something is wrong");
507        } 
508      } else {
509        if (o->u.e.repetition.lo == 0 &&
510            o->u.e.repetition.hi == 1) {
511          if (!NOBRACKET(o->u.e.e.group))
512            local_printf("[ ");
513        } else {
514          printrep(&o->u.e.repetition);
515          if (!NOPAREN(o->u.e.e.group))
516            local_printf("( ");
517        }
518        printobj_r(o->u.e.e.group, o->type, tflag);
519        if (o->u.e.repetition.lo == 0 &&
520            o->u.e.repetition.hi == 1) {
521          if (!NOBRACKET(o->u.e.e.group))
522            local_printf(" ]");
523        } else {
524          if (!NOPAREN(o->u.e.e.group))
525            local_printf(" )");
526        }
527      }
528      break;
529    case T_TERMSTR:
530      if (tflag)
531        local_printf("{TERMSTR}");
532      printrep(&o->u.e.repetition);
533      if (o->u.e.e.termstr.flags & F_CASESENSITIVE) {
534        unsigned char *p = (unsigned char*)o->u.e.e.termstr.str;
535        char sep;
536        int allprintable = 1;
537        local_printf("%%");
538        sep = 'x';
539        while (*p) {
540          if (!isgraph(*p)) allprintable = 0;
541          local_printf("%c%02X", sep, *p++);
542          sep = '.';
543        }
544        if (c2flag && allprintable)
545          local_printf(" ; %s\n", o->u.e.e.termstr.str);
546      } else {
547        local_printf("%c%s%c", '"', o->u.e.e.termstr.str, '"');
548      }
549      break;
550    case T_TERMRANGE:
551      if (tflag)
552        local_printf("{TERMRANGE}");
553      printrep(&o->u.e.repetition);
554      local_printf("%%x%02X-%02X",
555             o->u.e.e.termrange.lo,
556             o->u.e.e.termrange.hi);
557      /* XXX isprint does not handle non-ASCII */
558      if (c2flag &&
559          isprint(o->u.e.e.termrange.lo) &&
560          isprint(o->u.e.e.termrange.hi)) {
561        local_printf(" ; '%c'-'%c'\n",
562               o->u.e.e.termrange.lo,
563               o->u.e.e.termrange.hi);
564      }
565      break;
566    case T_PROSE:
567      if (tflag)
568        local_printf("{PROSE}");
569      printrep(&o->u.e.repetition);
570      local_printf("<%s>", o->u.e.e.proseval);
571      break;
572    default:
573      local_printf("{UNKNOWN OBJECT TYPE %d}", o->type);
574      break;
575    }
576    if (o->next)
577      local_printf(" ");
578    o = o->next;
579  }
580  if (iterating)
581    local_printf(" )");
582}
583
584static void
585escaped(char *c) {
586  while (*c) {
587    if (*c == '&') {
588      local_printf("&amp;");
589    }
590    else if (*c == '<') {
591      local_printf("&lt;");
592    }
593    else {
594      local_printf("%c", *c);
595    }
596    c += 1;
597  }
598}
599
600static void
601printobjasxml_r(object *o, int parenttype, int indent)
602{
603  while (o) {
604    switch (o->type) {
605    case T_ALTERNATION:
606      local_printf("<alternation>\n");
607      local_printf("<alternative>");
608      printobjasxml_r(o->u.alternation.left, o->type, indent + 2);
609      local_printf("</alternative>\n");
610      local_printf("<alternative>");
611      printobjasxml_r(o->u.alternation.right, o->type, indent + 2);
612      local_printf("</alternative>\n");
613      local_printf("</alternation>\n");
614      break;
615    case T_RULE:
616      if (o->u.e.islist) {
617        local_printf("<list min='%d' max='%d'>\n", o->u.e.repetition.lo, o->u.e.repetition.hi);
618        if (o->u.e.e.rule.rule) {
619          local_printf("<rule ref='%s'/>", o->u.e.e.rule.rule->name);
620          o->u.e.e.rule.rule->used = 1;
621        }
622        else {
623          local_printf("<rule ref='%s'/>", o->u.e.e.rule.name);
624        }
625        local_printf("</list>\n");
626      }
627      else {
628        if (o->u.e.e.rule.rule) {
629          local_printf("<rule min='%d' max='%d' ref='%s'/>", o->u.e.repetition.lo, o->u.e.repetition.hi, o->u.e.e.rule.rule->name);
630          o->u.e.e.rule.rule->used = 1;
631        }
632        else {
633          local_printf("<rule min='%d' max='%d' ref='%s'/>", o->u.e.repetition.lo, o->u.e.repetition.hi, o->u.e.e.rule.name);
634        }
635      }
636      break;
637    case T_GROUP:
638      if (o->u.e.islist) {
639        local_printf("<list min='%d' max='%d'>\n", o->u.e.repetition.lo, o->u.e.repetition.hi);
640        printobjasxml_r(o->u.e.e.group, o->type, indent + 2);
641        local_printf("</list>");
642      }
643      else {
644        local_printf("<group min='%d' max='%d'>\n", o->u.e.repetition.lo, o->u.e.repetition.hi);
645        printobjasxml_r(o->u.e.e.group, o->type, indent + 2);
646        local_printf("</group>");
647      }
648      break;
649    case T_TERMSTR:
650      local_printf("<term min='%d' max='%d'>", o->u.e.repetition.lo, o->u.e.repetition.hi);
651      if (o->u.e.e.termstr.flags & F_CASESENSITIVE) {
652        unsigned char *p = (unsigned char*)o->u.e.e.termstr.str;
653        char sep;
654        int allprintable = 1;
655        local_printf("%%");
656        sep = 'x';
657        while (*p) {
658          if (!isgraph(*p)) allprintable = 0;
659          local_printf("%c%02X", sep, *p++);
660          sep = '.';
661        }
662      } else {
663        local_printf("\"");
664        escaped(o->u.e.e.termstr.str);
665        local_printf("\"");
666      }
667      local_printf("</term>");
668      break;
669    case T_TERMRANGE:
670      local_printf("<termrange min='%d' max='%d'>", o->u.e.repetition.lo, o->u.e.repetition.hi);
671      local_printf("%%x%02X-%02X",
672             o->u.e.e.termrange.lo,
673             o->u.e.e.termrange.hi);
674      /* XXX isprint does not handle non-ASCII */
675      if (c2flag &&
676          isprint(o->u.e.e.termrange.lo) &&
677          isprint(o->u.e.e.termrange.hi)) {
678        local_printf(" ; '%c'-'%c'\n",
679               o->u.e.e.termrange.lo,
680               o->u.e.e.termrange.hi);
681      }
682      local_printf("</termrange>");
683      break;
684    case T_PROSE:
685      local_printf("<prose min='%d' max='%d'>", o->u.e.repetition.lo, o->u.e.repetition.hi);
686      escaped(o->u.e.e.proseval);
687      local_printf("</prose>");
688      break;
689    default:
690      local_printf("{UNKNOWN OBJECT TYPE %d}", o->type);
691      break;
692    }
693    if (o->next)
694      local_printf(" ");
695    o = o->next;
696  }
697}
698
699struct rule *
700findrule(char *name)
701{
702  char *lowername;
703  char *p, *q;
704  ENTRY *e;
705  ENTRY search;
706  struct rule *r;
707
708  lowername = malloc(strlen(name) + 1);
709  for (p = name, q = lowername; *p; p++, q++)
710    if (isupper(*p))
711      *q = tolower(*p);
712    else
713      *q = *p;
714  *q = '\0';
715  search.key = lowername;
716  search.data = NULL;
717  e = hsearch(search, FIND);
718  if (e == NULL) {
719    r = calloc(1, sizeof(struct rule));
720    r->name = name;
721    r->lowername = lowername;
722    search.data = r;
723    e = hsearch(search, ENTER);
724    if (e == NULL) {
725      fprintf(stderr, "hash table full -- increase MAXRULE\n");
726      exit(1);
727    }
728    if (rules) {
729      r->next = rules;
730      r->prev = rules->prev;
731      rules->prev->next = r;
732      rules->prev = r;
733    } else {
734      rules = r->next = r->prev = r;
735    }
736    return r;
737  } else {
738    free(lowername);
739    return (struct rule *)e->data;
740  }
741}
742
743void 
744parse_from(char *filename) {
745  extern FILE *yyin;
746  FILE *fin = NULL;
747 
748  if (filename != NULL) {
749    fin = fopen (filename, "rt");
750    if (!fin) {
751      fprintf(stderr, "input file not found: %s\n", filename);
752      exit(1);
753    }
754   
755    input_file = filename;
756    yyin = fin;
757  }
758  else {
759    yyin = stdin;
760    input_file = "stdin";
761  }
762 
763  scanreset();
764  yyparse();
765 
766  if (fin) fclose(fin); 
767}
768
769void
770predefine(fn_list *ifile) {
771  struct rule *r;
772  for (;ifile; ifile = ifile->next) {
773    parse_from(ifile->filename);
774  }
775 
776  for (r = rules; r; r = r->next) {
777    /* struct without rule definitions are created when names are used
778       they are != null when the rule was actually defined */
779    if (r->rule) 
780      r->predefined = 1;
781    else
782      r->used = 1;
783
784    if (r->next == rules)
785      break;
786  }
787}
788
789int
790summary(void) {
791  extern int yyerrors;
792  if (yyerrors > 0) {
793    fflush(stdout);
794    fprintf(stderr, "parsing failed: %d errors encountered\n", yyerrors);
795  }
796  return yyerrors;
797}
798
Note: See TracBrowser for help on using the repository browser.