home *** CD-ROM | disk | FTP | other *** search
/ Gold Fish 3 / goldfish_volume_3.bin / files / dev / lang / sgmls / src / sgmls.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-07-10  |  21.2 KB  |  1,033 lines

  1. /* sgmls.c:
  2.    Library for reading output of sgmls.
  3.  
  4.    Written by James Clark (jjc@jclark.com). */
  5.  
  6. #include "config.h"
  7. #include "std.h"
  8. #include "sgmls.h"
  9. #include "lineout.h"
  10.  
  11. #ifdef USE_PROTOTYPES
  12. #define P(parms) parms
  13. #else
  14. #define P(parms) ()
  15. #endif
  16.  
  17. typedef struct sgmls_data data_s;
  18. typedef struct sgmls_notation notation_s;
  19. typedef struct sgmls_internal_entity internal_entity_s;
  20. typedef struct sgmls_external_entity external_entity_s;
  21. typedef struct sgmls_entity entity_s;
  22. typedef struct sgmls_attribute attribute_s;
  23. typedef struct sgmls_event event_s;
  24.  
  25. /* lists are sorted in reverse order of level */
  26. struct list {
  27.   int subdoc_level;        /* -1 if associated with finished subdoc */
  28.   struct list *next;
  29.   char *name;
  30. };
  31.  
  32. struct entity_list {
  33.   int subdoc_level;
  34.   struct entity_list *next;
  35.   entity_s entity;
  36. };
  37.  
  38. struct notation_list {
  39.   int subdoc_level;
  40.   struct notation_list *next;
  41.   notation_s notation;
  42. };
  43.  
  44. struct sgmls {
  45.   FILE *fp;
  46.   char *buf;
  47.   unsigned buf_size;
  48.   struct entity_list *entities;
  49.   struct notation_list *notations;
  50.   attribute_s *attributes;
  51.   unsigned long lineno;
  52.   char *filename;
  53.   unsigned filename_size;
  54.   unsigned long input_lineno;
  55.   int subdoc_level;
  56.   char **files;            /* from `f' commands */
  57.   int nfiles;
  58.   char *sysid;            /* from `s' command */
  59.   char *pubid;            /* from `p' command */
  60. };
  61.  
  62. enum error_code {
  63.   E_ZERO,            /* Not an error */
  64.   E_NOMEM,            /* Out of memory */
  65.   E_BADESCAPE,            /* Bad escape */
  66.   E_NULESCAPE,            /* \000 other than in data */
  67.   E_NUL,            /* A null input character */
  68.   E_BADENTITY,            /* Reference to undefined entity */
  69.   E_INTERNALENTITY,        /* Internal entity when external was needed */
  70.   E_SYSTEM,            /* System input error */
  71.   E_COMMAND,            /* Bad command letter */
  72.   E_MISSING,            /* Missing arguments */
  73.   E_NUMBER,            /* Not a number */
  74.   E_ATTR,            /* Bad attribute type */
  75.   E_BADNOTATION,        /* Reference to undefined notation */
  76.   E_BADINTERNAL,        /* Bad internal entity type */
  77.   E_BADEXTERNAL,        /* Bad external entity type */
  78.   E_EOF,            /* EOF in middle of line */
  79.   E_SDATA,            /* \| other than in data */
  80.   E_LINELENGTH            /* line longer than UNSIGNED_MAX */
  81. };
  82.  
  83. static char *errlist[] = {
  84.   0,
  85.   "Out of memory",
  86.   "Bad escape",
  87.   "\\0 escape not in data",
  88.   "Nul character in input",
  89.   "Reference to undefined entity",
  90.   "Internal entity when external was needed",
  91.   "System input error",
  92.   "Bad command letter",
  93.   "Missing arguments",
  94.   "Not a number",
  95.   "Bad attribute type",
  96.   "Reference to undefined notation",
  97.   "Bad internal entity type",
  98.   "Bad external entity type",
  99.   "EOF in middle of line",
  100.   "\\| other than in data",
  101.   "Too many V commands",
  102.   "Input line too long"
  103. };
  104.  
  105. static void error P((enum error_code));
  106. static int parse_data P((char *, unsigned long *));
  107. static void parse_location P((char *, struct sgmls *));
  108. static void parse_notation P((char *, notation_s *));
  109. static void parse_internal_entity P((char *, internal_entity_s *));
  110. static void parse_external_entity
  111.   P((char *, struct sgmls *, external_entity_s *));
  112. static void parse_subdoc_entity P((char *, external_entity_s *));
  113. static attribute_s *parse_attribute P((struct sgmls *, char *));
  114. static void grow_datav P((void));
  115. static char *unescape P((char *));
  116. static char *unescape_file P((char *));
  117. static int unescape1 P((char *));
  118. static char *scan_token P((char **));
  119. static int count_args P((char *));
  120. static struct list *list_find P((struct list *, char *, int));
  121. static UNIV xmalloc P((unsigned));
  122. static UNIV xrealloc P((UNIV , unsigned));
  123. static char *strsave P((char *));
  124. static int read_line P((struct sgmls *));
  125. static notation_s *lookup_notation P((struct sgmls *, char *));
  126. static entity_s *lookup_entity P((struct sgmls *, char *));
  127. static external_entity_s *lookup_external_entity P((struct sgmls *, char *));
  128. static void define_external_entity P((struct sgmls *, external_entity_s *));
  129. static void define_internal_entity P((struct sgmls *, internal_entity_s *));
  130. static void define_notation P((struct sgmls *, notation_s *));
  131. static data_s *copy_data P((data_s *, int));
  132. static void list_finish_level P((struct list **, int));
  133. static void add_attribute P((attribute_s **, attribute_s *));
  134. static void default_errhandler P((int, char *, unsigned long));
  135.  
  136. #define xfree(s) do { if (s) free(s); } while (0)
  137.  
  138. static sgmls_errhandler *errhandler = default_errhandler;
  139. static unsigned long input_lineno = 0;
  140.  
  141. static data_s *datav = 0;
  142. static int datav_size = 0;
  143.  
  144. struct sgmls *sgmls_create(fp)
  145.      FILE *fp;
  146. {
  147.   struct sgmls *sp;
  148.  
  149.   sp = (struct sgmls *)malloc(sizeof(struct sgmls));
  150.   if (!sp)
  151.     return 0;
  152.   sp->fp = fp;
  153.   sp->entities = 0;
  154.   sp->notations = 0;
  155.   sp->attributes = 0;
  156.   sp->lineno = 0;
  157.   sp->filename = 0;
  158.   sp->filename_size = 0;
  159.   sp->input_lineno = 0;
  160.   sp->buf_size = 0;
  161.   sp->buf = 0;
  162.   sp->subdoc_level = 0;
  163.   sp->files = 0;
  164.   sp->nfiles = 0;
  165.   sp->sysid = 0;
  166.   sp->pubid = 0;
  167.   return sp;
  168. }
  169.  
  170. void sgmls_free(sp)
  171.      struct sgmls *sp;
  172. {
  173.   struct entity_list *ep;
  174.   struct notation_list *np;
  175.  
  176.   if (!sp)
  177.     return;
  178.   xfree(sp->filename);
  179.   sgmls_free_attributes(sp->attributes);
  180.  
  181.   for (ep = sp->entities; ep;) {
  182.     struct entity_list *tem = ep->next;
  183.     if (ep->entity.is_internal) {
  184.       xfree(ep->entity.u.internal.data.s);
  185.       free(ep->entity.u.internal.name);
  186.     }
  187.     else {
  188.       int i;
  189.       for (i = 0; i < ep->entity.u.external.nfilenames; i++)
  190.     xfree(ep->entity.u.external.filenames[i]);
  191.       xfree(ep->entity.u.external.filenames);
  192.       xfree(ep->entity.u.external.sysid);
  193.       xfree(ep->entity.u.external.pubid);
  194.       sgmls_free_attributes(ep->entity.u.external.attributes);
  195.       free(ep->entity.u.internal.name);
  196.     }
  197.     free(ep);
  198.     ep = tem;
  199.   }
  200.  
  201.   for (np = sp->notations; np;) {
  202.     struct notation_list *tem = np->next;
  203.     xfree(np->notation.sysid);
  204.     xfree(np->notation.pubid);
  205.     free(np->notation.name);
  206.     free(np);
  207.     np = tem;
  208.   }
  209.  
  210.   xfree(sp->buf);
  211.   xfree(sp->pubid);
  212.   xfree(sp->sysid);
  213.   if (sp->files) {
  214.     int i;
  215.     for (i = 0; i < sp->nfiles; i++)
  216.       free(sp->files[i]);
  217.     free(sp->files);
  218.   }
  219.   free(sp);
  220.  
  221.   xfree(datav);
  222.   datav = 0;
  223.   datav_size = 0;
  224. }
  225.  
  226. sgmls_errhandler *sgmls_set_errhandler(handler)
  227.      sgmls_errhandler *handler;
  228. {
  229.   sgmls_errhandler *old = errhandler;
  230.   if (handler)
  231.     errhandler = handler;
  232.   return old;
  233. }
  234.  
  235. int sgmls_next(sp, e)
  236.      struct sgmls *sp;
  237.      event_s *e;
  238. {
  239.   while (read_line(sp)) {
  240.     char *buf = sp->buf;
  241.  
  242.     e->filename = sp->filename;
  243.     e->lineno = sp->lineno;
  244.  
  245.     switch (buf[0]) {
  246.     case DATA_CODE:
  247.       e->u.data.n = parse_data(buf + 1, &sp->lineno);
  248.       e->u.data.v = datav;
  249.       e->type = SGMLS_EVENT_DATA;
  250.       return 1;
  251.     case START_CODE:
  252.       {
  253.     char *p;
  254.     e->u.start.attributes = sp->attributes;
  255.     sp->attributes = 0;
  256.     e->type = SGMLS_EVENT_START;
  257.     p = buf + 1;
  258.     e->u.start.gi = scan_token(&p);
  259.     return 1;
  260.       }
  261.     case END_CODE:
  262.       {
  263.     char *p = buf + 1;
  264.     e->type = SGMLS_EVENT_END;
  265.     e->u.end.gi = scan_token(&p);
  266.     return 1;
  267.       }
  268.     case START_SUBDOC_CODE:
  269.     case END_SUBDOC_CODE:
  270.       {
  271.     char *p = buf + 1;
  272.     char *name = scan_token(&p);
  273.     if (buf[0] == START_SUBDOC_CODE) {
  274.       e->u.entity = lookup_external_entity(sp, name);
  275.       sp->subdoc_level++;
  276.       e->type = SGMLS_EVENT_SUBSTART;
  277.     }
  278.     else {
  279.       e->type = SGMLS_EVENT_SUBEND;
  280.       list_finish_level((struct list **)&sp->entities, sp->subdoc_level);
  281.       list_finish_level((struct list **)&sp->notations, sp->subdoc_level);
  282.       sp->subdoc_level--;
  283.       e->u.entity = lookup_external_entity(sp, name);
  284.     }
  285.     return 1;
  286.       }
  287.     case ATTRIBUTE_CODE:
  288.       add_attribute(&sp->attributes, parse_attribute(sp, buf + 1));
  289.       break;
  290.     case DATA_ATTRIBUTE_CODE:
  291.       {
  292.     char *p = buf + 1;
  293.     char *name;
  294.     attribute_s *a;
  295.     external_entity_s *ext;
  296.  
  297.     name = scan_token(&p);
  298.     a = parse_attribute(sp, p);
  299.     ext = lookup_external_entity(sp, name);
  300.     add_attribute(&ext->attributes, a);
  301.       }
  302.       break;
  303.     case REFERENCE_ENTITY_CODE:
  304.       {
  305.     char *p = buf + 1;
  306.     char *name;
  307.     name = scan_token(&p);
  308.     e->u.entity = lookup_external_entity(sp, name);
  309.     e->type = SGMLS_EVENT_ENTITY;
  310.     return 1;
  311.       }
  312.     case DEFINE_NOTATION_CODE:
  313.       {
  314.     notation_s notation;
  315.  
  316.     parse_notation(buf + 1, ¬ation);
  317.     define_notation(sp, ¬ation);
  318.       }
  319.       break;
  320.     case DEFINE_EXTERNAL_ENTITY_CODE:
  321.       {
  322.     external_entity_s external;
  323.  
  324.     parse_external_entity(buf + 1, sp, &external);
  325.     define_external_entity(sp, &external);
  326.       }
  327.       break;
  328.     case DEFINE_SUBDOC_ENTITY_CODE:
  329.       {
  330.     external_entity_s external;
  331.  
  332.     parse_subdoc_entity(buf + 1, &external);
  333.     define_external_entity(sp, &external);
  334.       }
  335.       break;
  336.     case DEFINE_INTERNAL_ENTITY_CODE:
  337.       {
  338.     internal_entity_s internal;
  339.  
  340.     parse_internal_entity(buf + 1, &internal);
  341.     define_internal_entity(sp, &internal);
  342.       }
  343.       break;
  344.     case PI_CODE:
  345.       e->u.pi.len = unescape1(buf + 1);
  346.       e->u.pi.s = buf + 1;
  347.       e->type = SGMLS_EVENT_PI;
  348.       return 1;
  349.     case LOCATION_CODE:
  350.       parse_location(buf + 1, sp);
  351.       break;
  352.     case APPINFO_CODE:
  353.       e->u.appinfo = unescape(buf + 1);
  354.       e->type = SGMLS_EVENT_APPINFO;
  355.       return 1;
  356.     case SYSID_CODE:
  357.       sp->sysid = strsave(unescape(buf + 1));
  358.       break;
  359.     case PUBID_CODE:
  360.       sp->pubid = strsave(unescape(buf + 1));
  361.       break;
  362.     case FILE_CODE:
  363.       sp->files = xrealloc(sp->files, (sp->nfiles + 1)*sizeof(char *));
  364.       sp->files[sp->nfiles] = strsave(unescape_file(buf + 1));
  365.       sp->nfiles += 1;
  366.       break;
  367.     case CONFORMING_CODE:
  368.       e->type = SGMLS_EVENT_CONFORMING;
  369.       return 1;
  370.     default:
  371.       error(E_COMMAND);
  372.     }
  373.   }
  374.  
  375.   return 0;
  376. }
  377.  
  378. static
  379. int parse_data(p, linenop)
  380.      char *p;
  381.      unsigned long *linenop;
  382. {
  383.   int n = 0;
  384.   char *start = p;
  385.   char *q;
  386.   int is_sdata = 0;
  387.  
  388.   /* No need to copy before first escape. */
  389.  
  390.   for (; *p != '\\' && *p != '\0'; p++)
  391.     ;
  392.   q = p;
  393.   while (*p) {
  394.     if (*p == '\\') {
  395.       switch (*++p) {
  396.       case '\\':
  397.     *q++ = *p++;
  398.     break;
  399.       case 'n':
  400.     *q++ = RECHAR;
  401.     *linenop += 1;
  402.     p++;
  403.     break;
  404.       case '0':
  405.       case '1':
  406.       case '2':
  407.       case '3':
  408.       case '4':
  409.       case '5':
  410.       case '6':
  411.       case '7':
  412.     {
  413.       int val = *p++ - '0';
  414.       if (*p >= '0' && *p <= '7') {
  415.         val = val*8 + (*p++ - '0');
  416.         if (*p >= '0' && *p <= '7')
  417.           val = val*8 + (*p++ - '0');
  418.       }
  419.       *q++ = (char)val;
  420.     }
  421.     break;
  422.       case '|':
  423.     if (q > start || is_sdata) {
  424.       if (n >= datav_size)
  425.         grow_datav();
  426.       datav[n].s = start;
  427.       datav[n].len = q - start;
  428.       datav[n].is_sdata = is_sdata;
  429.       n++;
  430.     }
  431.     is_sdata = !is_sdata;
  432.     start = q;
  433.     p++;
  434.     break;
  435.       default:
  436.     error(E_BADESCAPE);
  437.       }
  438.     }
  439.     else
  440.       *q++ = *p++;
  441.   }
  442.  
  443.   if (q > start || is_sdata) {
  444.     if (n >= datav_size)
  445.       grow_datav();
  446.     datav[n].s = start;
  447.     datav[n].len = q - start;
  448.     datav[n].is_sdata = is_sdata;
  449.     n++;
  450.   }
  451.   return n;
  452. }
  453.  
  454. static
  455. void grow_datav()
  456. {
  457.   unsigned size = datav_size ? 2*datav_size : 2;
  458.   datav = (data_s *)xrealloc((UNIV)datav, size*sizeof(data_s));
  459.   datav_size = size;
  460. }
  461.  
  462. static
  463. void parse_location(s, sp)
  464.      char *s;
  465.      struct sgmls *sp;
  466. {
  467.   unsigned size;
  468.  
  469.   if (*s < '0' || *s > '9' || sscanf(s, "%lu", &sp->lineno) != 1)
  470.     error(E_NUMBER);
  471.   do {
  472.     ++s;
  473.   } while (*s >= '0' && *s <= '9');
  474.  
  475.   if (*s != ' ')
  476.     return;
  477.   s++;
  478.   s = unescape_file(s);
  479.   size = strlen(s) + 1;
  480.   if (size <= sp->filename_size)
  481.     strcpy(sp->filename, s);
  482.   else {
  483.     sp->filename = xrealloc(sp->filename, size);
  484.     strcpy(sp->filename, s);
  485.     sp->filename_size = size;
  486.   }
  487. }
  488.  
  489. static
  490. void parse_notation(s, n)
  491.      char *s;
  492.      notation_s *n;
  493. {
  494.   n->name = strsave(scan_token(&s));
  495. }
  496.  
  497. static
  498. void parse_internal_entity(s, e)
  499.      char *s;
  500.      internal_entity_s *e;
  501. {
  502.   char *type;
  503.  
  504.   e->name = strsave(scan_token(&s));
  505.   type = scan_token(&s);
  506.   if (strcmp(type, "CDATA") == 0)
  507.     e->data.is_sdata = 0;
  508.   else if (strcmp(type, "SDATA") == 0)
  509.     e->data.is_sdata = 1;
  510.   else
  511.     error(E_BADINTERNAL);
  512.   e->data.len = unescape1(s);
  513.   if (e->data.len == 0)
  514.     e->data.s = 0;
  515.   else {
  516.     e->data.s = xmalloc(e->data.len);
  517.     memcpy(e->data.s, s, e->data.len);
  518.   }
  519. }
  520.  
  521. static
  522. void parse_external_entity(s, sp, e)
  523.      char *s;
  524.      struct sgmls *sp;
  525.      external_entity_s *e;
  526. {
  527.   char *type;
  528.   char *notation;
  529.  
  530.   e->name = strsave(scan_token(&s));
  531.   type = scan_token(&s);
  532.   if (strcmp(type, "CDATA") == 0)
  533.     e->type = SGMLS_ENTITY_CDATA;
  534.   else if (strcmp(type, "SDATA") == 0)
  535.     e->type = SGMLS_ENTITY_SDATA;
  536.   else if (strcmp(type, "NDATA") == 0)
  537.     e->type = SGMLS_ENTITY_NDATA;
  538.   else
  539.     error(E_BADEXTERNAL);
  540.   notation = scan_token(&s);
  541.   e->notation = lookup_notation(sp, notation);
  542. }
  543.  
  544. static
  545. void parse_subdoc_entity(s, e)
  546.      char *s;
  547.      external_entity_s *e;
  548. {
  549.   e->name = strsave(scan_token(&s));
  550.   e->type = SGMLS_ENTITY_SUBDOC;
  551. }
  552.  
  553. static
  554. attribute_s *parse_attribute(sp, s)
  555.      struct sgmls *sp;
  556.      char *s;
  557. {
  558.   attribute_s *a;
  559.   char *type;
  560.  
  561.   a = (attribute_s *)xmalloc(sizeof(*a));
  562.   a->name = strsave(scan_token(&s));
  563.   type = scan_token(&s);
  564.   if (strcmp(type, "CDATA") == 0) {
  565.     unsigned long lineno = 0;
  566.     a->type = SGMLS_ATTR_CDATA;
  567.     a->value.data.n = parse_data(s, &lineno);
  568.     a->value.data.v = copy_data(datav, a->value.data.n);
  569.   }
  570.   else if (strcmp(type, "IMPLIED") == 0) {
  571.     a->type = SGMLS_ATTR_IMPLIED;
  572.   }
  573.   else if (strcmp(type, "NOTATION") == 0) {
  574.     a->type = SGMLS_ATTR_NOTATION;
  575.     a->value.notation = lookup_notation(sp, scan_token(&s));
  576.   }
  577.   else if (strcmp(type, "ENTITY") == 0) {
  578.     int n, i;
  579.     a->type = SGMLS_ATTR_ENTITY;
  580.     n = count_args(s);
  581.     if (n == 0)
  582.       error(E_MISSING);
  583.     a->value.entity.v = (entity_s **)xmalloc(n*sizeof(entity_s *));
  584.     a->value.entity.n = n;
  585.     for (i = 0; i < n; i++)
  586.       a->value.entity.v[i] = lookup_entity(sp, scan_token(&s));
  587.   }
  588.   else if (strcmp(type, "TOKEN") == 0) {
  589.     int n, i;
  590.     a->type = SGMLS_ATTR_TOKEN;
  591.     n = count_args(s);
  592.     if (n == 0)
  593.       error(E_MISSING);
  594.     a->value.token.v = (char **)xmalloc(n * sizeof(char *));
  595.     for (i = 0; i < n; i++)
  596.       a->value.token.v[i] = strsave(scan_token(&s));
  597.     a->value.token.n = n;
  598.   }
  599.   else
  600.     error(E_ATTR);
  601.   return a;
  602. }
  603.  
  604. void sgmls_free_attributes(p)
  605.      attribute_s *p;
  606. {
  607.   while (p) {
  608.     attribute_s *nextp = p->next;
  609.     switch (p->type) {
  610.     case SGMLS_ATTR_CDATA:
  611.       if (p->value.data.v) {
  612.     free(p->value.data.v[0].s);
  613.     free(p->value.data.v);
  614.       }
  615.       break;
  616.     case SGMLS_ATTR_TOKEN:
  617.       {
  618.     int i;
  619.     for (i = 0; i < p->value.token.n; i++)
  620.       free(p->value.token.v[i]);
  621.     xfree(p->value.token.v);
  622.       }
  623.       break;
  624.     case SGMLS_ATTR_ENTITY:
  625.       xfree(p->value.entity.v);
  626.       break;
  627.     case SGMLS_ATTR_IMPLIED:
  628.     case SGMLS_ATTR_NOTATION:
  629.       break;
  630.     }
  631.     free(p->name);
  632.     free(p);
  633.     p = nextp;
  634.   }
  635. }
  636.  
  637. static
  638. data_s *copy_data(v, n)
  639.      data_s *v;
  640.      int n;
  641. {
  642.   if (n == 0)
  643.     return 0;
  644.   else {
  645.     int i;
  646.     unsigned total;
  647.     char *p;
  648.     data_s *result;
  649.  
  650.     result = (data_s *)xmalloc(n*sizeof(data_s));
  651.     total = 0;
  652.     for (i = 0; i < n; i++)
  653.       total += v[i].len;
  654.     if (!total)
  655.       total++;
  656.     p = xmalloc(total);
  657.     for (i = 0; i < n; i++) {
  658.       result[i].s = p;
  659.       memcpy(result[i].s, v[i].s, v[i].len);
  660.       result[i].len = v[i].len;
  661.       p += v[i].len;
  662.       result[i].is_sdata = v[i].is_sdata;
  663.     }
  664.     return result;
  665.   }
  666. }
  667.  
  668. /* Unescape s, and return nul-terminated data.  Give an error
  669. if the data contains 0. */
  670.  
  671. static
  672. char *unescape(s)
  673.      char *s;
  674. {
  675.   int len = unescape1(s);
  676.   if (
  677. #ifdef __BORLANDC__
  678.       len > 0 &&
  679. #endif
  680.       memchr(s, '\0', len))
  681.     error(E_NULESCAPE);
  682.   s[len] = '\0';
  683.   return s;
  684. }
  685.  
  686. /* Like unescape(), but REs are represented by 012 not 015. */
  687.  
  688. static
  689. char *unescape_file(s)
  690.      char *s;
  691. {
  692.   char *p;
  693.   p = s = unescape(s);
  694.   while ((p = strchr(p, RECHAR)) != 0)
  695.     *p++ = '\n';
  696.   return s;
  697.  
  698. }
  699.  
  700. /* Unescape s, and return length of data.  The data may contain 0. */
  701.  
  702. static
  703. int unescape1(s)
  704.      char *s;
  705. {
  706.   const char *p;
  707.   char *q;
  708.  
  709.   q = strchr(s, '\\');
  710.   if (!q)
  711.     return (int)strlen(s);
  712.   p = q;
  713.   while (*p) {
  714.     if (*p == '\\') {
  715.       switch (*++p) {
  716.       case '\\':
  717.     *q++ = *p++;
  718.     break;
  719.       case 'n':
  720.     *q++ = RECHAR;
  721.     p++;
  722.     break;
  723.       case '0':
  724.       case '1':
  725.       case '2':
  726.       case '3':
  727.       case '4':
  728.       case '5':
  729.       case '6':
  730.       case '7':
  731.     {
  732.       int val = *p++ - '0';
  733.       if (*p >= '0' && *p <= '7') {
  734.         val = val*8 + (*p++ - '0');
  735.         if (*p >= '0' && *p <= '7')
  736.           val = val*8 + (*p++ - '0');
  737.       }
  738.       *q++ = (char)val;
  739.     }
  740.     break;
  741.       case '|':
  742.     error(E_SDATA);
  743.       default:
  744.     error(E_BADESCAPE);
  745.       }
  746.     }
  747.     else
  748.       *q++ = *p++;
  749.   }
  750.   return q - s;
  751. }
  752.  
  753. static
  754. char *scan_token(pp)
  755.      char **pp;
  756. {
  757.   char *start = *pp;
  758.   while (**pp != '\0') {
  759.     if (**pp == ' ') {
  760.       **pp = '\0';
  761.       *pp += 1;
  762.       break;
  763.     }
  764.     *pp += 1;
  765.   }
  766.   if (!*start)
  767.     error(E_MISSING);
  768.   return start;
  769. }
  770.  
  771. static
  772. int count_args(p)
  773.      char *p;
  774. {
  775.   int n = 0;
  776.  
  777.   while (*p != '\0') {
  778.     n++;
  779.     do {
  780.       ++p;
  781.       if (*p == ' ') {
  782.     p++;
  783.     break;
  784.       }
  785.     } while (*p != '\0');
  786.   }
  787.   return n;
  788. }
  789.  
  790. static
  791. int read_line(sp)
  792.      struct sgmls *sp;
  793. {
  794.   unsigned i = 0;
  795.   FILE *fp = sp->fp;
  796.   int c;
  797.   char *buf = sp->buf;
  798.   unsigned buf_size = sp->buf_size;
  799.  
  800.   c = getc(fp);
  801.   if (c == EOF) {
  802.     input_lineno = sp->input_lineno;
  803.     if (ferror(fp))
  804.       error(E_SYSTEM);
  805.     return 0;
  806.   }
  807.  
  808.   sp->input_lineno++;
  809.   input_lineno = sp->input_lineno;
  810.   for (;;) {
  811.     if (i >= buf_size) {
  812.       if (buf_size == 0)
  813.     buf_size = 24;
  814.       else if (buf_size > (unsigned)UINT_MAX/2) {
  815.     if (buf_size == (unsigned)UINT_MAX)
  816.       error(E_LINELENGTH);
  817.     buf_size = (unsigned)UINT_MAX;
  818.       }
  819.       else
  820.     buf_size *= 2;
  821.       buf = xrealloc(buf, buf_size);
  822.       sp->buf = buf;
  823.       sp->buf_size = buf_size;
  824.     }
  825.     if (c == '\0')
  826.       error(E_NUL);
  827.     if (c == '\n') {
  828.       buf[i] = '\0';
  829.       break;
  830.     }
  831.     buf[i++] = c;
  832.     c = getc(fp);
  833.     if (c == EOF) {
  834.       if (ferror(fp))
  835.     error(E_SYSTEM);
  836.       else
  837.     error(E_EOF);
  838.     }
  839.   }
  840.   return 1;
  841. }
  842.  
  843. static
  844. notation_s *lookup_notation(sp, name)
  845. struct sgmls *sp;
  846. char *name;
  847. {
  848.   struct notation_list *p
  849.     = (struct notation_list *)list_find((struct list *)sp->notations, name,
  850.                     sp->subdoc_level);
  851.   if (!p)
  852.     error(E_BADNOTATION);
  853.   return &p->notation;
  854. }
  855.  
  856. static
  857. entity_s *lookup_entity(sp, name)
  858. struct sgmls *sp;
  859. char *name;
  860. {
  861.   struct entity_list *p
  862.     = (struct entity_list *)list_find((struct list *)sp->entities, name,
  863.                       sp->subdoc_level);
  864.   if (!p)
  865.     error(E_BADENTITY);
  866.   return &p->entity;
  867. }
  868.  
  869. static
  870. external_entity_s *lookup_external_entity(sp, name)
  871. struct sgmls *sp;
  872. char *name;
  873. {
  874.   entity_s *p = lookup_entity(sp, name);
  875.   if (p->is_internal)
  876.     error(E_INTERNALENTITY);
  877.   return &p->u.external;
  878. }
  879.  
  880. static
  881. void define_external_entity(sp, e)
  882. struct sgmls *sp;
  883. external_entity_s *e;
  884. {
  885.   struct entity_list *p;
  886.   e->attributes = 0;
  887.   e->filenames = sp->files;
  888.   e->nfilenames = sp->nfiles;
  889.   sp->files = 0;
  890.   sp->nfiles = 0;
  891.   e->pubid = sp->pubid;
  892.   sp->pubid = 0;
  893.   e->sysid = sp->sysid;
  894.   sp->sysid = 0;
  895.   p = (struct entity_list *)xmalloc(sizeof(struct entity_list));
  896.   memcpy((UNIV)&p->entity.u.external, (UNIV)e, sizeof(*e));
  897.   p->entity.is_internal = 0;
  898.   p->subdoc_level = sp->subdoc_level;
  899.   p->next = sp->entities;
  900.   sp->entities = p;
  901. }
  902.  
  903. static
  904. void define_internal_entity(sp, e)
  905. struct sgmls *sp;
  906. internal_entity_s *e;
  907. {
  908.   struct entity_list *p;
  909.   p = (struct entity_list *)xmalloc(sizeof(struct entity_list));
  910.   memcpy((UNIV)&p->entity.u.internal, (UNIV)e, sizeof(*e));
  911.   p->entity.is_internal = 1;
  912.   p->subdoc_level = sp->subdoc_level;
  913.   p->next = sp->entities;
  914.   sp->entities = p;
  915. }
  916.  
  917. static
  918. void define_notation(sp, np)
  919. struct sgmls *sp;
  920. notation_s *np;
  921. {
  922.   struct notation_list *p;
  923.   np->sysid = sp->sysid;
  924.   sp->sysid = 0;
  925.   np->pubid = sp->pubid;
  926.   sp->pubid = 0;
  927.   p = (struct notation_list *)xmalloc(sizeof(struct notation_list));
  928.   memcpy((UNIV)&p->notation, (UNIV)np, sizeof(*np));
  929.   p->subdoc_level = sp->subdoc_level;
  930.   p->next = sp->notations;
  931.   sp->notations = p;
  932. }
  933.  
  934. static
  935. struct list *list_find(p, name, level)
  936.      struct list *p;
  937.      char *name;
  938.      int level;
  939. {
  940.   for (; p && p->subdoc_level == level; p = p->next)
  941.     if (strcmp(p->name, name) == 0)
  942.       return p;
  943.   return 0;
  944. }
  945.  
  946. /* Move all the items in the list whose subdoc level is level to the
  947. end of the list and make their subdoc_level -1. */
  948.  
  949. static
  950. void list_finish_level(listp, level)
  951.      struct list **listp;
  952.      int level;
  953. {
  954.   struct list **pp, *next_level, *old_level;
  955.   for (pp = listp; *pp && (*pp)->subdoc_level == level; pp = &(*pp)->next)
  956.     (*pp)->subdoc_level = -1;
  957.   next_level = *pp;
  958.   *pp = 0;
  959.   old_level = *listp;
  960.   *listp = next_level;
  961.   for (pp = listp; *pp; pp = &(*pp)->next)
  962.     ;
  963.   *pp = old_level;
  964. }
  965.  
  966. static
  967. void add_attribute(pp, a)
  968.      attribute_s **pp, *a;
  969. {
  970. #if 0
  971.   for (; *pp && strcmp((*pp)->name, a->name) < 0; pp = &(*pp)->next)
  972.     ;
  973. #endif
  974.   a->next = *pp;
  975.   *pp = a;
  976. }
  977.  
  978.  
  979. static
  980. char *strsave(s)
  981. char *s;
  982. {
  983.   if (!s)
  984.     return s;
  985.   else {
  986.     char *p = xmalloc(strlen(s) + 1);
  987.     strcpy(p, s);
  988.     return p;
  989.   }
  990. }
  991.  
  992. static
  993. UNIV xmalloc(n)
  994.   unsigned n;
  995. {
  996.   UNIV p = malloc(n);
  997.   if (!p)
  998.     error(E_NOMEM);
  999.   return p;
  1000. }
  1001.  
  1002. /* ANSI C says first argument to realloc can be NULL, but not everybody
  1003.    appears to support this. */
  1004.  
  1005. static
  1006. UNIV xrealloc(p, n)
  1007.      UNIV p;
  1008.      unsigned n;
  1009. {
  1010.   p = p ? realloc(p, n) : malloc(n);
  1011.   if (!p)
  1012.     error(E_NOMEM);
  1013.   return p;
  1014. }
  1015.  
  1016. static
  1017. void error(num)
  1018.      enum error_code num;
  1019. {
  1020.   (*errhandler)((int)num, errlist[num], input_lineno);
  1021.   abort();
  1022. }
  1023.  
  1024. static
  1025. void default_errhandler(num, msg, lineno)
  1026.      int num;
  1027.      char *msg;
  1028.      unsigned long lineno;
  1029. {
  1030.   fprintf(stderr, "Line %lu: %s\n", lineno, msg);
  1031.   exit(1);
  1032. }
  1033.