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