2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these librararies and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
23 /* $XConsortium: md1.c /main/3 1996/06/19 17:16:08 drk $ */
24 #include "sgmlincl.h" /* #INCLUDE statements for SGML parser. */
25 /* MDADL: Process ATTLIST declaration.
28 UNCH *tbuf; /* Work area for tokenization (tbuf). */
30 int i; /* Loop counter; temporary variable. */
31 int adlim; /* Number of unused ad slots in al. */
32 struct ad *alperm = 0; /* Attribute definition list. */
35 mdname = key[KATTLIST]; /* Identify declaration for messages. */
36 subdcl = 0; /* No subject as yet. */
37 parmno = 0; /* No parameters as yet. */
38 mdessv = es; /* Save es level for entity nesting check. */
39 reqadn = noteadn = 0; /* No required attributes yet. */
40 idadn = conradn = 0; /* No special atts yet.*/
41 AN(al) = 0; /* Number of attributes defined. */
42 ADN(al) = 0; /* Number of ad's in al (atts + name vals).*/
43 /* PARAMETER 1: Element name or a group of them.
45 parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
46 TRACEMD("1: element name or group");
47 switch (pcbmd.action) {
49 nmgrp[0] = etddef(tbuf);
53 parsegrp(nmgrp, &pcbgrnm, tbuf);
55 case RNS: /* Reserved name started. */
56 if (ustrcmp(tbuf+1, key[KNOTATION])) {
57 mderr(118, tbuf+1, key[KNOTATION]);
63 mderr(121, (UNCH *)0, (UNCH *)0);
66 /* Save first GI for error msgs. */
68 subdcl = nmgrp[0]->etdgi+1;
69 /* PARAMETER 2: Attribute definition list.
71 parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
72 TRACEMD("2: attribute list");
73 if (pcbmd.action!=NAS) {
74 mderr(120, (UNCH *)0, (UNCH *)0);
77 while (pcbmd.action==NAS) {
78 al[ADN(al)+1].adname = savenm(tbuf);
79 if ((adlim = ATTCNT-((int)++ADN(al)))<0) {
80 mderr(111, (UNCH *)0, (UNCH *)0);
85 if (mdattdef(adlim, 0)) {
89 parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
91 if (AN(al)>0) { /* Save list only if 1 or more good atts. */
92 if (reqadn) SET(ADLF(al), ADLREQ); /* Element must have start-tag. */
93 if (noteadn) SET(ADLF(al), ADLNOTE); /* Element cannot be EMPTY. */
94 if (conradn) SET(ADLF(al), ADLCONR); /* Element cannot be EMPTY. */
95 alperm = (struct ad *)rmalloc((1+ADN(al))*ADSZ);
96 memcpy((UNIV)alperm, (UNIV)al, (1+ADN(al))*ADSZ );
97 ds.attcnt += AN(al); /* Number of attributes defined. */
98 ds.attgcnt += ADN(al) - AN(al); /* Number of att grp members. */
101 /* Clear attribute list for next declaration. */
102 MEMZERO((UNIV)al, (1+ADN(al))*ADSZ);
104 /* PARAMETER 3: End of declaration.
106 /* Next pcb.action was set during attribute definition loop. */
108 if (pcbmd.action!=EMD) {mderr(126, (UNCH *)0, (UNCH *)0); return;}
109 if (es!=mdessv) synerr(37, &pcbmd);
111 /* EXECUTE: Store the definition for each element name specified.
114 for (i = 0; nmgrp[i]; i++) {
115 if (nmgrp[i]->adl) { /* Error if an ADL exists. */
116 mderr(112, (UNCH *)0, (UNCH *)0);
119 nmgrp[i]->adl = alperm; /* If virgin, store the adl ptr. */
121 if (alperm && nmgrp[i]->etdmod)
122 etdadl(nmgrp[i]); /* Check for conflicts with ETD. */
124 if (!stored && alperm) {
129 /* ETDADL: Check compatibility between ETD and ADL.
132 struct etd *p; /* Pointer to element type definition. */
135 /* Minimizable element cannot have required attribute. */
136 if (GET(p->etdmin, SMO) && GET(p->adl[0].adflags, ADLREQ)) {
137 mderr(40, (UNCH *)0, (UNCH *)0);
138 RESET(p->etdmin, SMO);
140 /* Empty element cannot have NOTATION attribute.
141 Attribute is not removed (too much trouble), but we trap
142 attempts to specify it on the start-tag in adlval().
144 if (GET(p->etdmod->ttype, MNONE)) {
145 if (GET(p->adl[0].adflags, ADLNOTE))
146 mderr(83, (UNCH *)0, (UNCH *)0);
148 /* Empty element cannot have CONREF attribute.
149 Attribute is not removed because it just acts
152 if (GET(p->adl[0].adflags, ADLCONR))
153 mderr(85, (UNCH *)0, (UNCH *)0);
155 /* "-" should not be specified for the end-tag minimization if
156 the element has a content reference attribute. */
157 if (GET(p->adl[0].adflags, ADLCONR) && BITON(p->etdmin, EMM))
158 mderr(153, (UNCH *)0, (UNCH *)0);
160 /* MDNADL: Process ATTLIST declaration for notation.
161 TO DO: Pass deftab and dvtab as parameters so
162 that prohibited types can be handled by leaving
163 them out of the tables.
166 UNCH *tbuf; /* Work area for tokenization (tbuf). */
168 int i; /* Loop counter; temporary variable. */
169 int adlim; /* Number of unused ad slots in al. */
170 struct ad *alperm = 0; /* Attribute definition list. */
173 /* PARAMETER 1: Notation name or a group of them.
175 parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
176 TRACEMD("1: notation name or group");
177 switch (pcbmd.action) {
179 nnmgrp[0] = dcndef(tbuf);
183 parsngrp(nnmgrp, &pcbgrnm, tbuf);
186 mderr(121, (UNCH *)0, (UNCH *)0);
189 subdcl = nnmgrp[0]->ename+1; /* Save first name for error msgs. */
190 /* PARAMETER 2: Attribute definition list.
192 parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
193 TRACEMD("2: attribute list");
194 if (pcbmd.action!=NAS) {
195 mderr(120, (UNCH *)0, (UNCH *)0);
198 while (pcbmd.action==NAS) {
199 al[ADN(al)+1].adname = savenm(tbuf);
200 if ((adlim = ATTCNT-((int)ADN(al)++))<0) {
201 mderr(111, (UNCH *)0, (UNCH *)0);
206 if (mdattdef(adlim, 1)) {
210 parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
212 if (AN(al)>0) { /* Save list only if 1 or more good atts. */
213 alperm = (struct ad *)rmalloc((1+ADN(al))*ADSZ);
214 memcpy((UNIV)alperm, (UNIV)al, (1+ADN(al))*ADSZ );
215 ds.attcnt += AN(al); /* Number of attributes defined. */
216 ds.attgcnt += ADN(al) - AN(al); /* Number of att grp members. */
219 /* Clear attribute list for next declaration. */
220 MEMZERO((UNIV)al, (1+ADN(al))*ADSZ);
222 /* PARAMETER 3: End of declaration.
224 /* Next pcb.action was set during attribute definition loop. */
226 if (pcbmd.action!=EMD) {mderr(126, (UNCH *)0, (UNCH *)0); return;}
227 if (es!=mdessv) synerr(37, &pcbmd);
229 /* EXECUTE: Store the definition for each notation name specified.
232 for (i = 0; nnmgrp[i]; i++) {
233 if (nnmgrp[i]->adl) { /* Error if an ADL exists. */
234 mderr(112, (UNCH *)0, (UNCH *)0);
237 nnmgrp[i]->adl = alperm; /* If virgin, store the adl ptr. */
238 if (nnmgrp[i]->entsw)
243 if (!stored && alperm) {
249 /* Data attributes have been specified for notation p, but entities
250 have already been declared with notation p. Fix up the definitions of
251 all entities with notation p. Generate an error for any data
252 attribute that was required. */
258 for (i = 0; i < ENTHASH; i++) {
260 for (ep = etab[i]; ep; ep = ep->enext)
261 if (ep->estore == ESN && ep->etx.n && ep->etx.n->nedcn == p) {
264 /* Don't use adlval because if there were required
265 attributes the error message wouldn't say what
266 entity was involved. */
267 for (adn = 1; adn <= ADN(al); adn++) {
268 if (GET(ADFLAGS(al,adn), AREQ)) {
269 sgmlerr(218, &pcbstag, ADNAME(al,adn),
271 SET(ADFLAGS(al,adn), AINVALID);
273 if (BITON(ADFLAGS(al, adn), AGROUP))
274 adn += ADNUM(al, adn);
276 storedatt(ep->etx.n);
281 /* MDATTDEF: Process an individual attribute definition.
282 The attribute name is parsed by the caller.
283 Duplicate attributes are parsed, but removed from list.
284 Returns 0 if successful, otherwise returns 1.
286 int mdattdef(adlim, datt)
287 int adlim; /* Remaining capacity of al (in tokens).*/
288 int datt; /* Non-zero if a data attribute. */
290 int deftype; /* Default value type: 0=not keyword. */
291 int errsw = 0; /* 1=semantic error; ignore att. */
292 int novalsw = 0; /* 1=semantic error; treat as IMPLIED. */
293 int attadn = (int)ADN(al); /* Save ad number of this attribute. */
294 struct parse *grppcb = NULL; /* PCB for name/token grp parse. */
295 int errcode; /* Error type returned by PARSEVAL, ANMTGRP. */
296 UNCH *advalsv; /* Save area for permanent value ptr. */
298 /* PARAMETER 1: Attribute name (parsed by caller).
300 TRACEMD("1: attribute name");
301 if (anmget((int)ADN(al)-1, al[attadn].adname)) {
303 mderr(99, ADNAME(al,attadn), (UNCH *)0);
305 ADNUM(al,attadn) = ADFLAGS(al,attadn) = ADLEN(al,attadn) = 0;
306 ADVAL(al,attadn) = 0; ADDATA(al,attadn).x = 0; ADTYPE(al,attadn) = ANMTGRP;
307 /* PARAMETER 2: Declared value.
309 parsemd(lbuf, NAMECASE, &pcblitp, NAMELEN);
310 TRACEMD("2: declared value");
311 switch (pcbmd.action) {
312 case NAS: /* Keyword for value type. */
313 switch (ADTYPE(al,attadn) = (UNCH)mapsrch(dvtab, lbuf+1)) {
315 mderr(100, ADNAME(al,attadn), lbuf+1);
320 mderr(156, (UNCH *)0, (UNCH *)0);
322 else if (!noteadn) noteadn = ADN(al);
325 mderr(101, ADNAME(al,attadn), (UNCH *)0);
327 grppcb = &pcbgrnm; /* NOTATION requires name grp. */
328 parsemd(lbuf, NAMECASE, &pcblitp, NAMELEN);/* Get GRPO*/
333 mderr(144, (UNCH *)0, (UNCH *)0);
339 mderr(102, ADNAME(al,attadn), (UNCH *)0);
346 mderr(155, (UNCH *)0, (UNCH *)0);
353 mderr(154, (UNCH *)0, (UNCH *)0);
359 grppcb = &pcbgrnt; /* Normal grp is name token grp. */
362 mderr(103, ADNAME(al,attadn), (UNCH *)0);
365 mderr(104, ADNAME(al,attadn), (UNCH *)0);
368 /* PARAMETER 2A: Name token group.
370 if (grppcb != NULL) {
371 TRACEMD("2A: name group");
372 switch (pcbmd.action) {
373 case GRPS: /* Name token list. */
374 SET(ADFLAGS(al,attadn), AGROUP);
375 /* Call routine to parse group, create ad entries in adl. */
376 errcode = anmtgrp(grppcb, al+attadn,
377 (GRPCNT<adlim ? GRPCNT+1 : adlim+1),
378 &al[attadn].adnum, ADN(al));
381 mderr(111, (UNCH *)0, (UNCH *)0);
383 mderr(105, ADNAME(al,attadn), (UNCH *)0);
386 ADN(al) += ADNUM(al,attadn); /* Add grp size to total ad cnt.*/
389 mderr(106, ADNAME(al,attadn), (UNCH *)0);
393 /* PARAMETER 3: Default value keyword.
395 parsemd(lbuf, AVALCASE,
396 (ADTYPE(al,attadn)==ACHARS) ? &pcblitr : &pcblitt, LITLEN);
397 TRACEMD("3: default keyword");
398 switch (pcbmd.action) {
399 case RNS: /* Keyword. */
400 deftype = mapsrch(deftab, lbuf+1);
402 case DFIXED: /* FIXED */
403 SET(ADFLAGS(al,attadn), AFIXED);
404 parsemd(lbuf, AVALCASE,
405 (ADTYPE(al,attadn)==ACHARS) ? &pcblitr : &pcblitt,
406 LITLEN); /* Real default. */
407 goto parm3x; /* Go process specified value. */
408 case DCURR: /* CURRENT: If ID, treat as IMPLIED. */
409 if (ADTYPE(al,attadn)==AID) {
410 mderr(80, ADNAME(al,attadn), (UNCH *)0);
414 mderr(157, (UNCH *)0, (UNCH *)0);
417 SET(ADFLAGS(al,attadn), ACURRENT);
419 case DREQ: /* REQUIRED */
420 SET(ADFLAGS(al,attadn), AREQ); ++reqadn;
422 case DCONR: /* CONREF */
423 if (ADTYPE(al,attadn)==AID) {
424 mderr(107, ADNAME(al,attadn), (UNCH *)0);
428 mderr(158, (UNCH *)0, (UNCH *)0);
431 SET(ADFLAGS(al,attadn), ACONREF); conradn = 1;
432 case DNULL: /* IMPLIED */
434 default: /* Unknown keyword is an error. */
435 mderr(108, ADNAME(al,attadn), lbuf+1);
439 /* Ignore erroneous att. */
442 ADN(al) = (UNCH)attadn-1;
448 /* PARAMETER 3x: Default value (non-keyword).
451 TRACEMD("3x: default (non-keyword)");
452 if (ADTYPE(al,attadn)==AID) { /* If ID, treat as IMPLIED. */
453 mderr(81, ADNAME(al,attadn), (UNCH *)0);
454 novalsw = 1; /* Keep parsing to keep things straight. */
456 switch (pcbmd.action) {
457 case LIT: /* Literal. */
458 case LITE: /* Literal. */
459 /* Null string (except CDATA) is error: msg and treat as IMPLIED. */
460 if (*lbuf == '\0' && ADTYPE(al,attadn)!=ACHARS) {
461 mderr(82, ADNAME(al,attadn), (UNCH *)0);
465 case NAS: /* Name character string. */
466 case NMT: /* Name character string. */
467 case NUM: /* Number or number token string. */
468 /* The name won't have a length byte because AVALCASE was specified. */
471 parsetkn(lbuf, NMC, LITLEN);
474 mderr(109, ADNAME(al,attadn), (UNCH *)0);
477 mderr(110, ADNAME(al,attadn), (UNCH *)0);
481 /* Ignore erroneous att. */
484 ADN(al) = (UNCH)attadn-1;
487 if (novalsw) return(0);
489 /* PARAMETER 3y: Validate and store default value.
491 if (ADTYPE(al,attadn)==ACHARS) {
492 UNS len = vallen(ACHARS, 0, lbuf);
494 /* Treat as implied. */
495 sgmlerr(224, &pcbmd, ADNAME(al,attadn), (UNCH *)0);
498 /* No more checking for CDATA value. */
499 ADNUM(al,attadn) = 0; /* CDATA is 0 tokens. */
500 ADVAL(al,attadn) = savestr(lbuf);/* Store default; save ptr. */
501 ADLEN(al,attadn) = len;
505 /* Parse value and save token count (GROUP implies 1 token). */
506 advalsv = (UNCH *)rmalloc(ustrlen(lbuf)+2); /* Storage for tokenized value. */
507 errcode = parseval(lbuf, (UNS)ADTYPE(al,attadn), advalsv);
508 if (BITOFF(ADFLAGS(al,attadn), AGROUP)) ADNUM(al,attadn) = (UNCH)tokencnt;
510 /* If value was invalid, or was a group member that was not in the group,
511 issue an appropriate message and set the error switch. */
513 {sgmlerr((UNS)errcode, &pcbmd, ADNAME(al,attadn), lbuf); errsw = 1;}
514 else if ( BITON(ADFLAGS(al,attadn), AGROUP)
515 && !amemget(&al[attadn], (int)ADNUM(al,attadn), advalsv) ) {
516 sgmlerr(79, &pcbmd, ADNAME(al,attadn), advalsv+1);
519 ADLEN(al,attadn) = vallen(ADTYPE(al,attadn), ADNUM(al,attadn), advalsv);
520 if (ADLEN(al,attadn) > LITLEN) {
521 sgmlerr(224, &pcbmd, ADNAME(al,attadn), (UNCH *)0);
522 ADLEN(al,attadn) = 0;
525 /* For valid tokenized value, save it and update statistics. */
527 ADVAL(al,attadn) = advalsv;
528 ds.attdef += ADLEN(al,attadn);
531 /* If value was bad, free the value's storage and treat as
532 IMPLIED or REQUIRED. */
533 frem((UNIV)advalsv); /* Release storage for value. */
534 ADVAL(al,attadn) = NULL; /* And make value NULL. */
537 /* ANMTGRP: Parse a name or name token group, create attribute descriptors
538 for its members, and add them to the attribute descriptor list.
539 The parse either terminates or returns a good token, so no
542 int anmtgrp(pcb, nt, grplim, adn, adsz)
543 struct parse *pcb; /* PCB for name or name token grp. */
544 struct ad nt[]; /* Buffer for creating name token list. */
545 int grplim; /* Maximum size of list (plus 1). */
546 UNS *adn; /* Ptr to number of names or tokens in grp. */
547 int adsz; /* Size of att def list. */
549 UNCH adtype = (UNCH)(pcb==&pcbgrnt ? ANMTGRP:ANOTEGRP);/*Attribute type.*/
550 int essv = es; /* Entity stack level when grp started. */
552 *adn = 0; /* Group is empty to start. */
553 while (parse(pcb)!=GRPE && *adn<grplim) {
554 switch (pcb->action) {
555 case NAS_: /* Name or name token (depending on pcb). */
557 parsenm(lbuf, NAMECASE);
558 nt[*adn+1].adname = savenm(lbuf);
559 if (antvget((int)(adsz+*adn), nt[*adn+1].adname, (UNCH **)0))
560 mderr(98, ntoa((int)*adn+1), nt[*adn+1].adname+1);
561 nt[++*adn].adtype = adtype;
562 nt[*adn].addef = NULL;
565 case EE_: /* Entity ended (correctly or incorrectly). */
566 if (es<essv) {synerr(37, pcb); essv = es;}
569 case PIE_: /* PI entity reference (invalid). */
570 entpisw = 0; /* Reset PI entity indicator. */
579 if (es!=essv) synerr(37, pcb);
580 if (*adn==grplim) return -1;
581 else return *adn; /* Return number of tokens. */
583 /* MDDTDS: Process start of DOCTYPE declaration (through MSO).
586 UNCH *tbuf; /* Work area for tokenization[LITLEN+2]. */
588 struct fpi fpicb; /* Formal public identifier structure. */
589 union etext etx; /* Ptr to entity text. */
590 UNCH estore = ESD; /* Entity storage class. */
591 int emdsw = 0; /* 1=end of declaration found; 0=not yet. */
593 mdname = key[KDOCTYPE]; /* Identify declaration for messages. */
594 subdcl = NULL; /* No subject as yet. */
595 parmno = 0; /* No parameters as yet. */
596 mdessv = es; /* Save es for checking entity nesting. */
597 dtdrefsw = 0; /* No external DTD entity as yet. */
598 /* PARAMETER 1: Document type name.
601 parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
602 TRACEMD("1: doc type name");
603 if (pcbmd.action!=NAS) {mderr(120, (UNCH *)0, (UNCH *)0); return;}
604 dtype = savenm(tbuf);
605 subdcl = dtype+1; /* Subject of declaration for error msgs. */
607 /* PARAMETER 2: External identifier keyword or MDS.
610 parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
611 TRACEMD("2: extid or MDS");
612 switch (pcbmd.action) {
614 if (mdextid(tbuf, &fpicb, dtype+1, &estore, (PNE)0)==0) return;
615 if ((etx.x = entgen(&fpicb))==0)
616 mderr(146, dtype+1, (UNCH *)0);
618 dtdrefsw = 1; /* Signal external DTD entity. */
623 mderr(128, (UNCH *)0, (UNCH *)0);
626 /* PARAMETER 3: MDS or end of declaration.
628 TRACEMD("3: MDS or EMD");
629 switch (pcbmd.action) {
630 default: /* Treat as end of declaration. */
631 mderr(126, (UNCH *)0, (UNCH *)0);
637 /* EXECUTE: Store entity definition if an external ID was specified.
640 if (es!=mdessv) synerr(37, &pcbmd);
641 propcb = &pcbmds; /* Prepare to parse doc type definition (MDS). */
643 /* TO DO: If concurrent DTD's supported, free existing
644 etext for all but first DTD (or reuse it). */
645 entdef(indtdent, estore, &etx);
646 ++ds.ecbcnt; ds.ecbtext += entlen;
648 REPEATCC; /* Push back the MDC. */
649 *FPOS = lex.d.msc; /* Simulate end of DTD subset. */
650 REPEATCC; /* Back up to read MSC next. */
651 delmscsw = 1; /* Insert MSC after referenced DTD. */
654 indtdsw = 1; /* Allow "DTD only" parameters. */
657 /* MDDTDE: Process DOCTYPE declaration end.
660 UNCH *tbuf; /* Work area for tokenization. */
662 mdessv = es; /* Save es for checking entity nesting. */
663 propcb = &pcbpro; /* Restore normal prolog parse. */
664 indtdsw = 0; /* Prohibit "DTD only" parameters. */
666 mdname = key[KDOCTYPE]; /* Identify declaration for messages. */
667 subdcl = dtype+1; /* Subject of declaration for error msgs. */
668 parmno = 0; /* No parameters as yet. */
669 /* PARAMETER 4: End of declaration.
672 parsemd(tbuf, NAMECASE, &pcblitp, LITLEN);
674 if (pcbmd.action!=EMD) mderr(126, (UNCH *)0, (UNCH *)0);
675 if (es!=mdessv) synerr(37, &pcbmd);
677 /* MDELEM: Process ELEMENT declaration.
680 UNCH *tbuf; /* Work area for tokenization (tbuf). */
682 UNCH *ranksuff = lbuf; /* Rank suffix. */
683 UNS dctype = 0; /* Declared content type (from dctab). */
684 UNCH fmin = 0; /* Minimization bit flags. */
685 int i; /* Loop counter. */
686 UNS u; /* Temporary variable. */
687 struct etd **mexgrp, **pexgrp; /* Ptr to model exceptions array. */
688 struct thdr *cmod, *cmodsv; /* Ptr to content model. */
689 UNCH *etdgi; /* GI of current etd (when going through group).*/
690 int minomitted = 0; /* Tag minimization parameters omitted. */
692 mdname = key[KELEMENT]; /* Identify declaration for messages. */
693 subdcl = NULL; /* No subject as yet. */
694 parmno = 0; /* No parameters as yet. */
695 mdessv = es; /* Save es level for entity nesting check. */
699 /* PARAMETER 1: Element name or a group of them.
701 parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
702 TRACEMD("1: element name or grp");
703 switch (pcbmd.action) {
705 nmgrp[0] = etddef(tbuf);
709 parsegrp(nmgrp, &pcbgrnm, tbuf);
712 mderr(121, (UNCH *)0, (UNCH *)0);
715 /* Save first GI for trace and error messages. */
717 subdcl = nmgrp[0]->etdgi+1;
719 /* PARAMETER 1A: Rank suffix (optional).
721 parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
722 TRACEMD("1A: rank suffix");
723 switch (pcbmd.action) {
725 ustrcpy(ranksuff, tbuf);
726 parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
730 /* PARAMETER 2A: Start-tag minimization.
732 TRACEMD("2A: start min");
733 switch (pcbmd.action) {
737 if (!ustrcmp(tbuf+1, key[KO])) {
738 if (OMITTAG==YES) SET(fmin, SMO);
743 if (OMITTAG==NO) {minomitted=1; break;}
744 mderr(129, tbuf+1, (UNCH *)0);
747 /* Must omit omitted end-tag minimization, if omitted
748 start-tag minimization was omitted (because OMITTAG == NO). */
750 /* PARAMETER 2B: End-tag minimization.
752 parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
753 TRACEMD("2B: end min");
754 switch (pcbmd.action) {
756 if (ustrcmp(tbuf+1, key[KO])) {mderr(129, tbuf+1, (UNCH *)0); return;}
757 if (OMITTAG==YES) SET(fmin, EMO);
763 mderr(129, tbuf+1, (UNCH *)0);
766 /* PARAMETER 3: Declared content.
768 parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
770 TRACEMD("3: declared content");
771 switch (pcbmd.action) {
773 dctype = mapsrch(dctab, tbuf+1);
774 if (!dctype) {mderr(24, tbuf+1, (UNCH *)0); return;}
775 /* Eliminate incompatibilities among parameters. */
776 if (GET(fmin, SMO) && GET(dctype, MNONE+MCDATA+MRCDATA)) {
777 mderr(58, (UNCH *)0, (UNCH *)0);
780 if (GET(dctype, MNONE) && BITON(fmin, EMM)) {
781 mderr(87, (UNCH *)0, (UNCH *)0);
784 /* If valid, process like a content model. */
786 cmodsv = parsemod((int)(pcbmd.action==GRPS ? 0 : dctype));
787 if (cmodsv==0) return;
788 u = (dctype ? 1 : cmodsv->tu.tnum+2) * THSZ;
789 cmod = (struct thdr *)rmalloc(u);
790 memcpy((UNIV)cmod , (UNIV)cmodsv, u );
791 ds.modcnt += cmod->tu.tnum;
795 mderr(130, (UNCH *)0, (UNCH *)0);
798 /* PARAMETERS 3A, 3B: Exceptions or end.
800 parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
801 if (BITOFF(cmod->ttype, MCDATA+MRCDATA+MNONE)) {
802 /* PARAMETER 3A: Minus exceptions.
805 switch (pcbmd.action) {
807 /* We cheat and use nnmgrp for this. */
808 mexgrp = copygrp((PETD *)nnmgrp,
809 u = parsegrp((PETD *)nnmgrp, &pcbgrnm, tbuf));
810 ++ds.pmexgcnt; ds.pmexcnt += u-1;
812 parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
816 /* PARAMETER 3B: Plus exceptions.
819 switch (pcbmd.action) {
821 pexgrp = copygrp((PETD *)nnmgrp,
822 u = parsegrp((PETD *)nnmgrp, &pcbgrnm, tbuf));
823 ++ds.pmexgcnt; ds.pmexcnt += u-1;
825 parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
830 /* PARAMETER 4: End of declaration.
833 if (pcbmd.action!=EMD) mderr(126, (UNCH *)0, (UNCH *)0);
834 if (es!=mdessv) synerr(37, &pcbmd);
836 /* EXECUTE: Store the definition for each element name specified.
839 for (i = -1; nmgrp[++i];) {
840 etdgi = nmgrp[i]->etdgi;
842 if ((tbuf[0] = *etdgi + ustrlen(ranksuff)) - 2 > NAMELEN) {
843 mderr(131, etdgi+1, ranksuff);
846 memcpy(tbuf+1, etdgi+1, *etdgi-1);
847 ustrcpy(tbuf+*etdgi-1, ranksuff);
849 nmgrp[i] = etddef(tbuf);
851 if (nmgrp[i]->etdmod) {mderr(56, etdgi+1, (UNCH *)0); continue;}
852 etdset(nmgrp[i], fmin+ETDDCL, cmod, mexgrp, pexgrp, nmgrp[i]->etdsrm);
854 if (nmgrp[i]->adl) etdadl(nmgrp[i]); /* Check ETD conflicts. */
859 VOID adlfree(al, aln)
863 for (; aln <= ADN(al); aln++) {
864 frem((UNIV)al[aln].adname);
866 frem((UNIV)ADVAL(al, aln));
867 if (BITON(ADFLAGS(al, aln), AGROUP)) {
869 for (i = 0; i < ADNUM(al, aln); i++)
870 frem((UNIV)al[aln + i + 1].adname);
871 aln += ADNUM(al, aln);
879 c-continued-statement-offset: 5