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

  1. /******************************************************************************/
  2. /* Separated parseatt and adlval for use with LINK and data attributes.       */
  3. /* Changed to short external names; added #undef statements.                  */
  4. /******************************************************************************/
  5. #include "sgmlincl.h"         /* #INCLUDE statements for SGML parser. */
  6. /******************************************************************************/
  7. #define GI (tags[ts].tetd->etdgi+1)              /* GI of current element. */
  8. #define NEWGI (newetd->etdgi+1)                  /* GI of new tag. */
  9. /******************************************************************************/
  10. /* PARSECON: Parse content of an element.
  11. */
  12. int parsecon(
  13. UNCH *tbuf,                   /* Work area for tokenization. */
  14. UNCH *tbuflim,                /* First address after tbuf: for parseatt. */
  15. struct parse *pcb)            /* Parse control block for this parse. */
  16. {
  17.      int srn;                 /* SHORTREF delimiter number (1-32). */
  18.      int refrc;               /* Return code from sentref, stagetd, etc. */
  19.  
  20. #ifndef FINAL
  21.      if (gtrace) tracecon(etagimct, dostag, datarc, pcb, conrefsw, didreq);
  22. #endif
  23.      if (eodsw) return(EOD_);
  24.      if (didreq && (conrefsw & TAGREF)) {didreq = 0; goto conr;}
  25.      if (etagimct>0) {etagimsw = --etagimct ? 1 : 0; destack(); return(ETG_);}
  26.      if (dostag) {
  27.           conrefsw = conrefsv;
  28.           etisw = etiswsv;
  29.           if (charmode) {dostag = 0; return datarc;}
  30.           return stag(datarc);
  31.      }
  32.      if (conrefsw) {conr: conrefsw = 0; destack(); return ETG_;}
  33.      else if (eofsw) return(EOD_);
  34.  
  35.      datarc = 0;
  36. /*lint -e716*/
  37.      while (1) {
  38. /*lint +e716*/
  39.           parse(pcb);
  40.           srn = (int)pcb->action - SRMIN;  /* Just in case it's a SHORTREF. */
  41.           switch (pcb->action) {
  42.           case DCE_:          /* Data character in element content. */
  43.                data = FPOS;
  44.           dce2:pcb = conpcb = &pcbconm; pcb->newstate = pcbcnda;
  45.                continue;
  46.  
  47.           case DAS_:          /* Current character begins data. */
  48.                data = FPOS;
  49.                continue;
  50.  
  51.           case NLF_:          /* NET or SR returns data in lookahead buffer. */
  52.                datalen = (UNS)(ptcon - data); REPEATCC;
  53.                goto rcc;
  54.  
  55.           case LAF_:          /* Return data in lookahead buffer: mixed. */
  56.                datalen = (UNS)(ptcon+1 - data);
  57.                goto rcc;
  58.  
  59.           case NON_:          /* Single nonchar in nonchbuf. */
  60.                datalen = 2; data = nonchbuf;
  61.                goto nrcc;
  62.  
  63.           case DAR_:          /* Return data except for last char. */
  64.                REPEATCC;
  65.           case DAF_:          /* Return data in source entity buffer. */
  66.                datalen = (UNS)(FPOS - data);
  67.           rcc: REPEATCC;
  68.           case DEF_:          /* Return data in data entity. */
  69.           nrcc:datarc = DAF_;
  70.                if (pcb==&pcbcone) {
  71.                     pcbconm.newstate = pcbcnet;
  72.                     pcb = conpcb = &pcbconm;
  73.                }
  74.                if (charmode) return(datarc);
  75.                stagmin = MINNONE; stagreal = newetd = ETDCDATA;
  76.                return(stag(datarc));
  77.  
  78.           case LAS_:          /* Start lookahead buffer with current char. */
  79.                *(ptcon = data = tbuf+1) = *FPOS;
  80.                continue;
  81.  
  82.           case LAM_:          /* Move character to lookahead buffer. */
  83.                *++ptcon = *FPOS;
  84.                continue;
  85.  
  86.           case STG_:          /* Process non-null start-tag. */
  87.                CTRSET(tagctr);          /* Start counting tag length. */
  88.                parsenm(tbuf, NAMECASE); /* Get the GI. */
  89.                newetd = etdref(tbuf);
  90.                if (newetd && newetd->adl) {
  91.                     parseatt(newetd->adl, tbuf, tbuflim);
  92.                     adlval((int)ADN, newetd);
  93.                }
  94.                parsetag(&pcbstag);      /* Parse the tag ending. */
  95.                if ((CTRGET(tagctr)-tagdelsw)>=TAGLEN)
  96.                     sgmlerr(66, &pcbstag, NULL, NULL);
  97.                if (!newetd) {
  98.                     sgmlerr(132, pcb, tbuf+1, NULL);
  99.                     continue;
  100.                }
  101.                return(stagetd(&pcbstag));
  102.  
  103.           case NST_:          /* Process null start-tag. */
  104.                return nstetd();
  105.  
  106.           case ETC_:          /* End-tag in CDATA or RCDATA. */
  107.           case ETG_:          /* Process non-null end-tag. */
  108.                newetd = etdref(parsenm(tbuf, NAMECASE));  /* Get the GI. */
  109.                parsetag(&pcbetag);                        /* Parse tag end. */
  110.                if (!newetd)                               /* Error: undefined.*/
  111.                     sgmlerr(11, &pcbetag, tbuf+1, NULL);
  112.                else if (etagetd(&pcbetag)>=0) return ETG_;/* Open element. */
  113.                if (pcb->action!=ETC_) continue;
  114.                /* Tag is undefined or not for an open element and we are in
  115.                   a CDATA or RCDATA element; issue message and treat as
  116.                   null end-tag (</>).
  117.                */
  118.                sgmlerr(57, &pcbetag, NULL, NULL);
  119.           case NET_:          /* Process null end-tag. */
  120.                if ((refrc = netetd(conpcb))!=0) return ETG_;
  121.                continue;
  122.  
  123.           case NED_:          /* Process null end-tag delimiter. */
  124.                etagmin = MINNET;
  125.                newetd = etagreal = ETDNET;
  126.                etagimct = etag();
  127.                etagimsw = etagimct ? 1 : 0; destack();
  128.                return ETG_;
  129.  
  130.           case GTR_:          /* EOB with space pending: repeat after GET.*/
  131.             /* --CCNT;           Space lost if premature EOD -- so what! */
  132.                if (entget()>-1) {REPEATCC; continue;}  /* Restart sequence. */
  133.           case EOD_:          /* End of primary file. */
  134.                if (ts<1) return(EOD_);  /* Normal end: stack is empty. */
  135.                etagimct = ts-1;     /* Treat as end-tag for top tag on stack. */
  136.                etagmin = MINETAG; etagreal = tags[0].tetd;
  137.                destack();
  138.                eofsw = 1;          /* Return EOD_ after destacking all. */
  139.                return ETG_;
  140.  
  141.           /* Short references ending with blanks:
  142.                If the blank sequence is followed by RE, go do SR7 or SR6.
  143.                If the entity is undefined and we are in mixed content,
  144.                the blanks must be returned as data.  If not, they
  145.                can be ignored.
  146.           */
  147.           case SR9_:          /* Process SR9 (two or more blanks). */
  148.                REPEATCC;      /* Make first blank the CC. */
  149.           case SR4_:          /* Process SR4 (RS, blanks). */
  150.                parseseq(tbuf, BSEQLEN); /* Squeeze out all blanks. */
  151.                if (*FPOS=='\r') {srn = (srn==9) ? 7 : 6; data = tbuf; goto sr6;}
  152.                else REPEATCC;
  153.                if ((refrc = shortref(srn, pcb))==DEF_) goto nrcc;
  154.                if (refrc>0) return refrc;
  155.                if (refrc==ENTUNDEF && pcb==&pcbconm)
  156.                     {data = tbuf; goto nrcc;}
  157.                continue;
  158.  
  159.           /* Short references ending with RE:
  160.                If the reference is defined, the RE is ignored.
  161.                For RE and RS RE,
  162.                no special action is needed if the reference is undefined,
  163.                as the RE will be processed immediately as the current character.
  164.                For B RE and RS B RE,
  165.                the input is primed with a special character that will
  166.                be treated as an RE that cannot be a short reference.
  167.           */
  168.           case SR7_:          /* Process SR7 (blanks, RE). */
  169.                datalen = (UNS)(FPOS - data);
  170.           case SR2_:          /* Process SR2 (RE). */
  171.           case SR5_:          /* Process SR5 (RS, RE). */
  172.           sr6:                /* Process SR6 (RS, blanks, RE). */
  173.                if ((refrc = shortref(srn, pcb))!=ENTUNDEF) {
  174.                     if (refrc==DEF_) goto nrcc;   /* Defined: data entity. */
  175.                     if (refrc>0) return refrc;    /* Defined: tag entity. */
  176.                     continue;                     /* Defined: not tag. */
  177.                }
  178.                if (pcb!=&pcbconm) continue;       /* Not mixed; ignore chars. */
  179.                if (srn>=6)                        /* Return blanks as data. */
  180.                     {*FPOS = lex.d.genre; REPEATCC; goto nrcc;}
  181.           case REF_:          /* Undefined SR with RE; return record end. */
  182.                datarc = REF_;
  183.                if (charmode) return(datarc);
  184.                /* If RE would be ignored, don't treat it as start-tag
  185.                   because it could force a required tag; but do change
  186.                   state to show that an RE was ignored.
  187.                */
  188.                if (scbsgml[pss].snext==scbsgmst) {
  189.                     scbsgml[pss].snext = scbsgmnr;
  190. #ifndef FINAL
  191.                if (trace) tracegml(scbsgml, pss, conactsw, conact);
  192. #endif
  193.                     continue;
  194.                }
  195.                stagmin = MINNONE; stagreal = newetd = ETDCDATA;
  196.                return(stag(datarc));
  197.  
  198.           case SR3_:          /* Process SR3 (RS). */
  199.                REPEATCC;
  200.                if ((refrc = shortref(srn, pcb))==DEF_) goto nrcc;
  201.                if (refrc>0) return refrc;
  202.                continue;
  203.  
  204.           case SR1_:          /* Process SR1 (TAB). */
  205.           case SR8_:          /* Process SR8 (space). */
  206.           case SR19:          /* Process SR19 (-). */
  207.                REPEATCC;
  208.                goto srproc;
  209.  
  210.           case FCE_:          /* Process free character (SR11-18, SR21-32). */
  211.                fce[0] = *FPOS;
  212.                srn = mapsrch(&lex.s.dtb[lex.s.fce], fce);
  213.           case SR10:          /* Process SR10 ("). */
  214.           case SR11:          /* Process SR11 (#). */
  215.           case SR20:          /* Process SR20 (-). */
  216.           srproc:
  217.                if ((refrc = shortref(srn, pcb))==DEF_) goto nrcc;
  218.                if (refrc>0) return refrc;
  219.                if (refrc==ENTUNDEF) {             /* Treat the SR as data. */
  220.                     /*lint -e514                  /* Allow Boolean use. */
  221.                     data = FPOS - (srn==lex.s.hyp2);/* Two data chars if SR20.*/
  222.                     /*lint +e514                  /* Warn of Boolean use. */
  223.                     if (pcb!=&pcbconm) {          /* If not in mixed content: */
  224.                          if (srn>=lex.s.data) goto dce2;   /* Change PCB. */
  225.                     }
  226.                     else pcb->newstate = pcbcnda;/* Now in data found state. */
  227.                }
  228.                continue;
  229.  
  230.           case ERX_:          /* Entity ref in RCDATA: cancel ending delims.*/
  231.                lexcon[lex.d.tago] = lex.l.fre;
  232.                lexcon[lex.d.net] = lex.l.nonet;
  233.                lexlms[lex.d.msc] = lex.l.fre;
  234.                continue;
  235.  
  236.           case EE_:           /* Entity end in RCDATA: check nesting. */
  237.                if (es<rcessv) {synerr(37, pcb); rcessv = es;}
  238.                /* If back at top level, re-enable the ending delimiters. */
  239.                if (es==rcessv) {
  240.                     lexcon[lex.d.tago] = lex.l.tago;
  241.                     lexcon[lex.d.net] = etictr ? lex.l.net : lex.l.nonet;
  242.                     lexlms[lex.d.msc] = lex.l.msc;
  243.                }
  244.                continue;
  245.  
  246.           case PIE_:          /* PI entity: same as PIS_. */
  247.                return PIS_;
  248.  
  249.           case RSR_:               /* Record start: ccnt=0; ++rcnt.*/
  250.                ++RCNT; CTRSET(RSCC);
  251.           default:
  252.                return (int)pcb->action; /* Default (MD_ MDC_ MSS_ MSE_ PIS_). */
  253.           }
  254.      }
  255.      /*lint -unreachable*/
  256. }
  257. /******************************************************************************/
  258. /* STAGETD: Process start-tag etd.
  259. */
  260. int stagetd(
  261. struct parse *pcb)            /* Parse control block for this parse. */
  262. {
  263.      if (!newetd->etdmod) {
  264.           sgmlerr(43, pcb, newetd->etdgi+1, NULL);
  265.           ++ds.etdercnt;
  266.           etdset(newetd, (UNCH)SMO+EMO+ETDOCC, &undechdr,
  267.                 (PETD *)0, (PETD *)0, (PECB *)0);
  268. #ifndef FINAL
  269.           if (gtrace) traceetd(newetd);
  270. #endif
  271.      }
  272.      stagmin = MINNONE; stagreal = newetd;
  273.      return stag(0);
  274. }
  275. /******************************************************************************/
  276. /* NSTETD: Process null start-tag etd.
  277. */
  278. int nstetd(void)
  279. {
  280.      newetd = ts>0 ? tags[ts].tetd
  281.                    : tags[0].tetd->etdmod[2].tu.thetd;
  282.      stagmin = MINNULL; stagreal = ETDNULL;
  283.      etisw = 0;
  284.      return stag(0);
  285. }
  286. /******************************************************************************/
  287. /* ETAGETD: Process end-tag etd.
  288. */
  289. int etagetd(
  290. struct parse *pcb)            /* Parse control block for this parse. */
  291. {
  292.      etagmin = MINNONE; etagreal = newetd;
  293.      if ((etagimct = etag())<0) {
  294.           sgmlerr(_ETAG, pcb, NEWGI, tags[ts].tetd->etdgi+1);
  295.           return etagimct;
  296.      }
  297.      etagimsw = etagimct ? 1 : 0; destack();
  298.      return ETG_;
  299. }
  300. /******************************************************************************/
  301. /* NETETD: Process null end-tag etd.
  302. */
  303. int netetd(
  304. struct parse *pcb)            /* Parse control block for this parse. */
  305. {
  306.      if (ts<1) {
  307.           sgmlerr(51, pcb, NULL, NULL);
  308.           return 0;
  309.      }
  310.      etagmin = MINNULL; etagreal = ETDNULL;
  311.      etagimsw = 0; destack();
  312.      return ETG_;
  313. }
  314. /******************************************************************************/
  315. /* SHORTREF: Process a short (alternative) reference to an entity.
  316.              Returns ENTUNDEF if entity is not defined, otherwise returns
  317.              the return code from stagetd or etagetd if the entity was
  318.              a tag, or zero if an error occurred somewhere.
  319. */
  320. int shortref(
  321. int srn,                      /* Short reference number. */
  322. struct parse *pcb)            /* Parse control block for this parse. */
  323. {
  324.      int rc;                  /* Return code from entopen. */
  325.      int stagrc;              /* Return code from stagetd. */
  326.  
  327.      if (tags[ts].tsrm==SRMNULL || !tags[ts].tsrm[srn]) return ENTUNDEF;
  328.      if (!tags[ts].tsrm[srn]->estore) {
  329.           sgmlerr(93, pcb, tags[ts].tsrm[srn]->ename+1,
  330.                            tags[ts].tsrm[0]->ename+1);
  331.           return(ENTUNDEF);
  332.      }
  333.      if ( (rc = entopen(tags[ts].tsrm[srn]))==ENTSGI
  334.        && (stagrc = newetd==ETDNULL ? nstetd() : stagetd(pcb))>0 )
  335.           return stagrc;
  336.      if ( rc==ENTEGI
  337.        && (newetd==ETDNULL ? netetd(pcb)>0 : etagetd(pcb))>=0 )
  338.           return ETG_;
  339.      if (rc==ENTDATA) return DEF_;
  340.      if (rc==ENTPI) return PIS_;
  341.      return(0);
  342. }
  343. /******************************************************************************/
  344. /* PARSEPRO: Parse prolog.
  345.              Note: ptpro cannot overrun tbuf (and therefore needn't be
  346.              tested), as long as the buffer exceeds the longest
  347.              lookahead sequence in the content parse tables.
  348. */
  349. int parsepro(
  350. UNCH *tbuf)                   /* Work area for tokenization. */
  351. {
  352.      int rc;                  /* Return code: DAF MSS DCE */
  353.  
  354. /*lint -e716*/
  355.      while (1) {
  356. /*lint +e716*/
  357.           switch (parse(propcb)) {
  358.  
  359.           case LAS_:          /* Start lookahead buffer with current char. */
  360.                *(ptpro = data = tbuf+1) = *FPOS;
  361.                continue;
  362.           case LAM_:          /* Move character to lookahead buffer. */
  363.                *++ptpro = *FPOS;
  364.                continue;
  365.           case LAF_:          /* Return data in lookahead buffer. */
  366.                datalen = (UNS)(ptpro+1 - data);
  367.                REPEATCC;
  368.                rc = DAF_;
  369.                break;         /* Prolog ended; data pending. */
  370.  
  371.           case DTD_:          /* Process document type declaration. */
  372.                parsenm(tbuf, NAMECASE); /* Get declaration name. */
  373.                if (!strcmp(tbuf+1, syn.k.sgml) && !sgmlsw++)
  374.                     {parse(&pcbmdi); continue;}   /* Ignore for now. */
  375.                if (!strcmp(tbuf+1, syn.k.doctype) && !dtdsw++)
  376.                     {mddtds(tbuf); newdtdsw = 1; return(DTD_);}
  377.                sgmlerr(_MDNAME, propcb, tbuf+1, NULL);
  378.                continue;
  379.           case DTE_:          /* DOCTYPE declaration (and prolog) ended. */
  380.                REPEATCC;      /* Put back char that followed MSC. */
  381.                if (dtdrefsw) {/* Process referenced DTD before real DTE. */
  382.                     dtdrefsw = 0; /* Keep us from coming through here again. */
  383.                     REPEATCC; /* Put back MSC so it follows referenced DTD. */
  384.                     if (!pass) entref(indtdent);
  385.                }
  386.                else mddtde(tbuf);
  387.                continue;
  388.  
  389.           case MD_:           /* Process markup declaration within DTD. */
  390.                parsenm(tbuf, NAMECASE); /* Get declaration name. */
  391.                if (pass) parse(&pcbmdi);
  392.                else if (!strcmp(tbuf+1, syn.k.entitee))  mdentity(tbuf);
  393.                else if (!strcmp(tbuf+1, syn.k.usemap))   mdsrmuse(tbuf);
  394.                else if (!strcmp(tbuf+1, syn.k.attlist))  mdadl(tbuf);
  395.                else if (!strcmp(tbuf+1, syn.k.shortref)) mdsrmdef(tbuf);
  396.                else if (!strcmp(tbuf+1, syn.k.element))  mdelem(tbuf);
  397.                else if (!strcmp(tbuf+1, syn.k.notation)) mdnot(tbuf);
  398.                else sgmlerr(_MDNAME, propcb, tbuf+1, NULL);
  399.                continue;
  400.           case MDC_:          /* Process markup declaration comment. */
  401.                parsemd(tbuf, NAMECASE, (struct parse *)0, NAMELEN);
  402.                continue;
  403.  
  404.           case MSS_:               /* Process marked section start. */
  405.                propcb = mdms(tbuf, propcb);
  406.                if (propcb==&pcbmsc || propcb==&pcbmsrc)
  407.                     {conpcb = propcb; rc = MSS_; break;}
  408.                continue;
  409.           case MSE_:               /* Process marked section end. */
  410.                if (mdmse()) propcb = &pcbmds;
  411.                continue;
  412.  
  413.           case PIE_:          /* PI entity: same as PIS_. */
  414.                return(PIS_);
  415.  
  416.           case PIS_:          /* Return processing instruction (string). */
  417.           case EOD_:          /* Return end of primary entity. */
  418.                return((int)propcb->action);  /* Prolog will continue later. */
  419.  
  420.           case CIR_:          /* Chars ignored; trying to resume parse. */
  421.                synerr(_RESTART, propcb);
  422.                REPEATCC;
  423.                continue;
  424.  
  425.           case PEP_:          /* Previous character ended prolog. */
  426.                REPEATCC;
  427.           case DCE_:          /* Data character ended prolog. */
  428.                REPEATCC;
  429.                rc = DCE_;
  430.                break;
  431.  
  432.           } /* switch */
  433.           if (!pass) setdtype();   /* First pass only: set document type. */
  434. #ifndef FINAL
  435.           traceset();              /* Set trace switches per DOS environment. */
  436. #endif
  437.           /* *DOC is first element; stack it at level 0. */
  438.           stack(newetd = nextetd = stagreal = etagreal = docetd);
  439.           return(rc);
  440.      } /* while */
  441.      /*lint -unreachable*/
  442. }
  443. /******************************************************************************/
  444. /* SETDTYPE: Establish specified or default document type.
  445. */
  446. VOID setdtype(void)
  447. {
  448.      /* Initialize default model hdr for declared content. */
  449.      undechdr.ttype = MANY+MCHARS+MGI;  /* Declared content is ANY. */
  450.      undechdr.tu.tnum = 0;              /* No content model. */
  451.  
  452.      /* Initialize content model and etd for *DOC. */
  453.      prcon[0].ttype = MGI;    /* Model is an element model. */
  454.      prcon[0].tu.tnum = 2;    /* A single group with a single GI in it. */
  455.      prcon[1].ttype = TTSEQ;  /* Non-repeatable SEQ group. */
  456.      prcon[1].tu.tnum = 1;    /* Only one token in group. */
  457.      prcon[2].ttype = TTETD;  /* Token is an etd. */
  458.      docetd = etddef(indocetd);  /* etd for document as a whole. */
  459.      etdset(docetd, ETDOCC, prcon, (PETD *)0, (PETD *)0, SRMNULL);
  460.  
  461.      /* Put specified or default document type etd in *DOC model. */
  462.      if (!*dtype) {
  463.           sgmlerr(_DOCTYPE, propcb, NULL, NULL);
  464.           memcpy( dtype , indefetd,10  );
  465.      }
  466.      prcon[2].tu.thetd = etddef(dtype);
  467.      if (!prcon[2].tu.thetd->etdmod) {
  468.           sgmlerr(52, propcb, dtype+1, NULL);
  469.           ++ds.etdercnt;
  470.           etdset(prcon[2].tu.thetd, (UNCH)SMO+EMO+ETDUSED+ETDOCC, &undechdr,
  471.                 (PETD *)0, (PETD *)0, (PECB *)0);
  472.      }
  473. #ifndef FINAL
  474.      if (gtrace) {
  475.           traceetd(docetd); tracemod(prcon);
  476.           traceetd(prcon[2].tu.thetd);
  477.      }
  478. #endif
  479.      return;
  480. }
  481. /******************************************************************************/
  482. #define RCEND    1            /* No more tokens: end element and retry GI. */
  483. #define RCREQ    2            /* Required GI must precede proposed GI. */
  484. #define RCMISS   3            /* GI invalid: not element end; no required GI. */
  485. #define RCHIT    4            /* GI is the one expected next. */
  486. #define RCMEX    5            /* GI invalid: minus exception. */
  487. #define RCHITMEX 6            /* RCHIT with invalid attempted minus exception.*/
  488. #define RCPEX    7            /* GI is valid solely because of plus exception.*/
  489. /******************************************************************************/
  490. /* PARSETAG: Tag end parser for SGML documents.
  491.              For start-tags, it
  492.              sets etisw to TAGNET if tag ended with ETI; otherwise to 0.
  493. */
  494. VOID parsetag(
  495. struct parse *pcb)            /* Parse control block: pcbstag or pcbetag. */
  496. {
  497.      tagdelsw = 1;            /* Assume tag had an ETI or TAGC. */
  498.      switch (parse(pcb)) {
  499.      case ETIC:               /* Tag closed with ETI. */
  500.           etisw = TAGNET;     /* Set switch for stack entry flag. */
  501.           return;
  502.  
  503.      case NVS:                /* Att name or value token found. */
  504.      case NTV:                /* Name token value found. */
  505.           synerr(_POSSATT, pcb);
  506.           pcb->newstate = 0;  /* Reset parse state. */
  507.      case TAGO:               /* Tag closing implied by TAGO. */
  508.           REPEATCC;           /* Put it back for next read. */
  509.           tagdelsw = 0;       /* Tag had no closing delimiter. */
  510.      case TAGC:               /* Normal close. */
  511.      default:                 /* Invalid character (msg was sent). */
  512.           etisw = 0;          /* Don't flag stack entry. */
  513.           return;
  514.      }
  515. }
  516. /******************************************************************************/
  517. /* STAG: Check whether a start-tag is valid at this point in the document
  518.          structure, or whether other tags must precede it.
  519.          Special case processing is done for the fake tag, #CDATA, as
  520.          it is never stacked.
  521. */
  522. int stag(
  523. int dataret)                  /* Data pending: DAF_ REF_ 0=not #PCDATA. */
  524. {
  525.      int rc, realrc;          /* Return code from context or other test. */
  526.      int mexts = 0;           /* >0=stack level of minus grp; -1=plus; 0=none.*/
  527.  
  528.      badresw = pexsw = 0;
  529.      /* If real element (i.e., not #PCDATA) set mexts and test if empty. */
  530.      if (dataret==0) {
  531.           mexts = pexmex(newetd);
  532.           /* If element is declared empty, it is same as a conref. */
  533.           if (GET(newetd->etdmod->ttype, MNONE)) conrefsw = TAGREF;
  534.      }
  535.      if (GET(tags[ts].tetd->etdmod->ttype, MANY))
  536.           rc = mexts>0 ? RCMEX : RCHIT;
  537.      else rc = context(newetd, tags[ts].tetd->etdmod, tags[ts].tpos,
  538.                        &tags[ts].status, mexts);
  539. #ifndef FINAL
  540.      if (gtrace) tracestg(newetd, dataret, rc, nextetd, mexts);
  541. #endif
  542.  
  543.      switch (rc) {
  544.      case RCEND:         /* End current element, then retry start-tag. */
  545.           if (ts<1) realrc = RCMISS;
  546.           else      realrc = RCEND;
  547.           break;
  548.      case RCREQ:         /* Stack compulsory GI, then retry start-tag. */
  549.           realrc = RCREQ;
  550.           break;
  551.      case RCMISS:        /* Start-tag invalid (#PCDATA or real). */
  552.           if (ts>0 && GET(tags[ts].tetd->etdmod->ttype, MANY))
  553.                realrc = RCEND;
  554.           else realrc = RCMISS;
  555.           break;
  556.      case RCMEX:         /* Start-tag invalid (minus exception). */
  557.           etagimct = ts - mexts;
  558.           realrc = RCEND;
  559.           break;
  560.      case RCHITMEX:      /* Invalid minus exclusion for required element. */
  561.           sgmlerr(_MEXERR, &pcbstag, NEWGI, tags[mexts].tetd->etdgi+1);
  562.      case RCHIT:         /* Start-tag was valid. */
  563.           realrc = RCHIT;
  564.           break;
  565.      case RCPEX:         /* Start-tag valid only because of plus exception. */
  566.           pexsw = TAGPEX;
  567.           realrc = RCHIT;
  568.           break;
  569.      }
  570.  
  571.      switch (realrc) {
  572.      case RCEND:         /* End current element, then retry start-tag. */
  573.           if (didreq) sgmlerr(07, &pcbstag, nextetd->etdgi+1, NULL);
  574.           didreq = 0;                   /* No required start-tag done. */
  575.           dostag = 1; etiswsv = etisw;  /* Save real start-tag status. */
  576.           conrefsv = conrefsw;          /* Save real start-tag conref. */
  577.           conrefsw = 0;                 /* Current element is not empty. */
  578.           etagmin = MINSTAG; destack(); /* Process omitted end-tag. */
  579.           return ETG_;
  580.      case RCREQ:         /* Stack compulsory GI, then retry start-tag. */
  581.           if (nextetd>=MINPTR) {
  582.                if ((mexts = pexmex(nextetd))>0) sgmlerr(_MEXERR, &pcbstag,
  583.                     nextetd->etdgi+1, tags[mexts].tetd->etdgi+1);
  584.                if (!nextetd->etdmod) {
  585.                     sgmlerr(53, &pcbstag, nextetd->etdgi+1, NULL);
  586.                     etdset(nextetd, (UNCH)SMO+EMO+ETDOCC, &undechdr,
  587.                           (PETD *)0, (PETD *)0, (PECB *)0);
  588.                     ++ds.etdercnt;
  589. #ifndef FINAL
  590.                     if (gtrace) traceetd(nextetd);
  591. #endif
  592.                }
  593.           }
  594.           if (BITOFF(nextetd->etdmin, SMO)) {
  595.                if (stagreal>=MINPTR)
  596.                     sgmlerr(21, &pcbstag, nextetd->etdgi+1, stagreal->etdgi+1);
  597.                else if (stagreal==ETDCDATA)
  598.                     sgmlerr(49, &pcbstag, nextetd->etdgi+1, NULL);
  599.                else sgmlerr(50, &pcbstag, nextetd->etdgi+1, NULL);
  600.           }
  601.           didreq = 1;                   /* Required start-tag done. */
  602.           dostag = 1; etiswsv = etisw;  /* Save real start-tag status. */
  603.           etisw = 0; conrefsv = conrefsw;  /* Save real start-tag conref. */
  604.           /* If element is declared empty, it is same as a conref. */
  605.           conrefsw = (GET(nextetd->etdmod->ttype, MNONE)) ? TAGREF : 0;
  606.           stack(nextetd);               /* Process omitted start-tag. */
  607.           return STG_;
  608.      case RCMISS:        /* Start-tag invalid (#PCDATA or actual). */
  609.           dostag = 0; contersw |= 1; didreq = 0;
  610.           if (dataret) {
  611.                if (dataret==REF_) badresw = 1;
  612.                else sgmlerr(_CHARS, conpcb, tags[ts].tetd->etdgi+1, NULL);
  613.                return dataret;
  614.           }
  615.           sgmlerr(_CONTEXT, &pcbstag, NEWGI, tags[ts].tetd->etdgi+1);
  616.           if (stagmin!=MINNULL) stagmin = MINNONE; stack(newetd);
  617.           return STG_;
  618.      case RCHIT:         /* Start-tag was valid. */
  619.           dostag = 0; didreq = 0;
  620.           if (dataret) return dataret;
  621.           stack(newetd);
  622.           return STG_;
  623.      }
  624.      /*lint -unreachable*/
  625.      return NOP_;        /* To avoid Borland C++ warning */
  626. }
  627. /******************************************************************************/
  628. /* PEXMEX: See if a GI is in a plus or minus exception group on the stack.
  629.            If in a minus, returns stack level of minus group; otherwise,
  630.            returns -1 if in a plus and not a minus, and zero if in neither.
  631. */
  632. int pexmex(curetd)
  633. struct etd *curetd;           /* The etd for this GI. */
  634. {
  635.      int tsl;                 /* Temporary stack level for looping. */
  636.      int pex = 0;             /* 1=found in plus grp; 0=not. */
  637.  
  638.      for (tsl = ts; tsl>0; --tsl) {
  639.           if (tags[tsl].tetd->etdmex && ingrp(tags[tsl].tetd->etdmex, curetd))
  640.                return(tsl);
  641.           if (tags[tsl].tetd->etdpex && ingrp(tags[tsl].tetd->etdpex, curetd))
  642.                pex = -1;
  643.      }
  644.      return(pex);
  645. }
  646. /******************************************************************************/
  647. /* STACK: Add a new entry to the tag stack.
  648.           If there is no room, issue a message and reuse last position.
  649. */
  650. VOID stack(
  651. struct etd *curetd)           /* The etd for this entry. */
  652. {
  653.      /* Stack the new element type definition (error if no room). */
  654.      if (++ts>TAGLVL)
  655.           sgmlerr(_STAGMAX, conpcb, curetd->etdgi+1, tags[--ts].tetd->etdgi+1);
  656.      tags[ts].tetd = curetd;
  657.  
  658.      /* Set flags: plus exception + tag had ETI + context error + empty. */
  659.      tags[ts].tflags = (char)pexsw + etisw + contersw + conrefsw; contersw = 0;
  660.  
  661.      /* If tag had ETI, update ETI counter and enable NET if first ETI. */
  662.      if (etisw && ++etictr==1) lexcon[lex.d.net] = lexcnm[lex.d.net] = lex.l.net;
  663.  
  664.      /* If etd has ALT table, use it; otherwise, use last element's ALT. */
  665.      tags[ts].tsrm = curetd->etdsrm ? curetd->etdsrm : tags[ts-1].tsrm;
  666.  
  667.      /* Initialize rest of stack entry. */
  668.      tags[ts].status = 0;
  669.      tags[ts].tpos[0].g = 1;       /* M: Index in model of next token to test.*/
  670.      tags[ts].tpos[0].t = 1;       /* P: Index in tpos of current group. */
  671.      tags[ts].tpos[0].h = 0;       /* 1=first group itself was hit; 0=not yet. */
  672.      tags[ts].tpos[1].g = 1;       /* Index of group in model (dummy grp). */
  673.      tags[ts].tpos[1].t = 1;       /* 1st token is next in grp to be tested. */
  674.      tags[ts].tpos[1].h = 0;       /* No hits as yet. */
  675. #ifndef FINAL
  676.      if (gtrace) tracestk(&tags[ts], ts, etictr);
  677. #endif
  678.      return;
  679. }
  680. /******************************************************************************/
  681. /* ETAG: Check validity of an end-tag by seeing if it matches any tag
  682.          on the stack.  If so, return the offset of the match from the
  683.          current entry (0=current).  If there is no match, issue a message
  684.          and return an error code (-1).
  685.          If the newetd is ETDNET, a NET delimiter was found, so check for
  686.          a tag that ended with ETI instead of a matching GI.
  687. */
  688. int etag(void)
  689. {
  690.      int tsl = ts+1;          /* Temporary stack level for looping. */
  691.  
  692.      /* See if end-tag is anywhere on stack, starting at current entry. */
  693.      while (--tsl) {
  694.           if (newetd!=ETDNET ? newetd==tags[tsl].tetd : tags[tsl].tflags) {
  695. #ifndef FINAL
  696.                if (gtrace) traceetg(&tags[ts], newetd, tsl, ts-tsl);
  697. #endif
  698.                return(ts-tsl);
  699.           }
  700.      }
  701.      return (-1);             /* End-tag didn't match any start-tag. */
  702. }
  703. /******************************************************************************/
  704. /* DESTACK:
  705.             Call ECONTEXT to see if element can be ended at this point.
  706.             and issue message if there are required tags left.
  707.             Remove the current entry from the tag stack.
  708.             Issue an error if the destacked element was not minimizable
  709.             and its end-tag was omitted.
  710. */
  711. VOID destack(void)
  712. {
  713.      register int ecode = 0;  /* Error code (0=o.k.). */
  714.      UNCH *eparm2 = NULL;     /* Second parameter of error message. */
  715.      register int minmsgsw;   /* 1=message if tag omitted; 0=no message. */
  716.  
  717.      /* If element has a content model (i.e., not a keyword) and there
  718.         are required tags left, issue an error message.
  719.      */
  720.      if ( !GET(tags[ts].tetd->etdmod->ttype, MKEYWORD)
  721.        && !econtext(tags[ts].tetd->etdmod, tags[ts].tpos, &tags[ts].status)) {
  722.           if (nextetd<MINPTR)
  723.                sgmlerr(54, conpcb, tags[ts].tetd->etdgi+1, NULL);
  724.           else sgmlerr(30, conpcb, tags[ts].tetd->etdgi+1, nextetd->etdgi+1);
  725.      }
  726.      /* If the current tag ended with ETI, decrement the etictr.
  727.         If etictr is now zero, disable the NET delimiter.
  728.      */
  729.      if (GET(tags[ts--].tflags, TAGNET) && --etictr==0)
  730.           lexcon[lex.d.net] = lexcnm[lex.d.net] = lex.l.nonet;
  731.  
  732.      minmsgsw = BITOFF(tags[ts+1].tetd->etdmin, EMO);
  733.      if (minmsgsw && (etagimsw || etagmin==MINETAG)) {
  734.           /* Minimization caused by NET delimiter. */
  735.           if (etagreal<MINPTR) ecode = 46;
  736.           /* Minimization caused by a containing end-tag. */
  737.           else {ecode = 20; eparm2 = etagreal->etdgi+1;}
  738.      }
  739.      else if (etagmin==MINSTAG && (minmsgsw || ts<=0)) {
  740.           /* Minimization caused by out-of-context start-tag. */
  741.           if (stagreal>=MINPTR) {
  742.                ecode = ts>0 ? 39 : 89;
  743.                eparm2 = stagreal->etdgi+1;
  744.           }
  745.           /* Minimization caused by out-of-context data. */
  746.           else if (stagreal==ETDCDATA) ecode = ts>0 ? 47 : 95;
  747.           /* Minimization caused by out-of-context short start-tag. */
  748.           else ecode = ts>0 ? 48 : 96;
  749.           if (ts<=0 && ecode) eodsw = 1;
  750.      }
  751.      if (ecode) sgmlerr((UNS)ecode, conpcb, tags[ts+1].tetd->etdgi+1, eparm2);
  752.      /* TEMP: See if parser bug caused stack to go below zero. */
  753.      else if (ts<0) {sgmlerr(64, conpcb, NULL, NULL); ts = 0;}
  754. #ifndef FINAL
  755.      if (gtrace) tracedsk(&tags[ts], &tags[ts+1], ts, etictr);
  756. #endif
  757. }
  758. /******************************************************************************/
  759. #undef GI
  760. #undef NEWGI
  761. #undef RCEND
  762. #undef RCREQ
  763. #undef RCMISS
  764. #undef RCHIT
  765. #undef RCMEX
  766. #undef RCHITMEX
  767. #undef RCPEX
  768. /******************************************************************************/
  769.