Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / programs / dtdocbook / sgmls / md1.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
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)
10  * any later version.
11  *
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
16  * details.
17  *
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
22  */
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.
26 */
27 VOID mdadl(tbuf)
28 UNCH *tbuf;                   /* Work area for tokenization (tbuf). */
29 {
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. */
33      int stored = 0;
34
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.
44      */
45      parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
46      TRACEMD("1: element name or group");
47      switch (pcbmd.action) {
48      case NAS:
49           nmgrp[0] = etddef(tbuf);
50           nmgrp[1] = 0;
51           break;
52      case GRPS:
53           parsegrp(nmgrp, &pcbgrnm, tbuf);
54           break;
55      case RNS:           /* Reserved name started. */
56           if (ustrcmp(tbuf+1, key[KNOTATION])) {
57                mderr(118, tbuf+1, key[KNOTATION]);
58                return;
59           }
60           mdnadl(tbuf);
61           return;
62      default:
63           mderr(121, (UNCH *)0, (UNCH *)0);
64           return;
65      }
66      /* Save first GI for error msgs. */
67      if (nmgrp[0])
68           subdcl = nmgrp[0]->etdgi+1;
69      /* PARAMETER 2: Attribute definition list.
70      */
71      parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
72      TRACEMD("2: attribute list");
73      if (pcbmd.action!=NAS) {
74           mderr(120, (UNCH *)0, (UNCH *)0);
75           return;
76      }
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);
81                adlfree(al, 1);
82                return;
83           }
84           ++AN(al);
85           if (mdattdef(adlim, 0)) {
86                adlfree(al, 1);
87                return;
88           }
89           parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
90      }
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. */
99           TRACEADL(alperm);
100      }
101      /* Clear attribute list for next declaration. */
102      MEMZERO((UNIV)al, (1+ADN(al))*ADSZ);
103
104      /* PARAMETER 3: End of declaration.
105      */
106      /* Next pcb.action was set during attribute definition loop. */
107      TRACEMD(emd);
108      if (pcbmd.action!=EMD) {mderr(126, (UNCH *)0, (UNCH *)0); return;}
109      if (es!=mdessv) synerr(37, &pcbmd);
110
111      /* EXECUTE: Store the definition for each element name specified.
112      */
113      TRACEGRP(nmgrp);
114      for (i = 0; nmgrp[i]; i++) {
115           if (nmgrp[i]->adl) {     /* Error if an ADL exists. */
116                mderr(112, (UNCH *)0, (UNCH *)0);
117                continue;
118           }
119           nmgrp[i]->adl = alperm;  /* If virgin, store the adl ptr. */
120           stored = 1;
121           if (alperm && nmgrp[i]->etdmod)
122                etdadl(nmgrp[i]); /* Check for conflicts with ETD. */
123      }
124      if (!stored && alperm) {
125           adlfree(alperm, 1);
126           frem((UNIV)alperm);
127      }
128 }
129 /* ETDADL: Check compatibility between ETD and ADL.
130 */
131 VOID etdadl(p)
132 struct etd *p;                /* Pointer to element type definition. */
133 {
134      parmno = 0;
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);
139      }
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().
143      */
144      if (GET(p->etdmod->ttype, MNONE)) {
145           if (GET(p->adl[0].adflags, ADLNOTE))
146                mderr(83, (UNCH *)0, (UNCH *)0);
147
148           /* Empty element cannot have CONREF attribute.
149              Attribute is not removed because it just acts
150              like IMPLIED anyway.
151           */
152           if (GET(p->adl[0].adflags, ADLCONR))
153                mderr(85, (UNCH *)0, (UNCH *)0);
154      }
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);
159 }
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.
164 */
165 VOID mdnadl(tbuf)
166 UNCH *tbuf;                   /* Work area for tokenization (tbuf). */
167 {
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. */
171      int stored = 0;
172
173      /* PARAMETER 1: Notation name or a group of them.
174      */
175      parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
176      TRACEMD("1: notation name or group");
177      switch (pcbmd.action) {
178      case NAS:
179           nnmgrp[0] = dcndef(tbuf);
180           nnmgrp[1] = 0;
181           break;
182      case GRPS:
183           parsngrp(nnmgrp, &pcbgrnm, tbuf);
184           break;
185      default:
186           mderr(121, (UNCH *)0, (UNCH *)0);
187           return;
188      }
189      subdcl = nnmgrp[0]->ename+1;        /* Save first name for error msgs. */
190      /* PARAMETER 2: Attribute definition list.
191      */
192      parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
193      TRACEMD("2: attribute list");
194      if (pcbmd.action!=NAS) {
195           mderr(120, (UNCH *)0, (UNCH *)0);
196           return;
197      }
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);
202                adlfree(al, 1);
203                return;
204           }
205           ++AN(al);
206           if (mdattdef(adlim, 1)) {
207                adlfree(al, 1);
208                return;
209           }
210           parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
211      }
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. */
217           TRACEADL(alperm);
218      }
219      /* Clear attribute list for next declaration. */
220      MEMZERO((UNIV)al, (1+ADN(al))*ADSZ);
221
222      /* PARAMETER 3: End of declaration.
223      */
224      /* Next pcb.action was set during attribute definition loop. */
225      TRACEMD(emd);
226      if (pcbmd.action!=EMD) {mderr(126, (UNCH *)0, (UNCH *)0); return;}
227      if (es!=mdessv) synerr(37, &pcbmd);
228
229      /* EXECUTE: Store the definition for each notation name specified.
230      */
231      TRACENGR(nnmgrp);
232      for (i = 0; nnmgrp[i]; i++) {
233           if (nnmgrp[i]->adl) {     /* Error if an ADL exists. */
234                mderr(112, (UNCH *)0, (UNCH *)0);
235                continue;
236           }
237           nnmgrp[i]->adl = alperm;  /* If virgin, store the adl ptr. */
238           if (nnmgrp[i]->entsw)
239                fixdatt(nnmgrp[i]);
240           stored = 1;
241           TRACEDCN(nnmgrp[i]);
242      }
243      if (!stored && alperm) {
244           adlfree(alperm, 1);
245           frem((UNIV)alperm);
246      }
247 }
248
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. */
253
254 VOID fixdatt(p)
255 struct dcncb *p;
256 {
257      int i;
258      for (i = 0; i < ENTHASH; i++) {
259           struct entity *ep;
260           for (ep = etab[i]; ep; ep = ep->enext)
261                if (ep->estore == ESN && ep->etx.n && ep->etx.n->nedcn == p) {
262                     int adn;
263                     initatt(p->adl);
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),
270                                       ep->ename + 1);
271                               SET(ADFLAGS(al,adn), AINVALID);
272                          }
273                          if (BITON(ADFLAGS(al, adn), AGROUP))
274                               adn += ADNUM(al, adn);
275                     }
276                     storedatt(ep->etx.n);
277                }
278      }
279 }
280
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.
285 */
286 int mdattdef(adlim, datt)
287 int adlim;                    /* Remaining capacity of al (in tokens).*/
288 int datt;                     /* Non-zero if a data attribute. */
289 {
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. */
297
298      /* PARAMETER 1: Attribute name (parsed by caller).
299      */
300      TRACEMD("1: attribute name");
301      if (anmget((int)ADN(al)-1, al[attadn].adname)) {
302           errsw = 1;
303           mderr(99, ADNAME(al,attadn), (UNCH *)0);
304      }
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.
308      */
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)) {
314           case 0:
315                mderr(100, ADNAME(al,attadn), lbuf+1);
316                return 1;
317           case ANOTEGRP:
318                if (datt) {
319                     errsw = 1;
320                     mderr(156, (UNCH *)0, (UNCH *)0);
321                }
322                else if (!noteadn) noteadn = ADN(al);
323                else {
324                     errsw = 1;
325                     mderr(101, ADNAME(al,attadn), (UNCH *)0);
326                }
327                grppcb = &pcbgrnm;         /* NOTATION requires name grp. */
328                parsemd(lbuf, NAMECASE, &pcblitp, NAMELEN);/* Get GRPO*/
329                break;
330           case AID:
331                if (datt) {
332                     errsw = 1;
333                     mderr(144, (UNCH *)0, (UNCH *)0);
334                }
335                else if (!idadn)
336                     idadn = attadn;
337                else {
338                     errsw = 1;
339                     mderr(102, ADNAME(al,attadn), (UNCH *)0);
340                }
341                break;
342           case AIDREF:
343           case AIDREFS:
344                if (datt) {
345                     errsw = 1;
346                     mderr(155, (UNCH *)0, (UNCH *)0);
347                }
348                break;
349           case AENTITY:
350           case AENTITYS:
351                if (datt) {
352                     errsw = 1;
353                     mderr(154, (UNCH *)0, (UNCH *)0);
354                }
355                break;
356           }
357           break;
358      case GRPS:
359           grppcb = &pcbgrnt;           /* Normal grp is name token grp. */
360           break;
361      case EMD:
362           mderr(103, ADNAME(al,attadn), (UNCH *)0);
363           return 1;
364      default:
365           mderr(104, ADNAME(al,attadn), (UNCH *)0);
366           return 1;
367      }
368      /* PARAMETER 2A: Name token group.
369      */
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));
379                if (errcode<=0) {
380                     if (adlim < GRPCNT)
381                          mderr(111, (UNCH *)0, (UNCH *)0);
382                     else
383                          mderr(105, ADNAME(al,attadn), (UNCH *)0);
384                     return 1;
385                }
386                ADN(al) += ADNUM(al,attadn);    /* Add grp size to total ad cnt.*/
387                break;
388           default:
389                mderr(106, ADNAME(al,attadn), (UNCH *)0);
390                return 1;
391           }
392      }
393      /* PARAMETER 3: Default value keyword.
394      */
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);
401           switch (deftype) {
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);
411                     break;
412                }
413                if (datt) {
414                     mderr(157, (UNCH *)0, (UNCH *)0);
415                     break;
416                }
417                SET(ADFLAGS(al,attadn), ACURRENT);
418                break;
419           case DREQ:          /* REQUIRED */
420                SET(ADFLAGS(al,attadn), AREQ); ++reqadn;
421                break;
422           case DCONR:         /* CONREF */
423                if (ADTYPE(al,attadn)==AID) {
424                     mderr(107, ADNAME(al,attadn), (UNCH *)0);
425                     break;
426                }
427                if (datt) {
428                     mderr(158, (UNCH *)0, (UNCH *)0);
429                     break;
430                }
431                SET(ADFLAGS(al,attadn), ACONREF); conradn = 1;
432           case DNULL:         /* IMPLIED */
433                break;
434           default:            /* Unknown keyword is an error. */
435                mderr(108, ADNAME(al,attadn), lbuf+1);
436                errsw = 1;
437           }
438           if (errsw) {
439                /* Ignore erroneous att. */
440                adlfree(al, attadn);
441                --AN(al);
442                ADN(al) = (UNCH)attadn-1;
443           }
444           return(0);
445      default:
446           break;
447      }
448      /* PARAMETER 3x: Default value (non-keyword).
449      */
450      parm3x:
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. */
455      }
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);
462                novalsw = 1;
463           }
464           break;
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. */
469           break;
470      case CDR:
471           parsetkn(lbuf, NMC, LITLEN);
472           break;
473      case EMD:
474           mderr(109, ADNAME(al,attadn), (UNCH *)0);
475           return 1;
476      default:
477           mderr(110, ADNAME(al,attadn), (UNCH *)0);
478           return 1;
479      }
480      if (errsw) {
481           /* Ignore erroneous att. */
482           adlfree(al, attadn);
483           --AN(al);
484           ADN(al) = (UNCH)attadn-1;
485           return(0);
486      }
487      if (novalsw) return(0);
488
489      /* PARAMETER 3y: Validate and store default value.
490      */
491      if (ADTYPE(al,attadn)==ACHARS) {
492           UNS len = vallen(ACHARS, 0, lbuf);
493           if (len > LITLEN) {
494                /* Treat as implied. */
495                sgmlerr(224, &pcbmd, ADNAME(al,attadn), (UNCH *)0);
496                return 0;
497           }
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;
502           ds.attdef += len;
503           return 0;
504      }
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;
509
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. */
512      if (errcode)
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);
517                errsw = 1;
518      }
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;
523           errsw = 1;
524      }
525      /* For valid tokenized value, save it and update statistics. */
526      if (!errsw) {
527           ADVAL(al,attadn) = advalsv;
528           ds.attdef += ADLEN(al,attadn);
529           return 0;
530      }
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. */
535      return 0;
536 }
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
540             switch is needed.
541 */
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. */
548 {
549      UNCH adtype = (UNCH)(pcb==&pcbgrnt ? ANMTGRP:ANOTEGRP);/*Attribute type.*/
550      int essv = es;           /* Entity stack level when grp started. */
551
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). */
556           case NMT_:
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;
563                continue;
564
565           case EE_:           /* Entity ended (correctly or incorrectly). */
566                if (es<essv) {synerr(37, pcb); essv = es;}
567                continue;
568
569           case PIE_:          /* PI entity reference (invalid). */
570                entpisw = 0;   /* Reset PI entity indicator. */
571                synerr(59, pcb);
572                continue;
573
574           default:
575                break;
576           }
577           break;
578      }
579      if (es!=essv) synerr(37, pcb);
580      if (*adn==grplim) return -1;
581      else return *adn;        /* Return number of tokens. */
582 }
583 /* MDDTDS: Process start of DOCTYPE declaration (through MSO).
584 */
585 VOID mddtds(tbuf)
586 UNCH *tbuf;                   /* Work area for tokenization[LITLEN+2]. */
587 {
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. */
592
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.
599      */
600      pcbmd.newstate = 0;
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. */
606
607      /* PARAMETER 2: External identifier keyword or MDS.
608      */
609      pcbmd.newstate = 0;
610      parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
611      TRACEMD("2: extid or MDS");
612      switch (pcbmd.action) {
613      case NAS:
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);
617           else
618                dtdrefsw = 1;  /* Signal external DTD entity. */
619           break;
620      case MDS:
621           goto execute;
622      default:
623           mderr(128, (UNCH *)0, (UNCH *)0);
624           return;
625      }
626      /* PARAMETER 3: MDS or end of declaration.
627      */
628      TRACEMD("3: MDS or EMD");
629      switch (pcbmd.action) {
630      default:                      /* Treat as end of declaration. */
631           mderr(126, (UNCH *)0, (UNCH *)0);
632      case EMD:
633           emdsw = 1;
634      case MDS:
635           break;
636      }
637      /* EXECUTE: Store entity definition if an external ID was specified.
638      */
639      execute:
640      if (es!=mdessv) synerr(37, &pcbmd);
641      propcb = &pcbmds;        /* Prepare to parse doc type definition (MDS). */
642      if (dtdrefsw) {
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;
647           if (emdsw) {
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. */
652           }
653      }
654      indtdsw = 1;                       /* Allow "DTD only" parameters. */
655      return;
656 }
657 /* MDDTDE: Process DOCTYPE declaration end.
658 */
659 VOID mddtde(tbuf)
660 UNCH *tbuf;                   /* Work area for tokenization. */
661 {
662      mdessv = es;             /* Save es for checking entity nesting. */
663      propcb = &pcbpro;        /* Restore normal prolog parse. */
664      indtdsw = 0;             /* Prohibit "DTD only" parameters. */
665
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.
670      */
671      pcbmd.newstate = 0;
672      parsemd(tbuf, NAMECASE, &pcblitp, LITLEN);
673      TRACEMD(emd);
674      if (pcbmd.action!=EMD) mderr(126, (UNCH *)0, (UNCH *)0);
675      if (es!=mdessv) synerr(37, &pcbmd);
676 }
677 /* MDELEM: Process ELEMENT declaration.
678 */
679 VOID mdelem(tbuf)
680 UNCH *tbuf;                   /* Work area for tokenization (tbuf). */
681 {
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. */
691
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. */
696      ranksuff[0] = 0;
697      mexgrp = pexgrp = 0;
698
699      /* PARAMETER 1: Element name or a group of them.
700      */
701      parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
702      TRACEMD("1: element name or grp");
703      switch (pcbmd.action) {
704      case NAS:
705           nmgrp[0] = etddef(tbuf);
706           nmgrp[1] = 0;
707           break;
708      case GRPS:
709           parsegrp(nmgrp, &pcbgrnm, tbuf);
710           break;
711      default:
712           mderr(121, (UNCH *)0, (UNCH *)0);
713           return;
714      }
715      /* Save first GI for trace and error messages. */
716      if (nmgrp[0])
717           subdcl = nmgrp[0]->etdgi+1;
718
719      /* PARAMETER 1A: Rank suffix (optional).
720      */
721      parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
722      TRACEMD("1A: rank suffix");
723      switch (pcbmd.action) {
724      case NUM:
725           ustrcpy(ranksuff, tbuf);
726           parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
727      default:
728           break;
729      }
730      /* PARAMETER 2A: Start-tag minimization.
731      */
732      TRACEMD("2A: start min");
733      switch (pcbmd.action) {
734      case CDR:
735           break;
736      case NAS:
737           if (!ustrcmp(tbuf+1, key[KO])) {
738                if (OMITTAG==YES) SET(fmin, SMO);
739                break;
740           }
741           /* fall through */
742      default:
743           if (OMITTAG==NO) {minomitted=1; break;}
744           mderr(129, tbuf+1, (UNCH *)0);
745           return;
746      }
747      /* Must omit omitted end-tag minimization, if omitted 
748         start-tag minimization was omitted (because OMITTAG == NO). */
749      if (!minomitted) {
750           /* PARAMETER 2B: End-tag minimization.
751            */
752           parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
753           TRACEMD("2B: end min");
754           switch (pcbmd.action) {
755           case NAS:
756                if (ustrcmp(tbuf+1, key[KO])) {mderr(129, tbuf+1, (UNCH *)0); return;}
757                if (OMITTAG==YES) SET(fmin, EMO);
758                break;
759           case CDR:
760                SET(fmin, EMM);
761                break;
762           default:
763                mderr(129, tbuf+1, (UNCH *)0);
764                return;
765           }
766           /* PARAMETER 3: Declared content.
767            */
768           parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
769      }
770      TRACEMD("3: declared content");
771      switch (pcbmd.action) {
772      case NAS:
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);
778                RESET(fmin, SMO);
779           }
780           if (GET(dctype, MNONE) && BITON(fmin, EMM)) {
781                mderr(87, (UNCH *)0, (UNCH *)0);
782                SET(fmin, EMO);
783           }
784           /* If valid, process like a content model. */
785      case GRPS:
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;
792           TRACEMOD(cmod);
793           break;
794      default:
795           mderr(130, (UNCH *)0, (UNCH *)0);
796           return;
797      }
798      /* PARAMETERS 3A, 3B: Exceptions or end.
799      */
800      parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
801      if (BITOFF(cmod->ttype, MCDATA+MRCDATA+MNONE)) {
802           /* PARAMETER 3A: Minus exceptions.
803           */
804           TRACEMD("3A: -grp");
805           switch (pcbmd.action) {
806           case MGRP:
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;
811                TRACEGRP(mexgrp);
812                parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
813           default:
814                break;
815           }
816           /* PARAMETER 3B: Plus exceptions.
817           */
818           TRACEMD("3B: +grp");
819           switch (pcbmd.action) {
820           case PGRP:
821                pexgrp = copygrp((PETD *)nnmgrp,
822                                 u = parsegrp((PETD *)nnmgrp, &pcbgrnm, tbuf));
823                ++ds.pmexgcnt; ds.pmexcnt += u-1;
824                TRACEGRP(pexgrp);
825                parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
826           default:
827                break;
828           }
829      }
830      /* PARAMETER 4: End of declaration.
831      */
832      TRACEMD(emd);
833      if (pcbmd.action!=EMD) mderr(126, (UNCH *)0, (UNCH *)0);
834      if (es!=mdessv) synerr(37, &pcbmd);
835
836      /* EXECUTE: Store the definition for each element name specified.
837      */
838      TRACEGRP(nmgrp);
839      for (i = -1; nmgrp[++i];) {
840           etdgi = nmgrp[i]->etdgi;
841           if (*ranksuff) {
842                if ((tbuf[0] = *etdgi + ustrlen(ranksuff)) - 2 > NAMELEN) {
843                     mderr(131, etdgi+1, ranksuff);
844                     continue;
845                }
846                memcpy(tbuf+1, etdgi+1, *etdgi-1);
847                ustrcpy(tbuf+*etdgi-1, ranksuff);
848                etdcan(etdgi);
849                nmgrp[i] = etddef(tbuf);
850           }
851           if (nmgrp[i]->etdmod) {mderr(56, etdgi+1, (UNCH *)0); continue;}
852           etdset(nmgrp[i], fmin+ETDDCL, cmod, mexgrp, pexgrp, nmgrp[i]->etdsrm);
853           ++ds.etdcnt;
854           if (nmgrp[i]->adl) etdadl(nmgrp[i]); /* Check ETD conflicts. */
855           TRACEETD(nmgrp[i]);
856      }
857 }
858
859 VOID adlfree(al, aln)
860 struct ad *al;
861 int aln;
862 {
863      for (; aln <= ADN(al); aln++) {
864           frem((UNIV)al[aln].adname);
865           if (ADVAL(al, aln))
866                frem((UNIV)ADVAL(al, aln));
867           if (BITON(ADFLAGS(al, aln), AGROUP)) {
868                int i;
869                for (i = 0; i < ADNUM(al, aln); i++)
870                     frem((UNIV)al[aln + i + 1].adname);
871                aln += ADNUM(al, aln);
872           }
873      }
874 }
875
876 /*
877 Local Variables:
878 c-indent-level: 5
879 c-continued-statement-offset: 5
880 c-brace-offset: -5
881 c-argdecl-indent: 0
882 c-label-offset: -5
883 comment-column: 30
884 End:
885 */