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

  1. /* sgmldecl.c -
  2.    SGML declaration parsing.
  3.  
  4.    Written by James Clark (jjc@jclark.com).
  5. */
  6.  
  7. #include "sgmlincl.h"
  8.  
  9. /* Symbolic names for the error numbers that are be generated only by
  10. this module. */
  11.  
  12. #define E_SHUNCHAR 159
  13. #define E_STANDARD 163
  14. #define E_SIGNIFICANT 164
  15. #define E_BADLIT 165
  16. #define E_SCOPE 166
  17. #define E_XNUM 167
  18. #define E_BADVERSION 168
  19. #define E_NMUNSUP 169
  20. #define E_XNMLIT 170
  21. #define E_CHARDESC 171
  22. #define E_CHARDUP 172
  23. #define E_CHARRANGE 173
  24. #define E_7BIT 174
  25. #define E_CHARMISSING 175
  26. #define E_SHUNNED 176
  27. #define E_NONSGML 177
  28. #define E_CAPSET 178
  29. #define E_CAPMISSING 179
  30. #define E_SYNTAX 180
  31. #define E_CHARNUM 181
  32. #define E_SWITCHES 182
  33. #define E_INSTANCE 183
  34. #define E_ZEROFEATURE 184
  35. #define E_YESNO 185
  36. #define E_CAPACITY 186
  37. #define E_NOTSUPPORTED 187
  38. #define E_FORMAL 189
  39. #define E_BADCLASS 190
  40. #define E_MUSTBENON 191
  41. #define E_BADBASECHAR 199
  42. #define E_SYNREFUNUSED 200
  43. #define E_SYNREFUNDESC 201
  44. #define E_SYNREFUNKNOWN 202
  45. #define E_SYNREFUNKNOWNSET 203
  46. #define E_FUNDUP 204
  47. #define E_BADFUN 205
  48. #define E_FUNCHAR 206
  49. #define E_GENDELIM 207
  50. #define E_SRDELIM 208
  51. #define E_BADKEY 209
  52. #define E_BADQUANTITY 210
  53. #define E_BADNAME 211
  54. #define E_REFNAME 212
  55. #define E_DUPNAME 213
  56. #define E_QUANTITY 214
  57. #define E_QTOOBIG 215
  58. #define E_NMSTRTCNT 219
  59. #define E_NMCHARCNT 220
  60. #define E_NMDUP 221
  61. #define E_NMBAD 222
  62. #define E_NMMINUS 223
  63. #define E_UNKNOWNSET 227
  64. #define E_TOTALCAP 235
  65.  
  66. #define CANON_NMC '.'        /* Canonical name character. */
  67. #define CANON_NMS 'A'        /* Canonical name start character. */
  68. #define CANON_MIN ':'        /* Canonical minimum data character. */
  69.  
  70. #define SUCCESS 1
  71. #define FAIL 0
  72. #define SIZEOF(v) (sizeof(v)/sizeof(v[0]))
  73. #define matches(tok, str) (ustrcmp((tok)+1, (str)) == 0)
  74.  
  75. static UNCH standard[] = "ISO 8879:1986";
  76.  
  77. #define REFERENCE_SYNTAX "ISO 8879:1986//SYNTAX Reference//EN"
  78. #define CORE_SYNTAX "ISO 8879:1986//SYNTAX Core//EN"
  79.  
  80. static UNCH (*newkey)[REFNAMELEN+1] = 0;
  81.  
  82. struct pmap {
  83.      char *name;
  84.      UNIV value;
  85. };
  86.  
  87. /* The reference capacity set. */
  88. #define REFCAPSET \
  89. { 35000L, 35000L, 35000L, 35000L, 35000L, 35000L, 35000L, 35000L, 35000L, \
  90. 35000L, 35000L, 35000L, 35000L, 35000L, 35000L, 35000L, 35000L }
  91.  
  92. long refcapset[NCAPACITY] = REFCAPSET;
  93.  
  94. /* A pmap of known capacity sets. */
  95.  
  96. static struct pmap capset_map[] = {
  97.      { "ISO 8879:1986//CAPACITY Reference//EN", (UNIV)refcapset },
  98.      { 0 },
  99. };
  100.  
  101. /* Table of capacity names.  Must match *CAP in sgmldecl.h. */
  102.  
  103. char *captab[] = {
  104.      "TOTALCAP",
  105.      "ENTCAP",
  106.      "ENTCHCAP",
  107.      "ELEMCAP",
  108.      "GRPCAP",
  109.      "EXGRPCAP",
  110.      "EXNMCAP",
  111.      "ATTCAP",
  112.      "ATTCHCAP",
  113.      "AVGRPCAP",
  114.      "NOTCAP",
  115.      "NOTCHCAP",
  116.      "IDCAP",
  117.      "IDREFCAP",
  118.      "MAPCAP",
  119.      "LKSETCAP",
  120.      "LKNMCAP",
  121. };
  122.  
  123. /* The default SGML declaration. */
  124. #define MAXNUMBER 99999999L
  125.  
  126. /* Reference quantity set */
  127.  
  128. #define REFATTCNT 40
  129. #define REFATTSPLEN 960
  130. #define REFBSEQLEN 960
  131. #define REFDTAGLEN 16
  132. #define REFDTEMPLEN 16
  133. #define REFENTLVL 16
  134. #define REFGRPCNT 32
  135. #define REFGRPGTCNT 96
  136. #define REFGRPLVL 16
  137. #define REFNORMSEP 2
  138. #define REFPILEN 240
  139. #define REFTAGLEN 960
  140. #define REFTAGLVL 24
  141.  
  142. #define ALLOC_MAX 65534
  143.  
  144. #define BIGINT 30000
  145.  
  146. #define MAXATTCNT ((ALLOC_MAX/sizeof(struct ad)) - 2)
  147. #define MAXATTSPLEN BIGINT
  148. #define MAXBSEQLEN BIGINT
  149. #define MAXDTAGLEN 16
  150. #define MAXDTEMPLEN 16
  151. #define MAXENTLVL ((ALLOC_MAX/sizeof(struct source)) - 1)
  152. #define MAXGRPCNT MAXGRPGTCNT
  153. /* Must be between 96 and 253 */
  154. #define MAXGRPGTCNT 253
  155. #define MAXGRPLVL MAXGRPGTCNT
  156. #define MAXLITLEN BIGINT
  157. /* This guarantees that NAMELEN < LITLEN (ie there's always space for a name
  158. in a buffer intended for a literal.) */
  159. #define MAXNAMELEN (REFLITLEN - 1)
  160. #define MAXNORMSEP 2
  161. #define MAXPILEN BIGINT
  162. #define MAXTAGLEN BIGINT
  163. #define MAXTAGLVL ((ALLOC_MAX/sizeof(struct tag)) - 1)
  164.  
  165. /* Table of quantity names.  Must match Q* in sgmldecl.h. */
  166.  
  167. static char *quantity_names[] = {
  168.     "ATTCNT",
  169.     "ATTSPLEN",
  170.     "BSEQLEN",
  171.     "DTAGLEN",
  172.     "DTEMPLEN",
  173.     "ENTLVL",
  174.     "GRPCNT",
  175.     "GRPGTCNT",
  176.     "GRPLVL",
  177.     "LITLEN",
  178.     "NAMELEN",
  179.     "NORMSEP",
  180.     "PILEN",
  181.     "TAGLEN",
  182.     "TAGLVL",
  183. };
  184.  
  185. static int max_quantity[] = {
  186.     MAXATTCNT,
  187.     MAXATTSPLEN,
  188.     MAXBSEQLEN,
  189.     MAXDTAGLEN,
  190.     MAXDTEMPLEN,
  191.     MAXENTLVL,
  192.     MAXGRPCNT,
  193.     MAXGRPGTCNT,
  194.     MAXGRPLVL,
  195.     MAXLITLEN,
  196.     MAXNAMELEN,
  197.     MAXNORMSEP,
  198.     MAXPILEN,
  199.     MAXTAGLEN,
  200.     MAXTAGLVL,
  201. };
  202.  
  203. static char *quantity_changed;
  204.  
  205. /* Non-zero means the APPINFO parameter was not NONE. */
  206. static int appinfosw = 0;
  207.  
  208. struct sgmldecl sd = {
  209.      REFCAPSET,            /* capacity */
  210. #ifdef SUPPORT_SUBDOC
  211.      MAXNUMBER,            /* subdoc */
  212. #else /* not SUPPORT_SUBDOC */
  213.      0,                /* subdoc */
  214. #endif /* not SUPPORT_SUBDOC */
  215.      1,                /* formal */
  216.      1,                /* omittag */
  217.      1,                /* shorttag */
  218.      1,                /* shortref */
  219.      { 1, 0 },            /* general/entity name case translation */
  220.      {                /* reference quantity set */
  221.       REFATTCNT,
  222.       REFATTSPLEN,
  223.       REFBSEQLEN,
  224.       REFDTAGLEN,
  225.       REFDTEMPLEN,
  226.       REFENTLVL,
  227.       REFGRPCNT,
  228.       REFGRPGTCNT,
  229.       REFGRPLVL,
  230.       REFLITLEN,
  231.       REFNAMELEN,
  232.       REFNORMSEP,
  233.       REFPILEN,
  234.       REFTAGLEN,
  235.       REFTAGLVL,
  236.      },
  237. };
  238.  
  239. static int systemcharset[] = {
  240. 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
  241. 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
  242. 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
  243. 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
  244. 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
  245. 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
  246. 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
  247. 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
  248. 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
  249. 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
  250. 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175,
  251. 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191,
  252. 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207,
  253. 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223,
  254. 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
  255. 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255,
  256. };
  257.  
  258. /* This is a private use designating sequence that by convention
  259. refers to the whole system character set whatever it is. */
  260.  
  261. #define SYSTEM_CHARSET_DESIGNATING_SEQUENCE "ESC 2/5 2/15 3/0"
  262.  
  263. static struct pmap charset_map[] = {
  264.      { "ESC 2/5 4/0", (UNIV)iso646charset }, /* ISO 646 IRV */
  265.      { "ESC 2/8 4/2", (UNIV)iso646G0charset }, /* ISO Registration Number 6, ASCII */
  266.      { "ESC 2/8 4/0", (UNIV)iso646G0charset }, /* ISO Registration Number 6, ASCII */
  267.      { "ESC 2/13 4/1", (UNIV)iso8859_1charset }, /* Latin 1 */
  268.      { "ESC 2/1 4/0", (UNIV)iso646C0charset }, /* ISO 646, C0 */
  269.      { "ESC 2/2 4/3", (UNIV)iso6429C1charset }, /* ISO 6429, C1 */
  270.      { SYSTEM_CHARSET_DESIGNATING_SEQUENCE, (UNIV)systemcharset },
  271.                 /* system character set */
  272.      { 0 }
  273. };
  274.  
  275. static int synrefcharset[256];    /* the syntax reference character set */
  276.  
  277. #define CHAR_NONSGML 01
  278. #define CHAR_SIGNIFICANT 02
  279. #define CHAR_MAGIC 04
  280. #define CHAR_SHUNNED 010
  281.  
  282. static UNCH char_flags[256];
  283. static int done_nonsgml = 0;
  284. static UNCH *nlextoke = 0;    /* new lextoke */
  285. static UNCH *nlextran = 0;    /* new lextran */
  286. #define MAX_SAVED_ERRS 4
  287. static UNIV saved_errs[MAX_SAVED_ERRS];
  288. static int nsaved_errs = 0;
  289.  
  290. static UNCH kcharset[] = "CHARSET";
  291. static UNCH kbaseset[] = "BASESET";
  292. static UNCH kdescset[] = "DESCSET";
  293. static UNCH kunused[] = "UNUSED";
  294. static UNCH kcapacity[] = "CAPACITY";
  295. static UNCH kpublic[] = "PUBLIC";
  296. static UNCH ksgmlref[] = "SGMLREF";
  297. static UNCH kscope[] = "SCOPE";
  298. static UNCH kdocument[] = "DOCUMENT";
  299. static UNCH kinstance[] = "INSTANCE";
  300. static UNCH ksyntax[] = "SYNTAX";
  301. static UNCH kswitches[] = "SWITCHES";
  302. static UNCH kfeatures[] = "FEATURES";
  303. static UNCH kminimize[] = "MINIMIZE";
  304. static UNCH kdatatag[] = "DATATAG";
  305. static UNCH komittag[] = "OMITTAG";
  306. static UNCH krank[] = "RANK";
  307. static UNCH kshorttag[] = "SHORTTAG";
  308. static UNCH klink[] = "LINK";
  309. static UNCH ksimple[] = "SIMPLE";
  310. static UNCH kimplicit[] = "IMPLICIT";
  311. static UNCH kexplicit[] = "EXPLICIT";
  312. static UNCH kother[] = "OTHER";
  313. static UNCH kconcur[] = "CONCUR";
  314. static UNCH ksubdoc[] = "SUBDOC";
  315. static UNCH kformal[] = "FORMAL";
  316. static UNCH kyes[] = "YES";
  317. static UNCH kno[] = "NO";
  318. static UNCH kappinfo[] = "APPINFO";
  319. static UNCH knone[] = "NONE";
  320. static UNCH kshunchar[] = "SHUNCHAR";
  321. static UNCH kcontrols[] = "CONTROLS";
  322. static UNCH kfunction[] = "FUNCTION";
  323. static UNCH krs[] = "RS";
  324. static UNCH kre[] = "RE";
  325. static UNCH kspace[] = "SPACE";
  326. static UNCH knaming[] = "NAMING";
  327. static UNCH klcnmstrt[] = "LCNMSTRT";
  328. static UNCH kucnmstrt[] = "UCNMSTRT";
  329. static UNCH klcnmchar[] = "LCNMCHAR";
  330. static UNCH kucnmchar[] = "UCNMCHAR";
  331. static UNCH knamecase[] = "NAMECASE";
  332. static UNCH kdelim[] = "DELIM";
  333. static UNCH kgeneral[] = "GENERAL";
  334. static UNCH kentity[] = "ENTITY";
  335. static UNCH kshortref[] = "SHORTREF";
  336. static UNCH knames[] = "NAMES";
  337. static UNCH kquantity[] = "QUANTITY";
  338.  
  339. #define sderr mderr
  340.  
  341. static UNIV pmaplookup P((struct pmap *, char *));
  342. static UNCH *ltous P((long));
  343. static VOID sdfixstandard P((UNCH *, int));
  344. static int sdparm P((UNCH *, struct parse *));
  345. static int sdname P((UNCH *, UNCH *));
  346. static int sdckname P((UNCH *, UNCH *));
  347. static int sdversion P((UNCH *));
  348. static int sdcharset P((UNCH *));
  349. static int sdcsdesc P((UNCH *, int *));
  350. static int sdpubcapacity P((UNCH *));
  351. static int sdcapacity P((UNCH *));
  352. static int sdscope P((UNCH *));
  353. static VOID setlexical P((void));
  354. static VOID noemptytag P((void));
  355. static int sdpubsyntax P((UNCH *));
  356. static int sdsyntax P((UNCH *));
  357. static int sdxsyntax P((UNCH *));
  358. static int sdtranscharnum P((UNCH *));
  359. static int sdtranschar P((int));
  360. static int sdshunchar P((UNCH *));
  361. static int sdsynref P((UNCH *));
  362. static int sdfunction P((UNCH *));
  363. static int sdnaming P((UNCH *));
  364. static int sddelim P((UNCH *));
  365. static int sdnames P((UNCH *));
  366. static int sdquantity P((UNCH *));
  367. static int sdfeatures P((UNCH *));
  368. static int sdappinfo P((UNCH *));
  369. static VOID sdsaverr P((UNS, UNCH *, UNCH *));
  370.  
  371. static VOID bufsalloc P((void));
  372. static VOID bufsrealloc P((void));
  373.  
  374. /* Parse the SGML declaration. Return non-zero if there was some appinfo. */
  375.  
  376. int sgmldecl()
  377. {
  378.      int i;
  379.      int errsw = 0;
  380.      UNCH endbuf[REFNAMELEN+2];    /* buffer for parsing terminating > */
  381.      static int (*section[]) P((UNCH *)) = {
  382.       sdversion,
  383.       sdcharset,
  384.       sdcapacity,
  385.       sdscope,
  386.       sdsyntax,
  387.       sdfeatures,
  388.       sdappinfo,
  389.      };
  390.      /* These are needed if we use mderr. */
  391.      parmno = 0;
  392.      mdname = sgmlkey;
  393.      subdcl = NULL;
  394.      nsaved_errs = 0;
  395.      for (i = 0; i < SIZEOF(section); i++)
  396.       if ((*section[i])(tbuf) == FAIL) {
  397.            errsw = 1;
  398.            break;
  399.       }
  400.      if (sd.formal) {
  401.       /* print saved errors */
  402.       int i;
  403.       for (i = 0; i < nsaved_errs; i++)
  404.            svderr(saved_errs[i]);
  405.      }
  406.      else {
  407.       /* free saved errors */
  408.       int i;
  409.       for (i = 0; i < nsaved_errs; i++)
  410.            msgsfree(saved_errs[i]);
  411.      }
  412.  
  413.      if (!errsw)
  414.       setlexical();
  415.      bufsrealloc();
  416.      /* Parse the >.  Don't overwrite the appinfo. */
  417.      if (!errsw)
  418.       sdparm(endbuf, 0);
  419.      /* We must exit if we hit end of document. */
  420.      if (pcbsd.action == EOD_)
  421.       exiterr(161, &pcbsd);
  422.      if (!errsw && pcbsd.action != ESGD)
  423.       sderr(126, (UNCH *)0, (UNCH *)0);
  424.      return appinfosw;
  425. }
  426.  
  427. /* Parse the literal (which should contain the version of the
  428. standard) at the beginning of a SGML declaration. */
  429.  
  430. static int sdversion(tbuf)
  431. UNCH *tbuf;
  432. {
  433.      if (sdparm(tbuf, &pcblitv) != LIT1) {
  434.       sderr(123, (UNCH *)0, (UNCH *)0);
  435.       return FAIL;
  436.      }
  437.      sdfixstandard(tbuf, 0);
  438.      if (ustrcmp(tbuf, standard) != 0)
  439.       sderr(E_BADVERSION, tbuf, standard);
  440.      return SUCCESS;
  441. }
  442.  
  443. /* Parse the CHARSET section. Use one token lookahead. */
  444.  
  445. static int sdcharset(tbuf)
  446. UNCH *tbuf;
  447. {
  448.      int i;
  449.      int status[256];
  450.  
  451.      if (sdname(tbuf, kcharset) == FAIL) return FAIL;
  452.      (void)sdparm(tbuf, 0);
  453.  
  454.      if (sdcsdesc(tbuf, status) == FAIL)
  455.       return FAIL;
  456.  
  457. #if 0
  458.      for (i = 128; i < 256; i++)
  459.       if (status[i] != UNDESC)
  460.            break;
  461.      if (i >= 256) {
  462.       /* Only a 7-bit character set was described.  Fill it out to 8-bits. */
  463.       for (i = 128; i < 256; i++)
  464.            status[i] = UNUSED;
  465. #if 0
  466.       sderr(E_7BIT, (UNCH *)0, (UNCH *)0);
  467. #endif
  468.      }
  469. #endif
  470.      /* Characters that are declared UNUSED in the document character set
  471.     are assigned to non-SGML. */
  472.      for (i = 0; i < 256; i++) {
  473.       if (status[i] == UNDESC) {
  474. #if 0
  475.            sderr(E_CHARMISSING, ltous((long)i), (UNCH *)0);
  476. #endif
  477.            char_flags[i] |= CHAR_NONSGML;
  478.       }
  479.       else if (status[i] == UNUSED)
  480.            char_flags[i] |= CHAR_NONSGML;
  481.      }
  482.      done_nonsgml = 1;
  483.      return SUCCESS;
  484. }
  485.  
  486. /* Parse a character set description.   Uses one character lookahead. */
  487.  
  488. static int sdcsdesc(tbuf, status)
  489. UNCH *tbuf;
  490. int *status;
  491. {
  492.      int i;
  493.      int nsets = 0;
  494.      struct fpi fpi;
  495.  
  496.      for (i = 0; i < 256; i++)
  497.       status[i] = UNDESC;
  498.  
  499.      for (;;) {
  500.       int nchars;
  501.       int *baseset = 0;
  502.  
  503.       if (pcbsd.action != NAS1) {
  504.            if (nsets == 0) {
  505.             sderr(120, (UNCH *)0, (UNCH *)0);
  506.             return FAIL;
  507.            }
  508.            break;
  509.       }
  510.       if (!matches(tbuf, kbaseset)) {
  511.            if (nsets == 0) {
  512.             sderr(118, tbuf+1, kbaseset);
  513.             return FAIL;
  514.            }
  515.            break;
  516.       }
  517.       nsets++;
  518.       MEMZERO((UNIV)&fpi, FPISZ);
  519.       if (sdparm(tbuf, &pcblitv) != LIT1) {
  520.            sderr(123, (UNCH *)0, (UNCH *)0);
  521.            return FAIL;
  522.       }
  523.       fpi.fpipubis = tbuf;
  524.       /* Give a warning if it is not a CHARSET fpi. */
  525.       if (parsefpi(&fpi))
  526.            sdsaverr(E_FORMAL, (UNCH *)0, (UNCH *)0);
  527.       else if (fpi.fpic != FPICHARS)
  528.            sdsaverr(E_BADCLASS, kcharset, (UNCH *)0);
  529.       else {
  530.            fpi.fpipubis[fpi.fpil + fpi.fpill] = '\0';
  531.            baseset = (int *)pmaplookup(charset_map,
  532.                        (char *)fpi.fpipubis + fpi.fpil);
  533.            if (!baseset)
  534.             sderr(E_UNKNOWNSET, fpi.fpipubis + fpi.fpil, (UNCH *)0);
  535.       }
  536.       if (sdname(tbuf, kdescset) == FAIL) return FAIL;
  537.       nchars = 0;
  538.       for (;;) {
  539.            long start, count;
  540.            long basenum;
  541.            if (sdparm(tbuf, 0) != NUM1)
  542.             break;
  543.            start = atol((char *)tbuf);
  544.            if (sdparm(tbuf, 0) != NUM1) {
  545.             sderr(E_XNUM, (UNCH *)0, (UNCH *)0);
  546.             return FAIL;
  547.            }
  548.            count = atol((char *)tbuf);
  549.            switch (sdparm(tbuf, &pcblitv)) {
  550.            case NUM1:
  551.             basenum = atol((char *)tbuf);
  552.             break;
  553.            case LIT1:
  554.             basenum = UNKNOWN;
  555.             break;
  556.            case NAS1:
  557.             if (matches(tbuf, kunused)) {
  558.              basenum = UNUSED;
  559.              break;
  560.             }
  561.             /* fall through */
  562.            default:
  563.             sderr(E_CHARDESC, ltous(start), (UNCH *)0);
  564.             return FAIL;
  565.            }
  566.            if (start + count > 256)
  567.             sderr(E_CHARRANGE, (UNCH *)0, (UNCH *)0);
  568.            else {
  569.             int i;
  570.             int lim = (int)start + count;
  571.             for (i = (int)start; i < lim; i++) {
  572.              if (status[i] != UNDESC)
  573.                   sderr(E_CHARDUP, ltous((long)i), (UNCH *)0);
  574.              else if (basenum == UNUSED || basenum == UNKNOWN)
  575.                   status[i] = (int)basenum;
  576.              else if (baseset == 0)
  577.                   status[i] = UNKNOWN_SET;
  578.              else {
  579.                   int n = basenum + (i - start);
  580.                   if (n < 0 || n > 255)
  581.                    sderr(E_CHARRANGE, (UNCH *)0, (UNCH *)0);
  582.                   else {
  583.                    if (baseset[n] == UNUSED)
  584.                     sderr(E_BADBASECHAR, ltous((long)n),
  585.                           (UNCH *)0);
  586.                    status[i] = baseset[n];
  587.                   }
  588.              }
  589.             }
  590.            }
  591.            nchars++;
  592.       }
  593.       if (nchars == 0) {
  594.            sderr(E_XNUM, (UNCH *)0, (UNCH *)0);
  595.            return FAIL;
  596.       }
  597.      }
  598.      return SUCCESS;
  599. }
  600.  
  601. /* Parse the CAPACITY section.  Uses one token lookahead. */
  602.  
  603. static int sdcapacity(tbuf)
  604. UNCH *tbuf;
  605. {
  606.      int ncap;
  607.      int i;
  608.  
  609.      if (sdckname(tbuf, kcapacity) == FAIL)
  610.       return FAIL;
  611.      if (sdparm(tbuf, 0) != NAS1) {
  612.       sderr(120, (UNCH *)0, (UNCH *)0);
  613.       return FAIL;
  614.      }
  615.      if (matches(tbuf, kpublic))
  616.       return sdpubcapacity(tbuf);
  617.      if (!matches(tbuf, ksgmlref)) {
  618.       sderr(E_CAPACITY, tbuf+1, (UNCH *)0);
  619.       return FAIL;
  620.      }
  621.      memcpy((UNIV)sd.capacity, (UNIV)refcapset, sizeof(sd.capacity));
  622.      ncap = 0;
  623.      for (;;) {
  624.       int capno = -1;
  625.       int i;
  626.  
  627.       if (sdparm(tbuf, 0) != NAS1)
  628.            break;
  629.       for (i = 0; i < SIZEOF(captab); i++)
  630.            if (matches(tbuf, captab[i])) {
  631.             capno = i;
  632.             break;
  633.            }
  634.       if (capno < 0)
  635.            break;
  636.       if (sdparm(tbuf, 0) != NUM1) {
  637.            sderr(E_XNUM, (UNCH *)0, (UNCH *)0);
  638.            return FAIL;
  639.       }
  640.       sd.capacity[capno] = atol((char *)tbuf);
  641.       ncap++;
  642.      }
  643.      if (ncap == 0) {
  644.       sderr(E_CAPMISSING, (UNCH *)0, (UNCH *)0);
  645.       return FAIL;
  646.      }
  647.      for (i = 1; i < NCAPACITY; i++)
  648.       if (sd.capacity[i] > sd.capacity[0])
  649.            sderr(E_TOTALCAP, (UNCH *)captab[i], (UNCH *)0);
  650.      return SUCCESS;
  651. }
  652.  
  653. /* Parse a CAPACITY section that started with PUBLIC.  Must do one
  654. token lookahead, since sdcapacity() also does. */
  655.  
  656. static int sdpubcapacity(tbuf)
  657. UNCH *tbuf;
  658. {
  659.      UNIV ptr;
  660.      if (sdparm(tbuf, &pcblitv) != LIT1) {
  661.       sderr(123, (UNCH *)0, (UNCH *)0);
  662.       return FAIL;
  663.      }
  664.      sdfixstandard(tbuf, 1);
  665.      ptr = pmaplookup(capset_map, (char *)tbuf);
  666.      if (!ptr)
  667.       sderr(E_CAPSET, tbuf, (UNCH *)0);
  668.      else
  669.       memcpy((UNIV)sd.capacity, (UNIV)ptr, sizeof(sd.capacity));
  670.      (void)sdparm(tbuf, 0);
  671.      return SUCCESS;
  672. }
  673.  
  674. /* Parse the SCOPE section. Uses no lookahead. */
  675.  
  676. static int sdscope(tbuf)
  677. UNCH *tbuf;
  678. {
  679.      if (sdckname(tbuf, kscope) == FAIL)
  680.       return FAIL;
  681.      if (sdparm(tbuf, 0) != NAS1) {
  682.       sderr(120, (UNCH *)0, (UNCH *)0);
  683.       return FAIL;
  684.      }
  685.      if (matches(tbuf, kdocument))
  686.       ;
  687.      else if (matches(tbuf, kinstance))
  688.       sderr(E_INSTANCE, (UNCH *)0, (UNCH *)0);
  689.      else {
  690.       sderr(E_SCOPE, tbuf+1, (UNCH *)0);
  691.       return FAIL;
  692.      }
  693.      return SUCCESS;
  694. }
  695.  
  696. /* Parse the SYNTAX section.  Uses one token lookahead. */
  697.  
  698. static int sdsyntax(tbuf)
  699. UNCH *tbuf;
  700. {
  701.      if (sdname(tbuf, ksyntax) == FAIL) return FAIL;
  702.      if (sdparm(tbuf, 0) != NAS1) {
  703.       sderr(120, (UNCH *)0, (UNCH *)0);
  704.       return FAIL;
  705.      }
  706.      if (matches(tbuf, kpublic))
  707.       return sdpubsyntax(tbuf);
  708.      return sdxsyntax(tbuf);
  709. }
  710.  
  711. /* Parse the SYNTAX section which starts with PUBLIC.  Uses one token
  712. lookahead. */
  713.  
  714. static int sdpubsyntax(tbuf)
  715. UNCH *tbuf;
  716. {
  717.      int nswitches;
  718.      if (sdparm(tbuf, &pcblitv) != LIT1)
  719.       return FAIL;
  720.      sdfixstandard(tbuf, 1);
  721.      if (ustrcmp(tbuf, CORE_SYNTAX) == 0)
  722.       sd.shortref = 0;
  723.      else if (ustrcmp(tbuf, REFERENCE_SYNTAX) == 0)
  724.       sd.shortref = 1;
  725.      else
  726.       sderr(E_SYNTAX, tbuf, (UNCH *)0);
  727.      if (sdparm(tbuf, 0) != NAS1)
  728.       return SUCCESS;
  729.      if (!matches(tbuf, kswitches))
  730.       return SUCCESS;
  731.      nswitches = 0;
  732.      for (;;) {
  733.       int errsw = 0;
  734.  
  735.       if (sdparm(tbuf, 0) != NUM1)
  736.            break;
  737.       if (atol((char *)tbuf) > 255) {
  738.            sderr(E_CHARNUM, (UNCH *)0, (UNCH *)0);
  739.            errsw = 1;
  740.       }
  741.       if (sdparm(tbuf, 0) != NUM1) {
  742.            sderr(E_XNUM, (UNCH *)0, (UNCH *)0);
  743.            return FAIL;
  744.       }
  745.       if (!errsw) {
  746.            if (atol((char *)tbuf) > 255)
  747.             sderr(E_CHARNUM, (UNCH *)0, (UNCH *)0);
  748.       }
  749.       nswitches++;
  750.      }
  751.      if (nswitches == 0) {
  752.       sderr(E_XNUM, (UNCH *)0, (UNCH *)0);
  753.       return FAIL;
  754.      }
  755.      sderr(E_SWITCHES, (UNCH *)0, (UNCH *)0);
  756.      return SUCCESS;
  757. }
  758.  
  759. /* Parse an explicit concrete syntax. Uses one token lookahead. */
  760.  
  761. static
  762. int sdxsyntax(tbuf)
  763. UNCH *tbuf;
  764. {
  765.      static int (*section[]) P((UNCH *)) = {
  766.       sdshunchar,
  767.       sdsynref,
  768.       sdfunction,
  769.       sdnaming,
  770.       sddelim,
  771.       sdnames,
  772.       sdquantity,
  773.      };
  774.      int i;
  775.  
  776.      for (i = 0; i < SIZEOF(section); i++)
  777.       if ((*section[i])(tbuf) == FAIL)
  778.            return FAIL;
  779.      return SUCCESS;
  780. }
  781.  
  782. /* Parse the SHUNCHAR section. Uses one token lookahead. */
  783.  
  784. static
  785. int sdshunchar(tbuf)
  786. UNCH *tbuf;
  787. {
  788.      int i;
  789.      for (i = 0; i < 256; i++)
  790.       char_flags[i] &= ~CHAR_SHUNNED;
  791.  
  792.      if (sdckname(tbuf, kshunchar) == FAIL)
  793.       return FAIL;
  794.  
  795.      if (sdparm(tbuf, 0) == NAS1) {
  796.       if (matches(tbuf, knone)) {
  797.            (void)sdparm(tbuf, 0);
  798.            return SUCCESS;
  799.       }
  800.       if (matches(tbuf, kcontrols)) {
  801.            for (i = 0; i < 256; i++)
  802.             if (ISASCII(i) && iscntrl(i))
  803.              char_flags[i] |= CHAR_SHUNNED;
  804.            if (sdparm(tbuf, 0) != NUM1)
  805.             return SUCCESS;
  806.       }
  807.      }
  808.      if (pcbsd.action != NUM1) {
  809.       sderr(E_SHUNCHAR, (UNCH *)0, (UNCH *)0);
  810.       return FAIL;
  811.      }
  812.      do {
  813.       long n = atol((char *)tbuf);
  814.       if (n > 255)
  815.            sderr(E_CHARNUM, (UNCH *)0, (UNCH *)0);
  816.       else
  817.            char_flags[(int)n] |= CHAR_SHUNNED;
  818.      } while (sdparm(tbuf, 0) == NUM1);
  819.      return SUCCESS;
  820. }
  821.  
  822. /* Parse the syntax reference character set. Uses one token lookahead. */
  823.  
  824. static
  825. int sdsynref(tbuf)
  826. UNCH *tbuf;
  827. {
  828.      return sdcsdesc(tbuf, synrefcharset);
  829. }
  830.  
  831. /* Translate a character number from the syntax reference character set
  832. to the system character set. If it can't be done, give an error message
  833. and return -1. */
  834.  
  835. static
  836. int sdtranscharnum(tbuf)
  837. UNCH *tbuf;
  838. {
  839.      long n = atol((char *)tbuf);
  840.      if (n > 255) {
  841.       sderr(E_CHARNUM, (UNCH *)0, (UNCH *)0);
  842.       return -1;
  843.      }
  844.      return sdtranschar((int)n);
  845. }
  846.  
  847.  
  848. static
  849. int sdtranschar(n)
  850. int n;
  851. {
  852.      int ch = synrefcharset[n];
  853.      if (ch >= 0)
  854.       return ch;
  855.      switch (ch) {
  856.      case UNUSED:
  857.       sderr(E_SYNREFUNUSED, ltous((long)n), (UNCH *)0);
  858.       break;
  859.      case UNDESC:
  860.       sderr(E_SYNREFUNDESC, ltous((long)n), (UNCH *)0);
  861.       break;
  862.      case UNKNOWN:
  863.       sderr(E_SYNREFUNKNOWN, ltous((long)n), (UNCH *)0);
  864.       break;
  865.      case UNKNOWN_SET:
  866.       sderr(E_SYNREFUNKNOWNSET, ltous((long)n), (UNCH *)0);
  867.       break;
  868.      default:
  869.       abort();
  870.      }
  871.      return -1;
  872. }
  873.  
  874.  
  875. /* Parse the function section. Uses two tokens lookahead. "NAMING"
  876. could be a function name. */
  877.  
  878. static
  879. int sdfunction(tbuf)
  880. UNCH *tbuf;
  881. {
  882.      static UNCH *fun[] = { kre, krs, kspace };
  883.      static int funval[] = { RECHAR, RSCHAR, ' ' };
  884.      int i;
  885.      int had_tab = 0;
  886.      int changed = 0;        /* attempted to change reference syntax */
  887.  
  888.      if (sdckname(tbuf, kfunction) == FAIL)
  889.       return FAIL;
  890.      for (i = 0; i < SIZEOF(fun); i++) {
  891.       int ch;
  892.       if (sdname(tbuf, fun[i]) == FAIL)
  893.            return FAIL;
  894.       if (sdparm(tbuf, 0) != NUM1) {
  895.            sderr(E_XNUM, (UNCH *)0, (UNCH *)0);
  896.            return FAIL;
  897.       }
  898.       ch = sdtranscharnum(tbuf);
  899.       if (ch >= 0 && ch != funval[i])
  900.            changed = 1;
  901.      }
  902.      for (;;) {
  903.       int tabsw = 0;
  904.       int namingsw = 0;
  905.       if (sdparm(tbuf, 0) != NAS1) {
  906.            sderr(120, (UNCH *)0, (UNCH *)0);
  907.            return FAIL;
  908.       }
  909.       if (matches(tbuf, (UNCH *)"TAB")) {
  910.            tabsw = 1;
  911.            if (had_tab)
  912.             sderr(E_FUNDUP, (UNCH *)0, (UNCH *)0);
  913.       }
  914.       else {
  915.            for (i = 0; i < SIZEOF(fun); i++)
  916.             if (matches(tbuf, fun[i]))
  917.              sderr(E_BADFUN, fun[i], (UNCH *)0);
  918.            if (matches(tbuf, knaming))
  919.             namingsw = 1;
  920.            else
  921.             changed = 1;
  922.       }
  923.       if (sdparm(tbuf, 0) != NAS1) {
  924.            sderr(120, (UNCH *)0, (UNCH *)0);
  925.            return FAIL;
  926.       }
  927.       if (namingsw) {
  928.            if (matches(tbuf, klcnmstrt))
  929.             break;
  930.            changed = 1;
  931.       }
  932.       if (sdparm(tbuf, 0) != NUM1) {
  933.            sderr(E_XNUM, (UNCH *)0, (UNCH *)0);
  934.            return FAIL;
  935.       }
  936.       if (tabsw && !had_tab) {
  937.            int ch = sdtranscharnum(tbuf);
  938.            if (ch >= 0 && ch != TABCHAR)
  939.             changed = 1;
  940.            had_tab = 1;
  941.       }
  942.  
  943.      }
  944.      if (!had_tab)
  945.       changed = 1;
  946.      if (changed)
  947.       sderr(E_FUNCHAR, (UNCH *)0, (UNCH *)0);
  948.      return SUCCESS;
  949. }
  950.  
  951. /* Parse the NAMING section.  Uses no lookahead. */
  952.  
  953. static
  954. int sdnaming(tbuf)
  955. UNCH *tbuf;
  956. {
  957.      int i;
  958.      int bad = 0;
  959.      static UNCH *classes[] = { klcnmstrt, kucnmstrt, klcnmchar, kucnmchar };
  960.      static UNCH *types[] = { kgeneral, kentity };
  961.  
  962. #define NCLASSES SIZEOF(classes)
  963.  
  964.      int bufsize = 4;        /* allocated size of buf */
  965.      UNCH *buf = (UNCH *)rmalloc(bufsize); /* holds characters
  966.                           in naming classes */
  967.      int bufi = 0;        /* next index into buf */
  968.      int start[NCLASSES];    /* index of first character for each class */
  969.      int count[NCLASSES];    /* number of characters for each class */
  970.  
  971.      for (i = 0; i < NCLASSES; i++) {
  972.       UNCH *s;
  973.  
  974.       if (sdckname(tbuf, classes[i]) == FAIL) {
  975.            frem((UNIV)buf);
  976.            return FAIL;
  977.       }
  978.       if (sdparm(tbuf, &pcblitp) != LIT1) {
  979.            sderr(123, (UNCH *)0, (UNCH *)0);
  980.            frem((UNIV)buf);
  981.            return FAIL;
  982.       }
  983.       start[i] = bufi;
  984.  
  985.       for (s = tbuf; *s; s++) {
  986.            int c = *s;
  987.            if (c == DELNONCH) {
  988.             c = UNSHIFTNON(*s);
  989.             s++;
  990.            }
  991.            c = sdtranschar(c);
  992.            if (c < 0)
  993.             bad = 1;
  994.            else if ((char_flags[c] & (CHAR_SIGNIFICANT | CHAR_MAGIC))
  995.             && c != '.' && c != '-'
  996.                         && !(c == '_' && i >= 2)) {
  997.             int class = lextoke[c];
  998.             if (class == SEP || class == SP || class == NMC
  999.             || class == NMS || class == NU)
  1000.              sderr(E_NMBAD, ltous((long)c), (UNCH *)0);
  1001.             else
  1002.              sderr(E_NMUNSUP, ltous((long)c), (UNCH *)0);
  1003.             bad = 1;
  1004.            }
  1005.            if (bufi >= bufsize)
  1006.             buf = (UNCH *)rrealloc((UNIV)buf, bufsize *= 2);
  1007.            buf[bufi++] = c;
  1008.       }
  1009.  
  1010.       count[i] = bufi - start[i];
  1011.       (void)sdparm(tbuf, 0);
  1012.      }
  1013.      if (!bad && count[0] != count[1]) {
  1014.       sderr(E_NMSTRTCNT, (UNCH *)0, (UNCH *)0);
  1015.       bad = 1;
  1016.      }
  1017.      if (!bad && count[2] != count[3]) {
  1018.       sderr(E_NMCHARCNT, (UNCH *)0, (UNCH *)0);
  1019.       bad = 1;
  1020.      }
  1021.      if (!bad) {
  1022.       nlextoke = (UNCH *)rmalloc(256);
  1023.       memcpy((UNIV)nlextoke, lextoke, 256);
  1024.       nlextoke['.'] = nlextoke['-'] = INV;
  1025.  
  1026.       nlextran = (UNCH *)rmalloc(256);
  1027.       memcpy((UNIV)nlextran, lextran, 256);
  1028.  
  1029.       for (i = 0; i < count[0]; i++) {
  1030.            UNCH lc = buf[start[0] + i];
  1031.            UNCH uc = buf[start[1] + i];
  1032.            nlextoke[lc] = NMS;
  1033.            nlextoke[uc] = NMS;
  1034.            nlextran[lc] = uc;
  1035.       }
  1036.  
  1037.       for (i = 0; i < count[2]; i++) {
  1038.            UNCH lc = buf[start[2] + i];
  1039.            UNCH uc = buf[start[3] + i];
  1040.            if (nlextoke[lc] == NMS) {
  1041.             sderr(E_NMDUP, ltous((long)lc), (UNCH *)0);
  1042.             bad = 1;
  1043.            }
  1044.            else if (nlextoke[uc] == NMS) {
  1045.             sderr(E_NMDUP, ltous((long)uc), (UNCH *)0);
  1046.             bad = 1;
  1047.            }
  1048.            else {
  1049.             nlextoke[lc] = NMC;
  1050.             nlextoke[uc] = NMC;
  1051.             nlextran[lc] = uc;
  1052.            }
  1053.       }
  1054.       if (nlextoke['-'] != NMC) {
  1055.            sderr(E_NMMINUS, (UNCH *)0, (UNCH *)0);
  1056.            bad = 1;
  1057.       }
  1058.       if (bad) {
  1059.            if (nlextoke) {
  1060.             frem((UNIV)nlextoke);
  1061.             nlextoke = 0;
  1062.            }
  1063.            if (nlextran) {
  1064.             frem((UNIV)nlextran);
  1065.             nlextran = 0;
  1066.            }
  1067.       }
  1068.      }
  1069.  
  1070.      frem((UNIV)buf);
  1071.  
  1072.      if (sdckname(tbuf, knamecase) == FAIL)
  1073.       return FAIL;
  1074.      for (i = 0; i < SIZEOF(types); ++i) {
  1075.       if (sdname(tbuf, types[i]) == FAIL)
  1076.            return FAIL;
  1077.       if (sdparm(tbuf, 0) != NAS1) {
  1078.            sderr(120, (UNCH *)0, (UNCH *)0);
  1079.            return FAIL;
  1080.       }
  1081.       if (matches(tbuf, kyes))
  1082.            sd.namecase[i] = 1;
  1083.       else if (matches(tbuf, kno))
  1084.            sd.namecase[i] = 0;
  1085.       else {
  1086.            sderr(E_YESNO, tbuf+1, (UNCH *)0);
  1087.            return FAIL;
  1088.       }
  1089.      }
  1090.      return SUCCESS;
  1091. }
  1092.  
  1093. /* Parse the DELIM section. Uses one token lookahead. */
  1094.  
  1095. static
  1096. int sddelim(tbuf)
  1097. UNCH *tbuf;
  1098. {
  1099.      int changed = 0;
  1100.      if (sdname(tbuf, kdelim) == FAIL
  1101.      || sdname(tbuf, kgeneral) == FAIL
  1102.      || sdname(tbuf, ksgmlref) == FAIL)
  1103.       return FAIL;
  1104.      for (;;) {
  1105.       if (sdparm(tbuf, 0) != NAS1) {
  1106.            sderr(120, (UNCH *)0, (UNCH *)0);
  1107.            return FAIL;
  1108.       }
  1109.       if (matches(tbuf, kshortref))
  1110.            break;
  1111.       if (sdparm(tbuf, &pcblitp) != LIT1) {
  1112.            sderr(123, (UNCH *)0, (UNCH *)0);
  1113.            return FAIL;
  1114.       }
  1115.       changed = 1;
  1116.      }
  1117.      if (changed) {
  1118.       sderr(E_GENDELIM, (UNCH *)0,(UNCH *)0);
  1119.       changed = 0;
  1120.      }
  1121.      if (sdparm(tbuf, 0) != NAS1) {
  1122.       sderr(120, (UNCH *)0, (UNCH *)0);
  1123.       return FAIL;
  1124.      }
  1125.      if (matches(tbuf, ksgmlref))
  1126.       sd.shortref = 1;
  1127.      else if (matches(tbuf, knone))
  1128.       sd.shortref = 0;
  1129.      else {
  1130.       sderr(118, tbuf+1, ksgmlref);    /* probably they forgot SGMLREF */
  1131.       return FAIL;
  1132.      }
  1133.      while (sdparm(tbuf, &pcblitp) == LIT1)
  1134.       changed = 1;
  1135.      if (changed)
  1136.       sderr(E_SRDELIM, (UNCH *)0, (UNCH *)0);
  1137.      return SUCCESS;
  1138. }
  1139.  
  1140. /* Parse the NAMES section. Uses one token lookahead. */
  1141.  
  1142. static
  1143. int sdnames(tbuf)
  1144. UNCH *tbuf;
  1145. {
  1146.      int i;
  1147.      if (sdckname(tbuf, knames) == FAIL)
  1148.       return FAIL;
  1149.      if (sdname(tbuf, ksgmlref) == FAIL)
  1150.       return FAIL;
  1151.  
  1152.      while (sdparm(tbuf, 0) == NAS1) {
  1153.       int j;
  1154.       if (matches(tbuf, kquantity))
  1155.            break;
  1156.       for (i = 0; i < NKEYS; i++)
  1157.            if (matches(tbuf, key[i]))
  1158.             break;
  1159.       if (i >= NKEYS) {
  1160.            sderr(E_BADKEY, tbuf+1, (UNCH *)0);
  1161.            return FAIL;
  1162.       }
  1163.       if (sdparm(tbuf, &pcblitp) != NAS1) {
  1164.            sderr(120, (UNCH *)0, (UNCH *)0);
  1165.            return FAIL;
  1166.       }
  1167.       if (!newkey) {
  1168.            newkey = (UNCH (*)[REFNAMELEN+1])rmalloc((REFNAMELEN+1)*NKEYS);
  1169.            MEMZERO((UNIV)newkey, (REFNAMELEN+1)*NKEYS);
  1170.       }
  1171.       for (j = 0; j < NKEYS; j++) {
  1172.            if (matches(tbuf, key[j])) {
  1173.             sderr(E_REFNAME, tbuf + 1, (UNCH *)0);
  1174.             break;
  1175.            }
  1176.            if (matches(tbuf, newkey[j])) {
  1177.             sderr(E_DUPNAME, tbuf + 1, (UNCH *)0);
  1178.             break;
  1179.            }
  1180.       }
  1181.       if (j >= NKEYS)
  1182.            ustrcpy(newkey[i], tbuf + 1);
  1183.      }
  1184.      /* Now install the new keys. */
  1185.      if (newkey) {
  1186.       for (i = 0; i < NKEYS; i++)
  1187.            if (newkey[i][0] != '\0') {
  1188.             UNCH temp[REFNAMELEN + 1];
  1189.  
  1190.             ustrcpy(temp, key[i]);
  1191.             ustrcpy(key[i], newkey[i]);
  1192.             ustrcpy(newkey[i], temp);
  1193.            }
  1194.      }
  1195.      return SUCCESS;
  1196. }
  1197.  
  1198. /* Parse the QUANTITY section. Uses one token lookahead. */
  1199.  
  1200. static int sdquantity(tbuf)
  1201. UNCH *tbuf;
  1202. {
  1203.      int quantity[NQUANTITY];
  1204.      int i;
  1205.  
  1206.      for (i = 0; i < NQUANTITY; i++)
  1207.       quantity[i] = -1;
  1208.      if (sdckname(tbuf, kquantity) == FAIL)
  1209.       return FAIL;
  1210.      if (sdname(tbuf, ksgmlref) == FAIL)
  1211.       return FAIL;
  1212.      while (sdparm(tbuf, 0) == NAS1 && !matches(tbuf, kfeatures)) {
  1213.       long n;
  1214.       for (i = 0; i < SIZEOF(quantity_names); i++)
  1215.            if (matches(tbuf, quantity_names[i]))
  1216.             break;
  1217.       if (i >= SIZEOF(quantity_names)) {
  1218.            sderr(E_BADQUANTITY, tbuf + 1, (UNCH *)0);
  1219.            return FAIL;
  1220.       }
  1221.       if (sdparm(tbuf, 0) != NUM1) {
  1222.            sderr(E_XNUM, (UNCH *)0, (UNCH *)0);
  1223.            return FAIL;
  1224.       }
  1225.       n = atol((char *)tbuf);
  1226.       if (n < sd.quantity[i])
  1227.            sderr(E_QUANTITY, (UNCH *)quantity_names[i],
  1228.              ltous((long)sd.quantity[i]));
  1229.       else if (n > max_quantity[i]) {
  1230.            sderr(E_QTOOBIG, (UNCH *)quantity_names[i],
  1231.              ltous((long)max_quantity[i]));
  1232.            quantity[i] = max_quantity[i];
  1233.       }
  1234.       else
  1235.            quantity[i] = (int)n;
  1236.      }
  1237.      for (i = 0; i < NQUANTITY; i++)
  1238.       if (quantity[i] > 0) {
  1239.            sd.quantity[i] = quantity[i];
  1240.            if (!quantity_changed)
  1241.             quantity_changed = (char *)rmalloc(NQUANTITY);
  1242.            quantity_changed[i] = 1;
  1243.       }
  1244.      return SUCCESS;
  1245. }
  1246.  
  1247. /* Parse the FEATURES section.  Uses no lookahead. */
  1248.  
  1249. static int sdfeatures(tbuf)
  1250. UNCH *tbuf;
  1251. {
  1252.      static struct  {
  1253.       UNCH *name;
  1254.       UNCH argtype;  /* 0 = no argument, 1 = boolean, 2 = numeric */
  1255.       UNIV valp;     /* UNCH * if boolean, long * if numeric. */
  1256.      } features[] = {
  1257.       { kminimize, 0, 0 },
  1258.       { kdatatag, 1, 0 },
  1259.       { komittag, 1, (UNIV)&sd.omittag },
  1260.       { krank, 1, 0 },
  1261.       { kshorttag, 1, (UNIV)&sd.shorttag },
  1262.       { klink, 0, 0 },
  1263.       { ksimple, 2, 0 },
  1264.       { kimplicit, 1, 0 },
  1265.       { kexplicit, 2, 0 },
  1266.       { kother, 0, 0 },
  1267.       { kconcur, 2, 0 },
  1268.       { ksubdoc, 2, (UNIV)&sd.subdoc },
  1269.       { kformal, 1, (UNIV)&sd.formal },
  1270.      };
  1271.  
  1272.      int i;
  1273.  
  1274.      if (sdckname(tbuf, kfeatures) == FAIL)
  1275.       return FAIL;
  1276.      for (i = 0; i < SIZEOF(features); i++) {
  1277.       if (sdname(tbuf, features[i].name) == FAIL) return FAIL;
  1278.       if (features[i].argtype > 0) {
  1279.            long n;
  1280.            if (sdparm(tbuf, 0) != NAS1) {
  1281.             sderr(120, (UNCH *)0, (UNCH *)0);
  1282.             return FAIL;
  1283.            }
  1284.            if (matches(tbuf, kyes)) {
  1285.             if (features[i].argtype > 1) {
  1286.              if (sdparm(tbuf, 0) != NUM1) {
  1287.                   sderr(E_XNUM, (UNCH *)0, (UNCH *)0);
  1288.                   return FAIL;
  1289.              }
  1290.              n = atol((char *)tbuf);
  1291.              if (n == 0)
  1292.                   sderr(E_ZEROFEATURE, features[i].name, (UNCH *)0);
  1293.             }
  1294.             else
  1295.              n = 1;
  1296.            }
  1297.            else if (matches(tbuf, kno))
  1298.             n = 0;
  1299.            else {
  1300.             sderr(E_YESNO, tbuf+1, (UNCH *)0);
  1301.             return FAIL;
  1302.            }
  1303.            if (features[i].valp == 0) {
  1304.             if (n > 0)
  1305.              sderr(E_NOTSUPPORTED, features[i].name,
  1306.                   (UNCH *)0);
  1307.            }
  1308.            else if (features[i].argtype > 1)
  1309.             *(long *)features[i].valp = n;
  1310.            else
  1311.             *(UNCH *)features[i].valp = (UNCH)n;
  1312.       }
  1313.      }
  1314.      if (!sd.shorttag)
  1315.       noemptytag();
  1316.      return SUCCESS;
  1317. }
  1318.  
  1319. /* Parse the APPINFO section.  Uses no lookahead. */
  1320.  
  1321. static int sdappinfo(tbuf)
  1322. UNCH *tbuf;
  1323. {
  1324.      if (sdname(tbuf, kappinfo) == FAIL) return FAIL;
  1325.      switch (sdparm(tbuf, &pcblitv)) {
  1326.      case LIT1:
  1327.       appinfosw = 1;
  1328.       break;
  1329.      case NAS1:
  1330.       if (matches(tbuf, knone))
  1331.            break;
  1332.       sderr(118, tbuf+1, knone);
  1333.       return FAIL;
  1334.      default:
  1335.       sderr(E_XNMLIT, knone, (UNCH *)0);
  1336.       return FAIL;
  1337.      }
  1338.      return SUCCESS;
  1339. }
  1340.  
  1341. /* Change a prefix of ISO 8879-1986 to ISO 8879:1986.  Amendment 1 to
  1342. the standard requires the latter. */
  1343.  
  1344. static VOID sdfixstandard(tbuf, silently)
  1345. UNCH *tbuf;
  1346. int silently;
  1347. {
  1348.      if (strncmp((char *)tbuf, "ISO 8879-1986", 13) == 0) {
  1349.       if (!silently)
  1350.            sderr(E_STANDARD, (UNCH *)0, (UNCH *)0);
  1351.       tbuf[8] = ':';
  1352.      }
  1353. }
  1354.  
  1355. static int sdname(tbuf, key)
  1356. UNCH *tbuf;
  1357. UNCH *key;
  1358. {
  1359.      if (sdparm(tbuf, 0) != NAS1) {
  1360.       sderr(120, (UNCH *)0, (UNCH *)0);
  1361.       return FAIL;
  1362.      }
  1363.      if (!matches(tbuf, key)) {
  1364.       sderr(118, tbuf+1, key);
  1365.       return FAIL;
  1366.      }
  1367.      return SUCCESS;
  1368. }
  1369.  
  1370. static int sdckname(tbuf, key)
  1371. UNCH *tbuf;
  1372. UNCH *key;
  1373. {
  1374.      if (pcbsd.action != NAS1) {
  1375.       sderr(120, (UNCH *)0, (UNCH *)0);
  1376.       return FAIL;
  1377.      }
  1378.      if (!matches(tbuf, key)) {
  1379.       sderr(118, tbuf+1, key);
  1380.       return FAIL;
  1381.      }
  1382.      return SUCCESS;
  1383. }
  1384.  
  1385. /* Parse a SGML declaration parameter.  If lpcb is NULL, pt must be
  1386. REFNAMELEN+2 characters long, otherwise at least LITLEN+2 characters
  1387. long. LPCB should be NULL if a literal is not allowed. */
  1388.  
  1389. static int sdparm(pt, lpcb)
  1390. UNCH *pt;            /* Token buffer. */
  1391. struct parse *lpcb;        /* PCB for literal parse. */
  1392. {
  1393.      for (;;) {
  1394.       parse(&pcbsd);
  1395.       if (pcbsd.action != ISIG)
  1396.            break;
  1397.       sderr(E_SIGNIFICANT, (UNCH *)0, (UNCH *)0);
  1398.      }
  1399.      ++parmno;
  1400.      switch (pcbsd.action) {
  1401.      case LIT1:
  1402.       if (!lpcb) {
  1403.            sderr(E_BADLIT, (UNCH *)0, (UNCH *)0);
  1404.            REPEATCC;
  1405.            return (int)(pcbsd.action = INV_);
  1406.       }
  1407.       parselit(pt, lpcb, REFLITLEN, lex.d.lit);
  1408.       return (int)pcbsd.action;
  1409.      case LIT2:
  1410.       if (!lpcb) {
  1411.            sderr(E_BADLIT, (UNCH *)0, (UNCH *)0);
  1412.            REPEATCC;
  1413.            return (int)(pcbsd.action = INV_);
  1414.       }
  1415.       parselit(pt, lpcb, REFLITLEN, lex.d.lita);
  1416.       return (int)(pcbsd.action = LIT1);
  1417.      case NAS1:
  1418.       parsenm(pt, 1);
  1419.       return (int)pcbsd.action;
  1420.      case NUM1:
  1421.       parsetkn(pt, NU, REFNAMELEN);
  1422.       return (int)pcbsd.action;
  1423.      }
  1424.      return (int)pcbsd.action;
  1425. }
  1426.  
  1427. VOID sdinit()
  1428. {
  1429.      int i;
  1430.      /* Shunned character numbers in the reference concrete syntax. */
  1431.      static UNCH refshun[] = {
  1432.       0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
  1433.       19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 127, 255
  1434.       };
  1435.      UNCH **p;
  1436.      /* A character is magic if it is a non-SGML character used for
  1437.      some internal purpose in the parser. */
  1438.      char_flags[EOS] |= CHAR_MAGIC;
  1439.      char_flags[EOBCHAR] |= CHAR_MAGIC;
  1440.      char_flags[EOFCHAR] |= CHAR_MAGIC;
  1441.      char_flags[GENRECHAR] |= CHAR_MAGIC;
  1442.      char_flags[DELNONCH] |= CHAR_MAGIC;
  1443.      char_flags[DELCDATA] |= CHAR_MAGIC;
  1444.      char_flags[DELSDATA] |= CHAR_MAGIC;
  1445.  
  1446.      /* Figure out the significant SGML characters. */
  1447.      for (p = lextabs; *p; p++) {
  1448.       UNCH datclass = (*p)[CANON_DATACHAR];
  1449.       UNCH nonclass = (*p)[CANON_NONSGML];
  1450.       for (i = 0; i < 256; i++)
  1451.            if (!(char_flags[i] & CHAR_MAGIC)
  1452.            && (*p)[i] != datclass && (*p)[i] != nonclass)
  1453.             char_flags[i] |= CHAR_SIGNIFICANT;
  1454.      }
  1455.      for (i = 0; i < SIZEOF(refshun); i++)
  1456.       char_flags[refshun[i]] |= CHAR_SHUNNED;
  1457.      for (i = 0; i < 256; i++)
  1458.       if (ISASCII(i) && iscntrl(i))
  1459.            char_flags[i] |= CHAR_SHUNNED;
  1460.      bufsalloc();
  1461. }
  1462.  
  1463.  
  1464. static
  1465. VOID bufsalloc()
  1466. {
  1467.      scbs = (struct source *)rmalloc((REFENTLVL+1)*sizeof(struct source));
  1468.      tbuf = (UNCH *)rmalloc(REFATTSPLEN+REFLITLEN+1);
  1469.      /* entbuf is used for parsing numeric character references */
  1470.      entbuf = (UNCH *)rmalloc(REFNAMELEN + 2);
  1471. }
  1472.  
  1473. static
  1474. VOID bufsrealloc()
  1475. {
  1476.      UNS size;
  1477.  
  1478.      if (ENTLVL != REFENTLVL)
  1479.       scbs = (struct source *)rrealloc((UNIV)scbs,
  1480.                        (ENTLVL+1)*sizeof(struct source));
  1481.      /* Calculate the size for tbuf. */
  1482.      size = LITLEN + ATTSPLEN;
  1483.      if (PILEN > size)
  1484.       size = PILEN;
  1485.      if (BSEQLEN > size)
  1486.       size = BSEQLEN;
  1487.      if (size != REFATTSPLEN + REFLITLEN)
  1488.       tbuf = (UNCH *)rrealloc((UNIV)tbuf, size + 1);
  1489.      if (NAMELEN != REFNAMELEN)
  1490.       entbuf = (UNCH *)rrealloc((UNIV)entbuf, NAMELEN + 2);
  1491. }
  1492.  
  1493.  
  1494. /* Check that the non-SGML characters are compatible with the concrete
  1495. syntax and munge the lexical tables accordingly.  If IMPLIED is
  1496. non-zero, then the SGML declaration was implied; in this case, don't
  1497. give error messages about shunned characters not being declared
  1498. non-SGML.  Also make any changes that are required by the NAMING section.
  1499. */
  1500.  
  1501. static VOID setlexical()
  1502. {
  1503.      int i;
  1504.      UNCH **p;
  1505.  
  1506.      if (nlextoke) {
  1507.       /* Handle characters that were made significant by the
  1508.          NAMING section. */
  1509.       for (i = 0; i < 256; i++)
  1510.            if (nlextoke[i] == NMC || nlextoke[i] == NMS)
  1511.             char_flags[i] |= CHAR_SIGNIFICANT;
  1512.      }
  1513.  
  1514.      for (i = 0; i < 256; i++)
  1515.       if (char_flags[i] & CHAR_SIGNIFICANT) {
  1516.            /* Significant SGML characters musn't be non-SGML. */
  1517.            if (char_flags[i] & CHAR_NONSGML) {
  1518.             UNCH buf[2];
  1519.             buf[0] = i;
  1520.             buf[1] = '\0';
  1521.             sderr(E_NONSGML, buf, (UNCH *)0);
  1522.             char_flags[i] &= ~CHAR_NONSGML;
  1523.            }
  1524.       }
  1525.       else {
  1526.            /* Shunned characters that are not significant SGML characters
  1527.           must be non-SGML. */
  1528.            if ((char_flags[i] & (CHAR_SHUNNED | CHAR_NONSGML))
  1529.            == CHAR_SHUNNED) {
  1530.            sderr(E_SHUNNED, ltous((long)i), (UNCH *)0);
  1531.            char_flags[i] |= CHAR_NONSGML;
  1532.            }
  1533.       }
  1534.  
  1535.  
  1536.      /* Now munge the lexical tables. */
  1537.      for (p = lextabs; *p; p++) {
  1538.       UNCH nonclass = (*p)[CANON_NONSGML];
  1539.       UNCH datclass = (*p)[CANON_DATACHAR];
  1540.       UNCH nmcclass = (*p)[CANON_NMC];
  1541.       UNCH nmsclass = (*p)[CANON_NMS];
  1542.       UNCH minclass = (*p)[CANON_MIN];
  1543.       for (i = 0; i < 256; i++) {
  1544.            if (char_flags[i] & CHAR_NONSGML) {
  1545.             /* We already know that it's not significant. */
  1546.             if (!(char_flags[i] & CHAR_MAGIC))
  1547.              (*p)[i] = nonclass;
  1548.            }
  1549.            else {
  1550.             if (char_flags[i] & CHAR_MAGIC) {
  1551.              sderr(E_MUSTBENON, ltous((long)i), (UNCH *)0);
  1552.             }
  1553.             else if (!(char_flags[i] & CHAR_SIGNIFICANT))
  1554.              (*p)[i] = datclass;
  1555.             else if (*p == lexmin) {
  1556.              /* If it used to be NONSGML, but its now significant,
  1557.                 treat it like a datachar. */
  1558.              if ((*p)[i] == nonclass)
  1559.                   (*p)[i] = datclass;
  1560.             }
  1561.             else if (nlextoke
  1562.                  /* This relies on the fact that lextoke
  1563.                 occurs last in lextabs. */
  1564.                  && lextoke[i] != nlextoke[i]) {
  1565.              switch (nlextoke[i]) {
  1566.              case NMC:
  1567.                   (*p)[i] = nmcclass;
  1568.                   break;
  1569.              case NMS:
  1570.                   (*p)[i] = nmsclass;
  1571.                   break;
  1572.              case INV:
  1573.                   /* This will happen if period is not a
  1574.                  name character. */
  1575.                   (*p)[i] = minclass;
  1576.                   break;
  1577.              default:
  1578.                   abort();
  1579.              }
  1580.             }
  1581.            }
  1582.       }
  1583.      }
  1584.      if (nlextran) {
  1585.       memcpy((UNIV)lextran, (UNIV)nlextran, 256);
  1586.       frem((UNIV)nlextran);
  1587.      }
  1588.      if (nlextoke) {
  1589.       frem((UNIV)nlextoke);
  1590.       nlextoke = 0;
  1591.      }
  1592.  
  1593. }
  1594.  
  1595. /* Munge parse tables so that empty start and end tags are not recognized. */
  1596.  
  1597. static VOID noemptytag()
  1598. {
  1599.      static struct parse *pcbs[] = { &pcbconm, &pcbcone, &pcbconr, &pcbconc };
  1600.      int i;
  1601.  
  1602.      for (i = 0; i < SIZEOF(pcbs); i++) {
  1603.       int maxclass, maxstate;
  1604.       int j, k, act;
  1605.       UNCH *plex = pcbs[i]->plex;
  1606.       UNCH **ptab = pcbs[i]->ptab;
  1607.  
  1608.       /* Figure out the maximum lexical class. */
  1609.       maxclass = 0;
  1610.       for (j = 0; j < 256; j++)
  1611.            if (plex[j] > maxclass)
  1612.             maxclass = plex[j];
  1613.  
  1614.       /* Now figure out the maximum state number and at the same time
  1615.          change actions. */
  1616.  
  1617.       maxstate = 0;
  1618.  
  1619.       for (j = 0; j <= maxstate; j += 2) {
  1620.            for (k = 0; k <= maxclass; k++)
  1621.             if (ptab[j][k] > maxstate)
  1622.              maxstate = ptab[j][k];
  1623.            /* If the '>' class has an empty start or end tag action,
  1624.           change it to the action that the NMC class has. */
  1625.            act = ptab[j + 1][plex['>']];
  1626.            if (act == NET_ || act == NST_)
  1627.             ptab[j + 1][plex['>']] = ptab[j + 1][plex['_']];
  1628.       }
  1629.      }
  1630. }
  1631.  
  1632. /* Lookup the value of the entry in pmap PTR whose key is KEY. */
  1633.  
  1634. static UNIV pmaplookup(ptr, key)
  1635. struct pmap *ptr;
  1636. char *key;
  1637. {
  1638.      for (; ptr->name; ptr++)
  1639.       if (strcmp(key, ptr->name) == 0)
  1640.            return ptr->value;
  1641.      return 0;
  1642. }
  1643.  
  1644. /* Return an ASCII representation of N. */
  1645.  
  1646. static UNCH *ltous(n)
  1647. long n;
  1648. {
  1649.      static char buf[sizeof(long)*3 + 2];
  1650.      sprintf(buf, "%ld", n);
  1651.      return (UNCH *)buf;
  1652. }
  1653.  
  1654. VOID sgmlwrsd(fp)
  1655. FILE *fp;
  1656. {
  1657.      int i;
  1658.      int changed;
  1659.      char *p;
  1660.      char uc[256];        /* upper case characters (with different lower
  1661.                    case characters) */
  1662.      char lcletter[256];    /* LC letters: a-z */
  1663.  
  1664.      fprintf(fp, "<!SGML \"%s\"\n", standard);
  1665.      fprintf(fp,
  1666.          "CHARSET\nBASESET \"-//Dummy//CHARSET Dummy//%s\"\nDESCSET\n",
  1667.          SYSTEM_CHARSET_DESIGNATING_SEQUENCE);
  1668.  
  1669.      if (!done_nonsgml) {
  1670.       done_nonsgml = 1;
  1671.       for (i = 0; i < 256; i++)
  1672.            if ((char_flags[i] & (CHAR_SIGNIFICANT | CHAR_SHUNNED))
  1673.            == CHAR_SHUNNED)
  1674.                 char_flags[i] |= CHAR_NONSGML;
  1675.      }
  1676.      i = 0;
  1677.      while (i < 256) {
  1678.       int j;
  1679.       for (j = i + 1; j < 256; j++)
  1680.            if ((char_flags[j] & CHAR_NONSGML)
  1681.            != (char_flags[i] & CHAR_NONSGML))
  1682.             break;
  1683.       if (char_flags[i] & CHAR_NONSGML)
  1684.            fprintf(fp, "%d %d UNUSED\n", i, j - i);
  1685.       else
  1686.            fprintf(fp, "%d %d %d\n", i, j - i, i);
  1687.       i = j;
  1688.      }
  1689.      fprintf(fp, "CAPACITY\n");
  1690.      changed = 0;
  1691.      for (i = 0; i < NCAPACITY; i++)
  1692.       if (refcapset[i] != sd.capacity[i]) {
  1693.            if (!changed) {
  1694.             fprintf(fp, "SGMLREF\n");
  1695.             changed = 1;
  1696.            }
  1697.            fprintf(fp, "%s %ld\n", captab[i], sd.capacity[i]);
  1698.       }
  1699.      if (!changed)
  1700.       fprintf(fp, "PUBLIC \"%s\"\n", capset_map[0].name);
  1701.      fprintf(fp, "SCOPE DOCUMENT\n");
  1702.  
  1703.      fprintf(fp, "SYNTAX\nSHUNCHAR");
  1704.      for (i = 0; i < 256; i++)
  1705.       if (char_flags[i] & CHAR_SHUNNED)
  1706.            break;
  1707.      if (i == 256)
  1708.       fprintf(fp, " NONE\n");
  1709.      else {
  1710.       for (; i < 256; i++)
  1711.            if (char_flags[i] & CHAR_SHUNNED)
  1712.             fprintf(fp, " %d", i);
  1713.       fprintf(fp, "\n");
  1714.      }
  1715.  
  1716.      fprintf(fp,
  1717.          "BASESET \"-//Dummy//CHARSET Dummy//%s\"\nDESCSET 0 256 0\n",
  1718.          SYSTEM_CHARSET_DESIGNATING_SEQUENCE);
  1719.  
  1720.      fprintf(fp, "FUNCTION\nRE %d\nRS %d\nSPACE %d\nTAB SEPCHAR %d\n",
  1721.          RECHAR, RSCHAR, ' ', TABCHAR);
  1722.  
  1723.      MEMZERO((UNIV)uc, 256);
  1724.      for (i = 0; i < 256; i++)
  1725.       if (lextran[i] != i)
  1726.            uc[lextran[i]] = 1;
  1727.  
  1728.      MEMZERO((UNIV)lcletter, 256);
  1729.      for (p = "abcdefghijklmnopqrstuvwxyz"; *p; p++)
  1730.       lcletter[(unsigned char)*p]= 1;
  1731.  
  1732.      fprintf(fp, "NAMING\n");
  1733.      fputs("LCNMSTRT \"", fp);
  1734.      for (i = 0; i < 256; i++)
  1735.       if (lextoke[i] == NMS && !uc[i] && !lcletter[i])
  1736.            fprintf(fp, "&#%d;", i);
  1737.      fputs("\"\n", fp);
  1738.      fputs("UCNMSTRT \"", fp);
  1739.      for (i = 0; i < 256; i++)
  1740.       if (lextoke[i] == NMS && !uc[i] && !lcletter[i])
  1741.            fprintf(fp, "&#%d;", lextran[i]);
  1742.      fputs("\"\n", fp);
  1743.      fputs("LCNMCHAR \"", fp);
  1744.      for (i = 0; i < 256; i++)
  1745.       if (lextoke[i] == NMC && !uc[i])
  1746.            fprintf(fp, "&#%d;", i);
  1747.      fputs("\"\n", fp);
  1748.      fputs("UCNMCHAR \"", fp);
  1749.      for (i = 0; i < 256; i++)
  1750.       if (lextoke[i] == NMC && !uc[i])
  1751.            fprintf(fp, "&#%d;", lextran[i]);
  1752.      fputs("\"\n", fp);
  1753.  
  1754.      fprintf(fp, "NAMECASE\nGENERAL %s\nENTITY %s\n",
  1755.          sd.namecase[0] ? "YES" : "NO",
  1756.          sd.namecase[1] ? "YES" : "NO");
  1757.      fprintf(fp, "DELIM\nGENERAL SGMLREF\nSHORTREF %s\n",
  1758.          sd.shortref ? "SGMLREF" : "NONE");
  1759.      fprintf(fp, "NAMES SGMLREF\n");
  1760.      if (newkey) {
  1761.       /* The reference key was saved in newkey. */
  1762.       for (i = 0; i < NKEYS; i++)
  1763.            if (newkey[i][0])
  1764.             fprintf(fp, "%s %s\n", newkey[i], key[i]);
  1765.      }
  1766.      fprintf(fp, "QUANTITY SGMLREF\n");
  1767.      if (quantity_changed)
  1768.       for (i = 0; i < NQUANTITY; i++)
  1769.            if (quantity_changed[i])
  1770.             fprintf(fp, "%s %d\n", quantity_names[i], sd.quantity[i]);
  1771.      fprintf(fp,
  1772.          "FEATURES\nMINIMIZE\nDATATAG NO OMITTAG %s RANK NO SHORTTAG %s\n",
  1773.          sd.omittag ? "YES" : "NO",
  1774.          sd.shorttag ? "YES" : "NO");
  1775.      fprintf(fp, "LINK SIMPLE NO IMPLICIT NO EXPLICIT NO\n");
  1776.      fprintf(fp, "OTHER CONCUR NO ");
  1777.      if (sd.subdoc > 0)
  1778.       fprintf(fp, "SUBDOC YES %ld ", sd.subdoc);
  1779.      else
  1780.       fprintf(fp, "SUBDOC NO ");
  1781.      fprintf(fp, "FORMAL %s\n", sd.formal ? "YES" : "NO");
  1782.      fprintf(fp, "APPINFO NONE");
  1783.      fprintf(fp, ">\n");
  1784. }
  1785.  
  1786. /* Save an error to be printed only if FORMAL is declared as YES. */
  1787.  
  1788. static
  1789. VOID sdsaverr(number, parm1, parm2)
  1790. UNS number;
  1791. UNCH *parm1;
  1792. UNCH *parm2;
  1793. {
  1794.      saved_errs[nsaved_errs++] = savmderr(number, parm1, parm2);
  1795. }
  1796.  
  1797. /*
  1798. Local Variables:
  1799. c-indent-level: 5
  1800. c-continued-statement-offset: 5
  1801. c-brace-offset: -5
  1802. c-argdecl-indent: 0
  1803. c-label-offset: -5
  1804. End:
  1805. */
  1806.