home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / Tools / linuxdoc-sgml-1.1 / sgmls-1.1 / replace.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-03  |  8.6 KB  |  468 lines

  1. /* replace.c
  2.    Parse ASP style replacement file.
  3.  
  4.    Written by James Clark (jjc@jclark.com). */
  5.  
  6. #include "sgmlsasp.h"
  7. #include "replace.h"
  8.  
  9. #define TABLE_SIZE 251
  10.  
  11. struct table_entry {
  12.   enum event_type type;
  13.   char *gi;
  14.   struct replacement replacement;
  15.   struct table_entry *next;
  16. };
  17.  
  18. struct replacement_table {
  19.   struct table_entry *table[TABLE_SIZE];
  20. };
  21.  
  22. struct buffer {
  23.   char *s;
  24.   unsigned len;
  25.   unsigned size;
  26. };
  27.  
  28. /* Tokens returned by get_token(). */
  29.  
  30. #define STRING 1
  31. #define STAGO 2
  32. #define ETAGO 3
  33. #define PLUS 4
  34.  
  35. static int get P((void));
  36. static int peek P((void));
  37. static int get_token P((void));
  38. static void scan_name P((struct buffer *, int));
  39. static struct replacement *define_replacement
  40.   P((struct replacement_table *, enum event_type, char *));
  41. static struct replacement_item **parse_string
  42.   P((struct replacement_item **, int));
  43. static UNIV xmalloc P((unsigned));
  44. static UNIV xrealloc P((UNIV, unsigned));
  45. static struct replacement_item **add_replacement_data
  46.   P((struct replacement_item **, char *, unsigned));
  47. static struct replacement_item **add_replacement_attr
  48.   P((struct replacement_item **, char *));
  49. static int hash P((enum event_type, char *));
  50. static NO_RETURN void parse_error VP((char *,...));
  51. static VOID buffer_init P((struct buffer *));
  52. static VOID buffer_append P((struct buffer *, int));
  53. static char *buffer_extract P((struct buffer *));
  54. #if 0
  55. static VOID buffer_free P((struct buffer *));
  56. #endif
  57.  
  58. #define buffer_length(buf) ((buf)->len)
  59.  
  60. #define NEW(type) ((type *)xmalloc(sizeof(type)))
  61.  
  62. static int current_lineno;
  63. static char *current_file;
  64. static FILE *fp;
  65.  
  66. struct replacement_table *make_replacement_table()
  67. {
  68.   int i;
  69.   struct replacement_table *tablep;
  70.  
  71.   tablep = NEW(struct replacement_table);
  72.   for (i = 0; i < TABLE_SIZE; i++)
  73.     tablep->table[i] = 0;
  74.   return tablep;
  75. }
  76.  
  77. void load_replacement_file(tablep, file)
  78.      struct replacement_table *tablep;
  79.      char *file;
  80. {
  81.   int tok;
  82.   struct buffer name;
  83.  
  84.   buffer_init(&name);
  85.   errno = 0;
  86.   fp = fopen(file, "r");
  87.   if (!fp) {
  88.     if (errno)
  89.       error("can't open `%s': %s", file, strerror(errno));
  90.     else
  91.       error("can't open `%s'", file);
  92.   }
  93.       
  94.   current_lineno = 1;
  95.   current_file = file;
  96.   tok = get_token();
  97.   while (tok != EOF) {
  98.     struct replacement *p;
  99.     struct replacement_item **tail;
  100.     enum event_type type;
  101.  
  102.     if (tok != STAGO && tok != ETAGO)
  103.       parse_error("syntax error");
  104.     type = tok == STAGO ? START_ELEMENT : END_ELEMENT;
  105.     scan_name(&name, '>');
  106.     p = define_replacement(tablep, type, buffer_extract(&name));
  107.     tok = get_token();
  108.     if (tok == PLUS) {
  109.       if (p)
  110.     p->flags |= NEWLINE_BEGIN;
  111.       tok = get_token();
  112.     }
  113.     tail = p ? &p->items : 0;
  114.     while (tok == STRING) {
  115.       tail = parse_string(tail, type == START_ELEMENT);
  116.       tok = get_token();
  117.     }
  118.     if (tok == PLUS) {
  119.       if (p)
  120.     p->flags |= NEWLINE_END;
  121.       tok = get_token();
  122.     }
  123.   }
  124.   fclose(fp);
  125. }
  126.  
  127. static
  128. struct replacement_item **parse_string(tail, recog_attr)
  129.      struct replacement_item **tail;
  130.      int recog_attr;
  131. {
  132.   struct buffer buf;
  133.   unsigned len;
  134.   
  135.   buffer_init(&buf);
  136.   for (;;) {
  137.     int c = get();
  138.     if (c == '\"')
  139.       break;
  140.     if (recog_attr && c == '[') {
  141.       if (buffer_length(&buf)) {
  142.     len = buffer_length(&buf);
  143.     tail = add_replacement_data(tail, buffer_extract(&buf), len);
  144.       }
  145.       scan_name(&buf, ']');
  146.       tail = add_replacement_attr(tail, buffer_extract(&buf));
  147.     }
  148.     else {
  149.       if (c == '\\') {
  150.     c = get();
  151.     switch (c) {
  152.     case EOF:
  153.       parse_error("unfinished string at end of file");
  154.     case 's':
  155.       buffer_append(&buf, ' ');
  156.       break;
  157.     case 'n':
  158.       buffer_append(&buf, '\n');
  159.       break;
  160.     case 't':
  161.       buffer_append(&buf, '\t');
  162.       break;
  163.     case 'r':
  164.       buffer_append(&buf, '\r');
  165.       break;
  166.     case 'f':
  167.       buffer_append(&buf, '\f');
  168.       break;
  169.     case '0':
  170.     case '1':
  171.     case '2':
  172.     case '3':
  173.     case '4':
  174.     case '5':
  175.     case '6':
  176.     case '7':
  177.       {
  178.         int val = c - '0';
  179.         c = peek();
  180.         if ('0' <= c && c <= '7') {
  181.           (void)get();
  182.           val = val*8 + (c - '0');
  183.           c = peek();
  184.           if ('0' <= c && c <= '7') {
  185.         (void)get();
  186.         val = val*8 + (c - '0');
  187.           }
  188.         }
  189.         buffer_append(&buf, val);
  190.         break;
  191.       }
  192.     default:
  193.       buffer_append(&buf, c);
  194.       break;
  195.     }
  196.       }
  197.       else
  198.     buffer_append(&buf, c);
  199.     }
  200.   }
  201.   len = buffer_length(&buf);
  202.   if (len > 0)
  203.     tail = add_replacement_data(tail, buffer_extract(&buf), len);
  204.   return tail;
  205. }
  206.  
  207. static
  208. struct replacement_item **add_replacement_data(tail, buf, n)
  209.      struct replacement_item **tail;
  210.      char *buf;
  211.      unsigned n;
  212. {
  213.   if (!tail)
  214.     free(buf);
  215.   else {
  216.     *tail = NEW(struct replacement_item);
  217.     (*tail)->type = DATA_REPL;
  218.     (*tail)->u.data.n = n;
  219.     (*tail)->next = 0;
  220.     (*tail)->u.data.s = buf;
  221.     tail = &(*tail)->next;
  222.   }
  223.   return tail;
  224. }
  225.  
  226. static
  227. struct replacement_item **add_replacement_attr(tail, name)
  228.      struct replacement_item **tail;
  229.      char *name;
  230. {
  231.   if (!tail)
  232.     free(name);
  233.   else {
  234.     *tail = NEW(struct replacement_item);
  235.     (*tail)->type = ATTR_REPL;
  236.     (*tail)->next = 0;
  237.     (*tail)->u.attr = name;
  238.     tail = &(*tail)->next;
  239.   }
  240.   return tail;
  241. }
  242.  
  243. static
  244. int get_token()
  245. {
  246.   int c;
  247.  
  248.   for (;;) {
  249.     c = get();
  250.     while (isspace(c))
  251.       c = get();
  252.     if (c != '%')
  253.       break;
  254.     do {
  255.       c = get();
  256.       if (c == EOF)
  257.     return EOF;
  258.     } while (c != '\n');
  259.   }
  260.   switch (c) {
  261.   case '+':
  262.     return PLUS;
  263.   case '<':
  264.     c = peek();
  265.     if (c == '/') {
  266.       (void)get();
  267.       return ETAGO;
  268.     }
  269.     return STAGO;
  270.   case '"':
  271.     return STRING;
  272.   case EOF:
  273.     return EOF;
  274.   default:
  275.     parse_error("bad input character `%c'", c);
  276.   }
  277. }
  278.  
  279. static
  280. void scan_name(buf, term)
  281.      struct buffer *buf;
  282.      int term;
  283. {
  284.   int c;
  285.   for (;;) {
  286.     c = get();
  287.     if (c == term)
  288.       break;
  289.     if (c == '\n' || c == EOF)
  290.       parse_error("missing `%c'", term);
  291.     if (fold_general_names) {
  292.       if (islower((unsigned char)c))
  293.     c = toupper((unsigned char)c);
  294.     }
  295.     buffer_append(buf, c);
  296.   }
  297.   if (buffer_length(buf) == 0)
  298.     parse_error("empty name");
  299.   buffer_append(buf, '\0');
  300. }
  301.  
  302. static
  303. int get()
  304. {
  305.   int c = getc(fp);
  306.   if (c == '\n')
  307.     current_lineno++;
  308.   return c;
  309. }
  310.  
  311. static
  312. int peek()
  313. {
  314.   int c = getc(fp);
  315.   if (c != EOF)
  316.     ungetc(c, fp);
  317.   return c;
  318. }
  319.  
  320. struct replacement *lookup_replacement(tablep, type, name)
  321.      struct replacement_table *tablep;
  322.      enum event_type type;
  323.      char *name;
  324. {
  325.   int h = hash(type, name);
  326.   struct table_entry *p;
  327.   
  328.   for (p = tablep->table[h]; p; p = p->next)
  329.     if (strcmp(name, p->gi) == 0 && type == p->type)
  330.       return &p->replacement;
  331.   return 0;
  332. }
  333.  
  334. /* Return 0 if already defined. */
  335.  
  336. static
  337. struct replacement *define_replacement(tablep, type, name)
  338.      struct replacement_table *tablep;
  339.      enum event_type type;
  340.      char *name;
  341. {
  342.   int h = hash(type, name);
  343.   struct table_entry *p;
  344.   
  345.   for (p = tablep->table[h]; p; p = p->next)
  346.     if (strcmp(name, p->gi) == 0 && type == p->type)
  347.       return 0;
  348.   p = NEW(struct table_entry);
  349.   p->next = tablep->table[h];
  350.   tablep->table[h] = p;
  351.   p->type = type;
  352.   p->gi = name;
  353.   p->replacement.flags = 0;
  354.   p->replacement.items = 0;
  355.   return &p->replacement;
  356. }
  357.  
  358. static
  359. VOID buffer_init(buf)
  360.      struct buffer *buf;
  361. {
  362.   buf->size = buf->len = 0;
  363.   buf->s = 0;
  364. }
  365.  
  366. static
  367. char *buffer_extract(buf)
  368.      struct buffer *buf;
  369. {
  370.   char *s = buf->s;
  371.   buf->s = 0;
  372.   buf->len = 0;
  373.   buf->size = 0;
  374.   return s;
  375. }
  376.  
  377. #if 0
  378. static
  379. VOID buffer_free(buf)
  380.      struct buffer *buf;
  381. {
  382.   if (buf->s) {
  383.     free((UNIV)buf->s);
  384.     buf->s = 0;
  385.     buf->size = buf->size = 0;
  386.   }
  387. }
  388. #endif
  389.  
  390. static
  391. VOID buffer_append(buf, c)
  392.      struct buffer *buf;
  393.      int c;
  394. {
  395.   if (buf->len >= buf->size) {
  396.     if (!buf->size)
  397.       buf->s = (char *)xmalloc(buf->size = 10);
  398.     else
  399.       buf->s = (char *)xrealloc((UNIV)buf->s, buf->size *= 2);
  400.   }
  401.   buf->s[buf->len] = c;
  402.   buf->len += 1;
  403. }
  404.  
  405. static
  406. int hash(type, s)
  407.      enum event_type type;
  408.      char *s;
  409. {
  410.   unsigned long h = 0, g;
  411.   
  412.   while (*s != 0) {
  413.     h <<= 4;
  414.     h += *s++;
  415.     if ((g = h & 0xf0000000) != 0) {
  416.       h ^= g >> 24;
  417.       h ^= g;
  418.     }
  419.   }
  420.   h ^= (int)type;
  421.   return (int)(h % TABLE_SIZE);
  422. }
  423.  
  424. static
  425. UNIV xmalloc(n)
  426.      unsigned n;
  427. {
  428.   UNIV p = (UNIV)malloc(n);
  429.   if (!p)
  430.     parse_error("out of memory");
  431.   return p;
  432. }
  433.  
  434. static
  435. UNIV xrealloc(p, size)
  436.      UNIV p;
  437.      unsigned size;
  438. {
  439.   p = (UNIV)realloc(p, size);
  440.   if (!p)
  441.     parse_error("out of memory");
  442.   return p;
  443. }
  444.      
  445. static NO_RETURN
  446. #ifdef VARARGS
  447. void parse_error(va_alist) va_dcl
  448. #else
  449. void parse_error(char *message,...)
  450. #endif
  451. {
  452.   char buf[512];
  453. #ifdef VARARGS
  454.   char *message;
  455. #endif
  456.   va_list ap;
  457.   
  458. #ifdef VARARGS
  459.   va_start(ap);
  460.   message = va_arg(ap, char *);
  461. #else
  462.   va_start(ap, message);
  463. #endif
  464.   vsprintf(buf, message, ap);
  465.   va_end(ap);
  466.   error("%s:%d: %s", current_file, current_lineno, buf);
  467. }
  468.