home *** CD-ROM | disk | FTP | other *** search
/ Otherware / Otherware_1_SB_Development.iso / mac / misc / compsci / arcsgm.cpt / ARC SGML 1.0 / sgmlc / modmd1.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-12-17  |  27.8 KB  |  771 lines

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