home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 98 / Skunkware 98.iso / src / net / bind-contrib.tar.gz / bind-contrib.tar / contrib / dnsparse / dnslex.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-10-25  |  5.2 KB  |  248 lines

  1. #ifndef lint
  2. char rcsid[] = "$Id: dnslex.c,v 8.1 1996/10/25 04:57:11 vixie Exp $";
  3. #endif /* lint */
  4.  
  5. /*
  6.  * A lexical analyzer for DNS master files.
  7.  *   Marion Hakanson (hakanson@cse.ogi.edu)
  8.  *   Oregon Graduate Institute of Science and Technology
  9.  *
  10.  * Copyright (c) 1990, Marion Hakanson.
  11.  *
  12.  * You may distribute under the terms of the GNU General Public License
  13.  * as specified in the README file that comes with the dnsparse kit.
  14.  *
  15.  * This program accepts as input DNS master files, as described
  16.  * in RFC-1035.  It breaks up the input in such a way that a single
  17.  * resource record (RR) is output on a single line, with a delimiter
  18.  * character between each token (or field) of the RR.
  19.  *
  20.  * The output format was designed for consumption by programs such
  21.  * as awk or perl, so the delimiter character can be used to quickly
  22.  * split the RR into its components.
  23.  *
  24.  * It is likely that one could change the add_*char, end_word, and
  25.  * end_line macros to put chars into a separate buffer or perform
  26.  * some other function, and thus use do_dblex() inside a full parser
  27.  * program (such as a DNS server).
  28.  *
  29.  * One other thing.  This program could probably have been written
  30.  * in lex instead of C, but lex has a number of builtin limits to
  31.  * the length of expressions (where RFC-1035 does not, in all cases).
  32.  * I probably should have used flex instead, but the simple state
  33.  * machine below was not that tough to implement, and it's also
  34.  * pretty quick and pretty small.
  35.  */
  36.  
  37. #include <stdio.h>
  38.  
  39. #ifdef BSD
  40. #define strchr index    /* system dependent */
  41. #define strrchr rindex
  42. #endif /* BSD */
  43. extern char *strchr(), *strrchr();
  44.  
  45. extern getopt(), optind, opterr;
  46. extern char *optarg;
  47.  
  48. #define FALSE 0
  49. #define TRUE  1
  50.  
  51. /* Globals */
  52. char *prog;
  53.  
  54.  
  55. usage_and_die()
  56. {
  57.     fprintf(stderr, "usage: %s [-d <char>]\n", prog);
  58.     exit(1);
  59. }
  60.  
  61.  
  62.  
  63. /* Special (to DNS) chars we output in printed (non-decimal-escaped) form */
  64. #define SPECS " \t\n;()\\.@"    /* for consumption by strchr() */
  65. #define SPECP " \\t\\n;()\\.@"    /* for consumption by fprintf() */
  66.  
  67.  
  68. main(argc, argv)
  69.     int  argc;
  70.     char **argv;
  71. {
  72. int opt;
  73.  
  74. /* Defaults */
  75. register FILE    *ifile = stdin,
  76.         *ofile = stdout;
  77. char delim = ':';
  78.  
  79. if ( prog = strrchr(argv[0], '/') )
  80.     prog++;
  81. else
  82.     prog = argv[0];
  83.  
  84. /* Parse the arguments */
  85. opterr = 0;
  86. while ( (opt = getopt(argc, argv, "d:")) != EOF )
  87.     switch ((char)opt)
  88.     {
  89.     case '?':
  90.         usage_and_die();
  91.         break;
  92.     case 'd':
  93.         delim = *optarg;
  94.         break;
  95.     default:
  96.         /* Not supposed to happen. */
  97.         fprintf(stderr, "%s: Hey getopt(3)!  Wake up!\n", prog);
  98.         usage_and_die();
  99.         break;
  100.     }
  101.         
  102.  
  103. /* This saves checking every char output against delim */
  104. if ( strchr(SPECS, delim) != NULL ) {
  105.     fprintf(stderr, "%s: delimiter '%c' cannot be one of '%s'.\n",
  106.             prog, delim, SPECP);
  107.     exit(1);
  108. }
  109.  
  110. (void) do_dblex(ifile, ofile, delim);
  111.  
  112. exit(0);
  113. }
  114.  
  115.  
  116.  
  117. int
  118. do_dblex (ifile, ofile, delim)
  119.     register FILE *ifile, *ofile;
  120.     char delim;
  121. {
  122. register int c;
  123. register int newword = FALSE;
  124. register int wordlen = 0;
  125. register int linelen = 0;
  126. int inbrackets = FALSE;
  127. int inquotes = FALSE;
  128.  
  129. /* no delim after last word on a line */
  130. #define add_char(c) \
  131. ( \
  132.     (newword ? (newword = FALSE, putc(delim,ofile)) : 0), \
  133.     putc((c),ofile), \
  134.     wordlen++ \
  135. )
  136.  
  137. /* don't count the backslash, but do check for delim */
  138. #define add_esc_char(c) ( add_char('\\'), putc((c),ofile) )
  139. #define add_dec_char(c) ( add_char('\\'), fprintf(ofile,"%3.3d",(char)(c)) )
  140.  
  141. /* ignore empty words except at beginning of a line */
  142. #define end_word() \
  143. ( \
  144.     (wordlen > 0 || linelen == 0) ? ( \
  145.     newword = TRUE, \
  146.     wordlen = 0, \
  147.     linelen++ \
  148.     ) : (0) \
  149. )
  150.  
  151. /* no delim at beginning of line; ignore empty lines */
  152. #define end_line() \
  153. ( \
  154.     (wordlen > 0) ? linelen++ : (0), \
  155.     newword = FALSE, \
  156.     wordlen = 0, \
  157.     (linelen > 0) ? ( \
  158.     putc('\n', ofile), \
  159.     linelen = 0 \
  160.     ) : (0) \
  161. )
  162.  
  163.  
  164.  
  165. while ( ! feof(ifile) ) {
  166.  
  167.     c = getc(ifile);
  168.     switch (c) {
  169.     case EOF:
  170.         break;
  171.     case ' ':
  172.     case '\t':
  173.         if ( inquotes )
  174.         add_esc_char(c);
  175.         else {
  176.         end_word();
  177.         while ( (c = getc(ifile)) != EOF && (c == ' ' || c == '\t') );
  178.         ungetc(c, ifile);
  179.         }
  180.         break;
  181.     case '\n':
  182.         if ( inquotes )
  183.         ; /* do nothing */
  184.         else if ( inbrackets )
  185.         end_word();
  186.         else
  187.         end_line();
  188.         break;
  189.     case ';':
  190.         if ( inquotes )
  191.         add_esc_char(c);
  192.         else {
  193.         if ( ! inbrackets )
  194.             end_line();
  195.         while ( (c = getc(ifile)) != EOF && c != '\n' ); /* skip */
  196.         }
  197.         break;
  198.     case '"':
  199.         if ( inquotes )
  200.         inquotes = FALSE;
  201.         else
  202.         inquotes = TRUE;
  203.         break;
  204.     case '(':
  205.         if ( inbrackets || inquotes )
  206.         add_esc_char(c);
  207.         else {
  208.         inbrackets = TRUE;
  209.         end_word();
  210.         }
  211.         break;
  212.     case ')':
  213.         if ( inbrackets && (! inquotes) ) {
  214.         inbrackets = FALSE;
  215.         end_word();
  216.         } else
  217.         add_esc_char(c);
  218.         break;
  219.     case '\\':
  220.         if ( (c = getc(ifile)) == EOF ) {
  221.         add_esc_char('\\');
  222.         end_line();
  223.         } else if ( c == '\n' ) {
  224.         if ( ! inquotes )
  225.             end_word();
  226.         } else if ( c == delim )
  227.         add_dec_char(c);    /* no delims inside fields */
  228.         else
  229.         add_esc_char(c);
  230.         break;
  231.     case '.':
  232.     case '@':
  233.         if ( inquotes )
  234.         add_esc_char(c);
  235.         else
  236.         add_char(c);
  237.         break;
  238.     default:
  239.         if ( c == delim )
  240.         add_dec_char(c);    /* no delims inside fields */
  241.         else
  242.         add_char(c);
  243.     }
  244. }
  245.  
  246. }
  247.  
  248.