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