home *** CD-ROM | disk | FTP | other *** search
/ Resource Library: Multimedia / Resource Library: Multimedia.iso / sgml / unix / sgmlc / modmd1.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-07-03  |  28.2 KB  |  768 lines

  1. /******************************************************************************/
  2. /* MDENTITY & MDEXTID: Support N/C/SDATA entities with attributes. */
  3. /* Changed free() to frem() to move memory allocation to TP environment. */
  4. /* Some minor LINT fixes. */
  5. /******************************************************************************/
  6. #include "sgmlincl.h"         /* #INCLUDE statements for SGML parser. */
  7. /******************************************************************************/
  8. /* MDADL: Process ATTLIST declaration.
  9. */
  10. VOID mdadl(
  11. UNCH *tbuf)                   /* Work area for tokenization (tbuf). */
  12. {
  13.      struct etd *nmgrp[GRPCNT+1];   /* Array of etds being defined. */
  14.      int i;                   /* Loop counter; temporary variable. */
  15.      int adlim;               /* Number of unused ad slots in al. */
  16.      struct ad *alperm = 0;   /* Attribute definition list. */
  17.  
  18.      mdname = syn.k.attlist;  /* Identify declaration for messages. */
  19.      subdcl = 0;              /* No subject as yet. */
  20.      parmno = 0;              /* No parameters as yet. */
  21.      mdessv = es;             /* Save es level for entity nesting check. */
  22.      reqadn = noteadn = 0;    /* No required attributes yet. */
  23.      idadn = conradn = 0;     /* No special atts yet.*/
  24.      AN = 0;                  /* Number of attributes defined. */
  25.      ADN = 0;                 /* Number of ad's in al (atts + name vals).*/
  26.      /* PARAMETER 1: Element name or a group of them.
  27.      */
  28.      parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
  29. #ifndef FINAL
  30.      if (dtrace) tracemd("1: element name or group");
  31. #endif
  32.      switch (pcbmd.action) {
  33.      case NAS:
  34.           nmgrp[0] = etddef(tbuf);
  35.           nmgrp[1] = 0;
  36.           break;
  37.      case GRPS:
  38.           parsegrp(nmgrp, &pcbgrnm);
  39.           break;
  40.      case RNS:           /* Reserved name started. */
  41.           if (strcmp(tbuf+1, syn.k.notation)) {
  42.                mderr(118, tbuf+1, syn.k.notation);
  43.                return;
  44.           }
  45.           mdnadl(tbuf);
  46.           return;
  47.      default:
  48.           mderr(121, NULL, NULL);
  49.           return;
  50.      }
  51.      subdcl = nmgrp[0]->etdgi+1;        /* Save first GI for error msgs. */
  52.      /* PARAMETER 2: Attribute definition list.
  53.      */
  54.      parsemd((STRING)al[ADN+1].adname, NAMECASE, &pcblitp, NAMELEN);
  55. #ifndef FINAL
  56.      if (dtrace) tracemd("2: attribute list");
  57. #endif
  58.      if (pcbmd.action!=NAS) {
  59.           mderr(120, NULL, NULL);
  60.           return;
  61.      }
  62.      while (pcbmd.action==NAS) {
  63.           if ((adlim = ATTCNT-((int)ADN++))<0) {mderr(111, NULL, NULL); return;}
  64.           ++AN;
  65.           if (mdattdef(adlim)) return;
  66.           parsemd((STRING)al[ADN+1].adname, NAMECASE, &pcblitp, NAMELEN);
  67.      }
  68.      if (AN>0) {   /*  Save list only if 1 or more good atts. */
  69.           if (reqadn)  SET(ADLF, ADLREQ);    /* Element must have start-tag. */
  70.           if (noteadn) SET(ADLF, ADLNOTE);   /* Element cannot be EMPTY. */
  71.           if (conradn) SET(ADLF, ADLCONR);   /* Element cannot be EMPTY. */
  72.           alperm = (struct ad *)rmalloc((1+ADN)*ADSZ);
  73.           memcpy((UNIV)alperm, (UNIV)al, (1+ADN)*ADSZ );
  74.           ds.attcnt += AN;         /* Number of attributes defined. */
  75.           ds.attgcnt += ADN - AN;  /* Number of att grp members. */
  76. #ifndef FINAL
  77.           if (atrace) traceadl(alperm);
  78. #endif
  79.      }
  80.      /* Clear attribute list for next declaration. */
  81.      memset((UNIV)al, '\0', (1+ADN)*ADSZ);
  82.  
  83.      /* PARAMETER 3: End of declaration.
  84.      */
  85.      /* Next pcb.action was set during attribute definition loop. */
  86. #ifndef FINAL
  87.      if (dtrace) tracemd(emd);
  88. #endif
  89.      if (pcbmd.action!=EMD) {mderr(126, NULL, NULL); return;}
  90.      if (es!=mdessv) synerr(37, &pcbmd);
  91.  
  92.      /* EXECUTE: Store the definition for each element name specified.
  93.      */
  94. #ifndef FINAL
  95.      if (gtrace) tracegrp(nmgrp);
  96. #endif
  97.      for (i = -1; nmgrp[++i];) {
  98.           if (nmgrp[i]->adl) {     /* Error if an ADL exists. */
  99.                mderr(112, NULL, NULL);
  100.                continue;
  101.           }
  102.           nmgrp[i]->adl = alperm;  /* If virgin, store the adl ptr. */
  103.           etdadl(nmgrp[i]);        /* Check for conflicts with ETD. */
  104.      }
  105. }
  106. /******************************************************************************/
  107. /* ETDADL: Check compatibility between ETD and ADL.
  108. */
  109. void etdadl(
  110. struct etd *p)                /* Pointer to element type definition. */
  111. {
  112.      parmno = 0;
  113.      /* Minimizable element cannot have required attribute. */
  114.      if (GET(p->etdmin, SMO) && GET(p->adl[0].adflags, ADLREQ)) {
  115.           mderr(40, NULL, NULL);
  116.           RESET(p->etdmin, SMO);
  117.      }
  118.      /* Empty element cannot have NOTATION attribute.
  119.         Attribute is not removed (too much trouble), but we trap
  120.         attempts to specify it on the start-tag in PARSEATT.C.
  121.      */
  122.      if (p->etdmod && GET(p->etdmod->ttype, MNONE)) {
  123.           if (GET(p->adl[0].adflags, ADLNOTE))
  124.                mderr(83, NULL, NULL);
  125.  
  126.           /* Empty element cannot have CONREF attribute.
  127.              Attribute is not removed because it just acts
  128.              like IMPLIED anyway.
  129.           */
  130.           if (GET(p->adl[0].adflags, ADLCONR))
  131.                mderr(85, NULL, NULL);
  132.      }
  133. }
  134. /******************************************************************************/
  135. /* MDNADL: Process ATTLIST declaration for notation.
  136.            TO DO: Pass deftab and dvtab as parameters so
  137.            that prohibited types can be handled by leaving
  138.            them out of the tables.
  139. */
  140. VOID mdnadl(
  141. UNCH *tbuf)                   /* Work area for tokenization (tbuf). */
  142. {
  143.      PDCB nmgrp[GRPCNT+1];    /* Array of dcncb's being defined. */
  144.      int i;                   /* Loop counter; temporary variable. */
  145.      int adlim;               /* Number of unused ad slots in al. */
  146.      struct ad *alperm = 0;   /* Attribute definition list. */
  147.  
  148.      /* PARAMETER 1: Notation name or a group of them.
  149.      */
  150.      parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
  151. #ifndef FINAL
  152.      if (dtrace) tracemd("1: notation name or group");
  153. #endif
  154.      switch (pcbmd.action) {
  155.      case NAS:
  156.           nmgrp[0] = dcndef(tbuf);
  157.           nmgrp[1] = 0;
  158.           break;
  159.      case GRPS:
  160.           parsngrp(nmgrp, &pcbgrnm);
  161.           break;
  162.      default:
  163.           mderr(121, NULL, NULL);
  164.           return;
  165.      }
  166.      subdcl = nmgrp[0]->ename+1;        /* Save first name for error msgs. */
  167.      /* PARAMETER 2: Attribute definition list.
  168.      */
  169.      parsemd((STRING)al[ADN+1].adname, NAMECASE, &pcblitp, NAMELEN);
  170. #ifndef FINAL
  171.      if (dtrace) tracemd("2: attribute list");
  172. #endif
  173.      if (pcbmd.action!=NAS) {
  174.           mderr(120, NULL, NULL);
  175.           return;
  176.      }
  177.      while (pcbmd.action==NAS) {
  178.           if ((adlim = ATTCNT-((int)ADN++))<0) {mderr(111, NULL, NULL); return;}
  179.           ++AN;
  180.           if (mdattdef(adlim)) return;
  181.           parsemd((STRING)al[ADN+1].adname, NAMECASE, &pcblitp, NAMELEN);
  182.      }
  183.      if (AN>0) {   /*  Save list only if 1 or more good atts. */
  184.           alperm = (struct ad *)rmalloc((1+ADN)*ADSZ);
  185.           memcpy((UNIV)alperm, (UNIV)al, (1+ADN)*ADSZ );
  186.           ds.attcnt += AN;         /* Number of attributes defined. */
  187.           ds.attgcnt += ADN - AN;  /* Number of att grp members. */
  188. #ifndef FINAL
  189.           if (atrace) traceadl(alperm);
  190. #endif
  191.      }
  192.      /* Clear attribute list for next declaration. */
  193.      memset((UNIV)al, '\0', (1+ADN)*ADSZ);
  194.  
  195.      /* PARAMETER 3: End of declaration.
  196.      */
  197.      /* Next pcb.action was set during attribute definition loop. */
  198. #ifndef FINAL
  199.      if (dtrace) tracemd(emd);
  200. #endif
  201.      if (pcbmd.action!=EMD) {mderr(126, NULL, NULL); return;}
  202.      if (es!=mdessv) synerr(37, &pcbmd);
  203.  
  204.      /* EXECUTE: Store the definition for each notation name specified.
  205.      */
  206. #ifndef FINAL
  207.      if (gtrace) tracengr(nmgrp);
  208. #endif
  209.      for (i = -1; nmgrp[++i];) {
  210.           if (nmgrp[i]->adl) {     /* Error if an ADL exists. */
  211.                mderr(112, NULL, NULL);
  212.                continue;
  213.           }
  214.           nmgrp[i]->adl = alperm;  /* If virgin, store the adl ptr. */
  215. #ifndef FINAL
  216.           if (ntrace) tracedcn(nmgrp[i]);
  217. #endif
  218.      }
  219. }
  220. /******************************************************************************/
  221. /* MDATTDEF: Process an individual attribute definition.
  222.              The attribute name is parsed by the caller.
  223.              Duplicate attributes are parsed, but removed from list.
  224.              Returns 0 if successful, otherwise returns 1.
  225. */
  226. int mdattdef(
  227. int adlim)                    /* Remaining capacity of al (in tokens).*/
  228. {
  229.      int deftype;             /* Default value type: 0=not keyword. */
  230.      int errsw = 0;           /* 1=semantic error; ignore att. */
  231.      int novalsw = 0;         /* 1=semantic error; treat as IMPLIED. */
  232.      int attadn = (int)ADN;   /* Save ad number of this attribute. */
  233.      struct parse *grppcb;    /* PCB for name/token grp parse. */
  234.      int errcode;             /* Error type returned by PARSEVAL, ANMTGRP. */
  235.      UNCH *advalsv;           /* Save area for permanent value ptr. */
  236.  
  237.      /* PARAMETER 1: Attribute name (parsed by caller).
  238.      */
  239. #ifndef FINAL
  240.      if (dtrace) tracemd("1: attribute name");
  241. #endif
  242.      if (anmget((int)ADN-1, al[attadn].adname)) {
  243.           errsw = 1;
  244.           mderr(99, ADNAME(attadn), NULL);
  245.      }
  246.      ADNUM(attadn) = ADFLAGS(attadn) = ADLEN(attadn) = 0;
  247.      ADVAL(attadn) = 0; ADDATA(attadn).x = 0; ADTYPE(attadn) = ANMTGRP;
  248.      /* PARAMETER 2: Declared value.
  249.      */
  250.      parsemd(lbuf, NAMECASE, &pcblitp, NAMELEN);
  251. #ifndef FINAL
  252.      if (dtrace) tracemd("2: declared value");
  253. #endif
  254.      switch (pcbmd.action) {
  255.      case NAS:                /* Keyword for value type. */
  256.           switch (ADTYPE(attadn) = (char)mapsrch(dvtab, lbuf+1)) {
  257.           case 0:
  258.                mderr(100, ADNAME(attadn), lbuf+1);
  259.                return 1;
  260.           case ANOTEGRP:
  261.                if (!noteadn) noteadn = ADN;
  262.                else {
  263.                     errsw = 1;
  264.                     mderr(101, ADNAME(attadn), NULL);
  265.                }
  266.                grppcb = &pcbgrnm;         /* NOTATION requires name grp. */
  267.                parsemd(lbuf, NAMECASE, &pcblitp, NAMELEN);/* Get GRPO*/
  268.                break;
  269.           case AID:
  270.                if (!idadn) idadn = attadn;
  271.                else {
  272.                     errsw = 1;
  273.                     mderr(102, ADNAME(attadn), NULL);
  274.                }
  275.                break;
  276.           }
  277.           break;
  278.      case GRPS:
  279.           grppcb = &pcbgrnt;           /* Normal grp is name token grp. */
  280.           break;
  281.      case EMD:
  282.           mderr(103, ADNAME(attadn), NULL);
  283.           return 1;
  284.      default:
  285.           mderr(104, ADNAME(attadn), NULL);
  286.           return 1;
  287.      }
  288.      /* PARAMETER 2A: Name token group.
  289.      */
  290.      if (pcbmd.action==GRPS || ADTYPE(attadn)==ANOTEGRP) {
  291. #ifndef FINAL
  292.      if (dtrace) tracemd("2A: name group");
  293. #endif
  294.           switch (pcbmd.action) {
  295.           case GRPS:               /* Name token list. */
  296.                SET(ADFLAGS(attadn), AGROUP);
  297.                /* Call routine to parse group, create ad entries in adl. */
  298.                errcode = anmtgrp(grppcb, al+attadn,
  299.                     (GRPCNT<adlim ? GRPCNT+1 : adlim+1),
  300.                     &al[attadn].adnum, (int)ADN);
  301.                if (errcode<=0) {
  302.                     mderr(105, ADNAME(attadn), NULL);
  303.                     return 1;
  304.                }
  305.                ADN += ADNUM(attadn);    /* Add grp size to total ad cnt.*/
  306.                break;
  307.           default:
  308.                mderr(106, ADNAME(attadn), NULL);
  309.                return 1;
  310.           }
  311.      }
  312.      /* PARAMETER 3: Default value keyword.
  313.      */
  314.      parsemd(lbuf, AVALCASE, &pcblitr, LITLEN);
  315. #ifndef FINAL
  316.      if (dtrace) tracemd("3: default keyword");
  317. #endif
  318.      switch (pcbmd.action) {
  319.      case RNS:                /* Keyword. */
  320.           deftype = mapsrch(deftab, lbuf+1);
  321.           switch (deftype) {
  322.           case DFIXED:        /* FIXED */
  323.                SET(ADFLAGS(attadn), AFIXED);
  324.                parsemd(lbuf, AVALCASE, &pcblitr, LITLEN);  /* Real default. */
  325.                goto parm3x;   /* Go process specified value. */
  326.           case DCURR:         /* CURRENT: If ID, treat as IMPLIED. */
  327.                if (ADTYPE(attadn)==AID) {
  328.                     mderr(80, ADNAME(attadn), NULL);
  329.                     break;
  330.                }
  331.                SET(ADFLAGS(attadn), ACURRENT);
  332.                break;
  333.           case DREQ:          /* REQUIRED */
  334.                SET(ADFLAGS(attadn), AREQ); ++reqadn;
  335.                break;
  336.           case DCONR:         /* CONREF */
  337.                if (ADTYPE(attadn)==AID) {
  338.                     mderr(107, ADNAME(attadn), NULL);
  339.                     break;
  340.                }
  341.                SET(ADFLAGS(attadn), ACONREF); conradn = 1;
  342.           case DNULL:         /* IMPLIED */
  343.                break;
  344.           default:            /* Unknown keyword is an error. */
  345.                mderr(108, ADNAME(attadn), lbuf+1);
  346.                errsw = 1;
  347.           }
  348.           if (errsw) {--AN; ADN = (char)attadn-1;} /* Ignore erroneous att. */
  349.           return(0);
  350.      default:
  351.           break;
  352.      }
  353.      /* PARAMETER 3x: Default value (non-keyword).
  354.      */
  355.      parm3x:
  356. #ifndef FINAL
  357.      if (dtrace) tracemd("3x: default (non-keyword)");
  358. #endif
  359. /*   if (ADTYPE(attadn)==AID) {    ** If ID, treat as IMPLIED. **
  360.           mderr(81, ADNAME(attadn), NULL);
  361.           novalsw = 1;             ** Keep parsing to keep things straight. **
  362.      } */
  363.      switch (pcbmd.action) {
  364.      case LIT:                /* Literal. */
  365.      case LITE:               /* Literal. */
  366.           /* Null string (except CDATA) is error: msg and treat as IMPLIED. */
  367.           if (*lbuf<=2 && ADTYPE(attadn)!=ACHARS) {
  368.                mderr(82, ADNAME(attadn), NULL);
  369.                novalsw = 1;
  370.           }
  371.      case NAS:                /* Name character string. */
  372.      case NMT:                /* Name character string. */
  373.      case NUM:                /* Number or number token string. */
  374.           break;
  375.      case EMD:
  376.           mderr(109, ADNAME(attadn), NULL);
  377.           return 1;
  378.      default:
  379.           mderr(110, ADNAME(attadn), NULL);
  380.           return 1;
  381.      }
  382.      if (errsw) {
  383.           --AN; ADN = (char)attadn-1;    /* Ignore erroneous att. */
  384.           return(0);
  385.      }
  386.      if (novalsw) return(0);
  387.  
  388.      /* PARAMETER 3y: Validate and store default value.
  389.      */
  390.      if (ADTYPE(attadn)==ACHARS) {
  391.           /* No more checking for CDATA value. */
  392.           ADNUM(attadn) = 0;             /* CDATA is 0 tokens. */
  393.           ADVAL(attadn) = strlsave(lbuf);/* Store default; save ptr. */
  394.           ds.attdef += (ADLEN(attadn) = *lbuf);/* Length for capacity count.*/
  395.           return 0;
  396.      }
  397.      /* Parse value and save token count (GROUP implies 1 token). */
  398.      advalsv = rmalloc(*lbuf+1);   /* Storage for tokenized value. */
  399.      errcode = parseval(lbuf, (UNS)ADTYPE(attadn), advalsv);
  400.      if (BITOFF(ADFLAGS(attadn), AGROUP)) ADNUM(attadn) = (char)tokencnt;
  401.  
  402.      /* If value was invalid, or was a group member that was not in the group,
  403.         issue an appropriate message and set the error switch. */
  404.      if (errcode)
  405.           {sgmlerr((UNS)errcode, &pcbmd, ADNAME(attadn), lbuf+1); errsw = 1;}
  406.      else if ( BITON(ADFLAGS(attadn), AGROUP)
  407.           && !amemget(&al[attadn], (int)ADNUM(attadn), pvalptr) ) {
  408.                sgmlerr(79, &pcbmd, ADNAME(attadn), pvalptr+1);
  409.                errsw = 1;
  410.      }
  411.      /* For valid tokenized value, save it and update statistics. */
  412.      if (!errsw) {
  413.           ds.attdef += (ADLEN(attadn) = (char)vallen(ADTYPE(attadn)>=ATKNLIST,
  414.                (int)ADNUM(attadn), (ADVAL(attadn) = pvalptr)));
  415.           return 0;
  416.      }
  417.      /* If value was bad, free the value's storage and treat as
  418.         IMPLIED or REQUIRED. */
  419.      frem((UNIV)advalsv);          /* Release storage for value. */
  420.      ADVAL(attadn) = NULL;         /* And make value NULL. */
  421.      return 0;
  422. }
  423. /******************************************************************************/
  424. /* ANMTGRP: Parse a name or name token group, create attribute descriptors
  425.             for its members, and add them to the attribute descriptor list.
  426.             The parse either terminates or returns a good token, so no
  427.             switch is needed.
  428. */
  429. int anmtgrp(
  430. struct parse *pcb,            /* PCB for name or name token grp. */
  431. struct ad nt[],               /* Buffer for creating name token list. */
  432. int grplim,                   /* Maximum size of list (plus 1). */
  433. UNCH *adn,                    /* Ptr to number of names or tokens in grp. */
  434. int adsz)                     /* Size of att def list. */
  435. {
  436.      UNCH adtype = (char)(pcb==&pcbgrnt ? ANMTGRP:ANOTEGRP);/*Attribute type.*/
  437.      int essv = es;           /* Entity stack level when grp started. */
  438.  
  439.      *adn = 0;                /* Group is empty to start. */
  440.      while (parse(pcb)!=GRPE && (int)*adn<grplim) {
  441.           switch (pcb->action) {
  442.           case NAS_:          /* Name or name token (depending on pcb). */
  443.           case NMT_:
  444.                parsenm(nt[*adn+1].adname, NAMECASE);
  445.                if (antvget((int)(adsz+*adn), nt[*adn+1].adname))
  446.                     mderr(98, ntoa((int)*adn+1), nt[*adn+1].adname+1);
  447.                nt[++*adn].adtype = adtype;
  448.                nt[*adn].addef    = NULL;
  449.                continue;
  450.  
  451.           case EE_:           /* Entity ended (correctly or incorrectly). */
  452.                if (es<essv) {synerr(37, pcb); essv = es;}
  453.                continue;
  454.  
  455.           case PIE_:          /* PI entity reference (invalid). */
  456.                entpisw = 0;   /* Reset PI entity indicator. */
  457.                synerr(59, pcb);
  458.                continue;
  459.  
  460.           default:
  461.                break;
  462.           }
  463.           break;
  464.      }
  465.      if (es!=essv) synerr(37, pcb);
  466.      if ((int)*adn==grplim) return -1;
  467.      else return (int)*adn;        /* Return number of tokens. */
  468. }
  469. /******************************************************************************/
  470. /* MDDTDS: Process start of DOCTYPE declaration (through MSO).
  471. */
  472. VOID mddtds(
  473. UNCH *tbuf)                   /* Work area for tokenization[LITLEN+2]. */
  474. {
  475.      struct fpi fpicb;        /* Formal public identifier structure. */
  476.      union etext etx;         /* Ptr to entity text. */
  477.      UNCH estore = ESD;       /* Entity storage class. */
  478.      int emdsw = 0;           /* 1=end of declaration found; 0=not yet. */
  479.  
  480.      mdname = syn.k.doctype;  /* Identify declaration for messages. */
  481.      subdcl = NULL;           /* No subject as yet. */
  482.      parmno = 0;              /* No parameters as yet. */
  483.      mdessv = es;             /* Save es for checking entity nesting. */
  484.      dtdrefsw = 0;            /* No external DTD entity as yet. */
  485.      /* PARAMETER 1: Document type name.
  486.      */
  487.      pcbmd.newstate = 0;
  488.      parsemd(dtype, NAMECASE, &pcblitp, NAMELEN);
  489. #ifndef FINAL
  490.      if (dtrace) tracemd("1: doc type name");
  491. #endif
  492.      if (pcbmd.action!=NAS) {mderr(120, NULL, NULL); return;}
  493.      subdcl = dtype+1;        /* Subject of declaration for error msgs. */
  494.  
  495.      /* PARAMETER 2: External identifier keyword or MDS.
  496.      */
  497.      pcbmd.newstate = 0;
  498.      parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
  499. #ifndef FINAL
  500.      if (dtrace) tracemd("2: extid or MDS");
  501. #endif
  502.      switch (pcbmd.action) {
  503.      case NAS:
  504.           if (mdextid(tbuf, &fpicb, dtype, &estore, (PNE)0)==0) return;
  505.           if ((etx.x = entgen(&fpicb))==0) return;
  506.           dtdrefsw = 1;            /* Signal external DTD entity. */
  507.           break;
  508.      case MDS:
  509.           goto execute;
  510.      default:
  511.           mderr(128, NULL, NULL);
  512.           return;
  513.      }
  514.      /* PARAMETER 3: MDS or end of declaration.
  515.      */
  516. #ifndef FINAL
  517.      if (dtrace) tracemd("3: MDS or EMD");
  518. #endif
  519.      switch (pcbmd.action) {
  520.      default:                      /* Treat as end of declaration. */
  521.           mderr(126, NULL, NULL);
  522.      case EMD:
  523.           emdsw = 1;
  524.      case MDS:
  525.           break;
  526.      }
  527.      /* EXECUTE: Store entity definition if an external ID was specified.
  528.      */
  529.      execute:
  530.      if (es!=mdessv) synerr(37, &pcbmd);
  531.      propcb = &pcbmds;        /* Prepare to parse doc type definition (MDS). */
  532.      if (dtdrefsw) {
  533.           if (!pass) {        /* Store entity on first pass only. */
  534.                /* TO DO: If concurrent DTD's supported, free existing
  535.                          etext for all but first DTD (or reuse it). */
  536.                entdef(indtdent, estore, &etx);
  537.                ++ds.ecbcnt; ds.ecbtext += entlen;
  538.           }
  539.           if (emdsw) {
  540.                REPEATCC;                /* Push back the MDC. */
  541.                *FPOS = lex.d.msc;       /* Simulate end of DTD subset. */
  542.                REPEATCC;                /* Back up to read MSC next. */
  543.                delmscsw = 1;            /* Insert MSC after referenced DTD. */
  544.           }
  545.      }
  546.      indtdsw = 1;                       /* Allow "DTD only" parameters. */
  547.      return;
  548. }
  549. /******************************************************************************/
  550. /* MDDTDE: Process DOCTYPE declaration end.
  551. */
  552. VOID mddtde(
  553. UNCH *tbuf)                   /* Work area for tokenization. */
  554. {
  555.      mdessv = es;             /* Save es for checking entity nesting. */
  556.      propcb = &pcbpro;        /* Restore normal prolog parse. */
  557.      indtdsw = 0;             /* Prohibit "DTD only" parameters. */
  558.  
  559.      mdname = syn.k.doctype;  /* Identify declaration for messages. */
  560.      subdcl = dtype+1;        /* Subject of declaration for error msgs. */
  561.      parmno = 0;              /* No parameters as yet. */
  562.      /* PARAMETER 4: End of declaration.
  563.      */
  564.      pcbmd.newstate = 0;
  565.      parsemd(tbuf, NAMECASE, &pcblitp, LITLEN);
  566. #ifndef FINAL
  567.      if (dtrace) tracemd(emd);
  568. #endif
  569.      if (pcbmd.action!=EMD) mderr(126, NULL, NULL);
  570.      if (es!=mdessv) synerr(37, &pcbmd);
  571. }
  572. /******************************************************************************/
  573. /* MDELEM: Process ELEMENT declaration.
  574. */
  575. VOID mdelem(
  576. UNCH *tbuf)                   /* Work area for tokenization (tbuf). */
  577. {
  578.      UNCH ranksuff[NAMELEN+2];/* Rank suffix. */
  579.      UNCH comgibuf[NAMELEN+2];/* Buffer for complete GI (stem + rank suffix). */
  580.      struct etd *nmgrp[GRPCNT+1];   /* Array of etds being defined. */
  581.      UNS dctype = 0;          /* Declared content type (from dctab). */
  582.      UNCH fmin = 0;           /* Minimization bit flags. */
  583.      int i;                   /* Loop counter. */
  584.      UNS u;                   /* Temporary variable. */
  585.      struct etd **mexgrp, **pexgrp; /* Ptr to model exceptions array. */
  586.      struct thdr *cmod, *cmodsv;    /* Ptr to content model. */
  587.      UNCH *etdgi;             /* GI of current etd (when going through group).*/
  588.  
  589.      mdname = syn.k.element;  /* Identify declaration for messages. */
  590.      subdcl = NULL;           /* No subject as yet. */
  591.      parmno = 0;              /* No parameters as yet. */
  592.      mdessv = es;             /* Save es level for entity nesting check. */
  593.      ranksuff[0] = 0;
  594.      mexgrp = pexgrp = 0;
  595.      /* PARAMETER 1: Element name or a group of them.
  596.      */
  597.      parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
  598. #ifndef FINAL
  599.      if (dtrace) tracemd("1: element name or grp");
  600. #endif
  601.      switch (pcbmd.action) {
  602.      case NAS:
  603.           nmgrp[0] = etddef(tbuf);
  604.           nmgrp[1] = 0;
  605.           break;
  606.      case GRPS:
  607.           parsegrp(nmgrp, &pcbgrnm);
  608.           break;
  609.      default:
  610.           mderr(121, NULL, NULL);
  611.           return;
  612.      }
  613.      /* Save first GI for trace and error messages. */
  614.      subdcl = nmgrp[0]->etdgi+1;
  615.  
  616.      /* PARAMETER 1A: Rank suffix (optional).
  617.      */
  618.      parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
  619. #ifndef FINAL
  620.      if (dtrace) tracemd("1A: rank suffix");
  621. #endif
  622.      switch (pcbmd.action) {
  623.      case NUM:
  624.           memcpy(ranksuff  , tbuf, *tbuf );
  625.           parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
  626.      default:
  627.           break;
  628.      }
  629.      /* PARAMETER 2A: Start-tag minimization.
  630.      */
  631. #ifndef FINAL
  632.      if (dtrace) tracemd("2A: start min");
  633. #endif
  634.      switch (pcbmd.action) {
  635.      case NAS:
  636.           if (*tbuf!=3 || *(tbuf+1)!='O') {mderr(129, tbuf+1, NULL); return;}
  637.           SET(fmin, SMO);
  638.      case CDR:
  639.           break;
  640.      default:
  641.           mderr(129, tbuf+1, NULL);
  642.           return;
  643.      }
  644.      /* PARAMETER 2B: End-tag minimization.
  645.      */
  646.      parsemd(tbuf, NAMECASE, &pcblitp, 1);
  647. #ifndef FINAL
  648.      if (dtrace) tracemd("2B: end min");
  649. #endif
  650.      switch (pcbmd.action) {
  651.      case NAS:
  652.           if (*(tbuf+1)!='O') {mderr(129, tbuf+1, NULL); return;}
  653.           SET(fmin, EMO);
  654.      case CDR:
  655.           break;
  656.      default:
  657.           mderr(129, tbuf+1, NULL);
  658.           return;
  659.      }
  660.      /* PARAMETER 3: Declared content.
  661.      */
  662.      parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
  663. #ifndef FINAL
  664.      if (dtrace) tracemd("3: declared content");
  665. #endif
  666.      switch (pcbmd.action) {
  667.      case NAS:
  668.           dctype = mapsrch(dctab, tbuf+1);
  669.           if (!dctype) {mderr(24, tbuf+1, NULL); return;}
  670.           /* Eliminate incompatibilities among parameters. */
  671.           if (GET(fmin, SMO) && GET(dctype, MNONE+MCDATA+MRCDATA)) {
  672.                mderr(58, NULL, NULL);
  673.                RESET(fmin, SMO);
  674.           }
  675.           if (GET(dctype, MNONE) && BITOFF(fmin, EMO)) {
  676.                mderr(87, NULL, NULL);
  677.                SET(fmin, EMO);
  678.           }
  679.           /* If valid, process like a content model. */
  680.      case GRPS:
  681.           cmodsv = parsemod((int)(pcbmd.action==GRPS ? 0 : dctype));
  682.           if (cmodsv==0) return;
  683.           cmod = (struct thdr *)rmalloc(u = (cmodsv->tu.tnum+1) * THSZ);
  684.           memcpy((UNIV)cmod  , (UNIV)cmodsv, u );
  685.           ds.modcnt += cmod->tu.tnum;
  686. #ifndef FINAL
  687.           if (gtrace) tracemod(cmod);
  688. #endif
  689.           break;
  690.      default:
  691.           mderr(130, NULL, NULL);
  692.           return;
  693.      }
  694.      /* PARAMETERS 3A, 3B: Exceptions or end.
  695.      */
  696.      parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
  697.      if (BITOFF(cmod->ttype, MCDATA+MRCDATA+MNONE)) {
  698.           /* PARAMETER 3A: Minus exceptions.
  699.           */
  700. #ifndef FINAL
  701.           if (dtrace) tracemd("3A: -grp");
  702. #endif
  703.           switch (pcbmd.action) {
  704.           case MGRP:
  705.                mexgrp = copygrp((PETD *)tbuf,
  706.                     u = parsegrp((PETD *)tbuf, &pcbgrnm));
  707.                ++ds.pmexgcnt; ds.pmexcnt += u-1;
  708. #ifndef FINAL
  709.                if (gtrace) tracegrp(mexgrp);
  710. #endif
  711.                parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
  712.           default:
  713.                break;
  714.           }
  715.           /* PARAMETER 3B: Plus exceptions.
  716.           */
  717. #ifndef FINAL
  718.           if (dtrace) tracemd("3B: +grp");
  719. #endif
  720.           switch (pcbmd.action) {
  721.           case PGRP:
  722.                pexgrp = copygrp((PETD *)tbuf,
  723.                     u = parsegrp((PETD *)tbuf, &pcbgrnm));
  724.                ++ds.pmexgcnt; ds.pmexcnt += u-1;
  725. #ifndef FINAL
  726.                if (gtrace) tracegrp(pexgrp);
  727. #endif
  728.                parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
  729.           default:
  730.                break;
  731.           }
  732.      }
  733.      /* PARAMETER 4: End of declaration.
  734.      */
  735. #ifndef FINAL
  736.      if (dtrace) tracemd(emd);
  737. #endif
  738.      if (pcbmd.action!=EMD) mderr(126, NULL, NULL);
  739.      if (es!=mdessv) synerr(37, &pcbmd);
  740.  
  741.      /* EXECUTE: Store the definition for each element name specified.
  742.      */
  743. #ifndef FINAL
  744.      if (gtrace) tracegrp(nmgrp);
  745. #endif
  746.      for (i = -1; nmgrp[++i];) {
  747.           etdgi = nmgrp[i]->etdgi;
  748.           if (*ranksuff) {
  749.                if ((comgibuf[0] = *etdgi + ranksuff[0]-2)>NAMELEN) {
  750.                     mderr(131, etdgi+1, ranksuff+1);
  751.                     continue;
  752.                }
  753.                memcpy(comgibuf+1, etdgi+1, *etdgi-1);
  754.                memcpy(comgibuf+*etdgi-1  , ranksuff+1, *ranksuff-1 );
  755.                etdcan(etdgi);
  756.                nmgrp[i] = etddef(comgibuf);
  757.           }
  758.           if (nmgrp[i]->etdmod) {mderr(56, etdgi+1, NULL); continue;}
  759.           etdset(nmgrp[i], fmin+ETDDCL, cmod, mexgrp, pexgrp, nmgrp[i]->etdsrm);
  760.           ++ds.etdcnt;
  761.           if (nmgrp[i]->adl) etdadl(nmgrp[i]); /* Check ETD conflicts. */
  762. #ifndef FINAL
  763.           if (gtrace) traceetd(nmgrp[i]);
  764. #endif
  765.      }
  766. }
  767. /******************************************************************************/
  768.