Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / programs / dtdocbook / sgmls / md2.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: md2.c /main/3 1996/06/19 17:16:14 drk $ */
24 #include "sgmlincl.h"         /* #INCLUDE statements for SGML parser. */
25 /* MDENTITY: Process ENTITY declaration.
26 */
27 VOID mdentity(tbuf)
28 UNCH *tbuf;                   /* Work area for tokenization[LITLEN+2]. */
29 {
30      struct fpi fpicb;        /* Formal public identifier structure. */
31      struct fpi *fpis = &fpicb;  /* Ptr to current or #DEFAULT fpi. */
32      union etext etx;         /* Ptr to entity text. */
33      UNCH estore = ESM;       /* Entity storage class. */
34      struct entity *ecb;      /* Ptr to entity control block. */
35      int parmsw = 0;          /* 1=parameter entity declaration; 0 = not. */
36      int defltsw = 0;         /* 1=#DEFAULT declaration; 0=not. */
37      PNE pne = 0;             /* Ptr to N/C/SDATA entity control block. */
38
39      mdname = key[KENTITY];  /* Declaration name for messages. */
40      subdcl = NULL;           /* No subject as yet. */
41      parmno = 0;              /* No parameters as yet. */
42      mdessv = es;             /* Save es for checking entity nesting. */
43      /* PARAMETER 1: Entity name.
44      */
45      pcbmd.newstate = 0;
46      parsemd(nmbuf, ENTCASE, &pcblitp, NAMELEN);
47      TRACEMD("1: entity nm");
48      switch (pcbmd.action) {
49      case PEN:
50           parsemd(nmbuf + 1, ENTCASE, &pcblitp, NAMELEN);
51           if (pcbmd.action!=NAS) {mderr(120, (UNCH *)0, (UNCH *)0); return;}
52           if (nmbuf[1] == NAMELEN + 2) {
53                /* It was too long. */
54                nmbuf[0] = NAMELEN + 2;
55                nmbuf[NAMELEN + 1] = '\0';
56                mderr(65, (UNCH *)0, (UNCH *)0);
57           }
58           else
59                nmbuf[0] = nmbuf[1] + 1; /* Increment length for PERO. */
60           nmbuf[1] = lex.d.pero;        /* Prefix PERO to name. */
61           parmsw = 1;                   /* Indicate parameter entity. */
62      case NAS:
63           break;
64      case RNS:           /* Reserved name started. */
65           if (ustrcmp(nmbuf+1, key[KDEFAULT])) {
66                mderr(118, nmbuf+1, key[KDEFAULT]);
67                return;
68           }
69           memcpy(nmbuf, indefent, *indefent);/* Copy #DEFAULT to name buffer. */
70           fpis = &fpidf;                /* Use #DEFAULT fpi if external. */
71           defltsw = 1;                  /* Indicate #DEFAULT is being defined.*/
72           break;
73      default:
74           mderr(122, (UNCH *)0, (UNCH *)0);
75           return;
76      }
77      subdcl = nmbuf+1;                  /* Subject name for error messages. */
78      /* PARAMETER 2: Entity text keyword (optional).
79      */
80      pcbmd.newstate = 0;
81      parsemd(tbuf, NAMECASE, &pcblitp, LITLEN);
82      TRACEMD("2: keyword");
83      switch (pcbmd.action) {
84      case NAS:
85           if ((estore = (UNCH)mapsrch(enttab, tbuf+1))==0) {
86                estore = parmsw ? ESP : ESF;
87                pne = (PNE)rmalloc(NESZ);
88                if (mdextid(tbuf, fpis, nmbuf+1+parmsw, &estore, pne)==0)
89                     return;
90                if (defltsw) etx.x = NULL;
91                else if ((etx.x = entgen(&fpicb))==0) {
92                     if (parmsw)
93                          mderr(148, nmbuf+2, (UNCH *)0);
94                     else
95                          mderr(147, nmbuf+1, (UNCH *)0);
96                }
97                goto parm4;
98           }
99           if (parmsw && (estore==ESX || estore==ESC)) {
100                mderr(38, tbuf+1, (UNCH *)0);
101                estore = ESM;
102           }
103           pcbmd.newstate = 0;
104           parsemd(tbuf, NAMECASE, &pcblitp, LITLEN);
105           break;
106      default:
107           estore = ESM;
108           break;
109      }
110      /* PARAMETER 3: Parameter literal.
111      */
112      TRACEMD("3: literal");
113      switch (pcbmd.action) {
114      case LITE:
115      case LIT:
116           switch (estore) {
117           case ESM:           /* LITERAL: parameter literal required. */
118           case ESC:           /* CDATA: parameter literal required. */
119           case ESX:           /* SDATA: parameter literal required. */
120           case ESI:           /* PI: parameter literal required. */
121                etx.c = savestr(tbuf);
122                break;
123           case ESMD:          /* MD: parameter literal required. */
124                etx.c = sandwich(tbuf, lex.m.mdo, lex.m.mdc); 
125                goto bcheck;
126           case ESMS:          /* MS: parameter literal required. */
127                etx.c = sandwich(tbuf, lex.m.mss, lex.m.mse);
128                goto bcheck;
129           case ESS:           /* STARTTAG: parameter literal required. */
130                etx.c = sandwich(tbuf, lex.m.stag, lex.m.tagc);
131                goto bcheck;
132           case ESE:           /* ENDTAG: parameter literal required. */
133                etx.c = sandwich(tbuf, lex.m.etag, lex.m.tagc);
134           bcheck:
135                if (etx.c == 0) {
136                     mderr(225, (UNCH *)0, (UNCH *)0);
137                     return;
138                }
139                break;
140           }
141           break;
142      default:
143           mderr(123, (UNCH *)0, (UNCH *)0);
144           return;
145      }
146      /* PARAMETER 4: End of declaration.
147      */
148      pcbmd.newstate = 0;
149      parsemd(tbuf, NAMECASE, &pcblitp, LITLEN);
150      parm4:
151      TRACEMD(emd);
152      if (pcbmd.action!=EMD) mderr(126, (UNCH *)0, (UNCH *)0);
153      if (es!=mdessv) synerr(37, &pcbmd);
154
155      /* EXECUTE: If the entity already exists, ignore the new definition.
156                  If it is a new entity, store the definition.
157      */
158      if ((ecb = entfind(nmbuf))!=0 && ecb->estore) {
159           if (ecb->dflt) {
160                mderr(228, nmbuf + 1, (UNCH *)0);
161                hout((THASH)etab, nmbuf, hash(nmbuf, ENTHASH));
162                if (ecb->estore == ESN) {
163                     frem((UNIV)NEID(ecb->etx.n));
164                     frem((UNIV)ecb->etx.n);
165                }
166                else if (ecb->estore >= ESFM)
167                     frem((UNIV)ecb->etx.x);
168                frem((UNIV)ecb);
169           }
170           else {
171                /* Duplicate definition: not an error. */
172                if (sw.swdupent) mderr(68, nmbuf+1, (UNCH *)0);
173                if (estore<ESFM) frem((UNIV)etx.c);
174                return;
175           }
176      }
177      ++ds.ecbcnt;                       /* Do capacity before NOTATION. */
178      ds.ecbtext += estore<ESFM ? ustrlen(etx.c) : entlen;
179      ecb = entdef(nmbuf, estore, &etx); /* Define the entity. */
180      if (estore==ESN) {                 /* If entity is external: */
181           NEENAME(pne) = ecb->ename;    /* Store entity name in ne. */
182           NEID(pne) = etx.x;            /* Store system fileid in ne. */
183           NESYSID(pne) = fpis->fpisysis ? savestr(fpis->fpisysis) : 0;
184           NEPUBID(pne) = fpis->fpipubis ? savestr(fpis->fpipubis) : 0;
185           ecb->etx.n = pne;             /* Store ne control block in etx. */
186           TRACEESN(pne);
187      }
188      else if (pne)
189           frem((UNIV)pne);
190      if (defltsw) {
191           ecbdeflt = ecb;     /* If #DEFAULT save ecb. */
192           if (fpidf.fpipubis)
193                fpidf.fpipubis = savestr(fpidf.fpipubis);
194           if (fpidf.fpisysis)
195                fpidf.fpisysis = savestr(fpidf.fpisysis);
196      }
197 }
198 /* SANDWICH: Catenate a prefix and suffix to a string.
199    The result has an EOS but no length.
200    Return 0 if the result if longer than LITLEN.
201 */
202 UNCH *sandwich(s, pref, suff)
203 UNCH *s;                      /* String, with EOS. */
204 UNCH *pref;                   /* Prefix, with length and EOS. */
205 UNCH *suff;                   /* Suffix, with length and EOS. */
206 {
207      UNCH *pt;
208      UNS slen, tlen;
209
210      slen = ustrlen(s);
211      tlen = slen + (*pref - 2) + (*suff - 2);
212      if (tlen > LITLEN)
213           return 0;
214      pt = (UNCH *)rmalloc(tlen + 1);
215      memcpy(pt, pref + 1, *pref - 2);
216      memcpy(pt + (*pref - 2), s, slen);
217      memcpy(pt + (*pref - 2) + slen, suff + 1, *suff - 1);
218      return pt;
219 }
220 /* MDEXTID: Process external identifier parameter of a markup declaration.
221             On entry, tbuf contains SYSTEM or PUBLIC if all is well.
222             NULL is returned if an error, otherwise fpis.  If it is a
223             valid external data entity, the caller's estore is set to ESN
224             and its nxetype is set to the code for the external entity type.
225             The event that terminated the parse is preserved in pcb.action,
226             so the caller should process it before further parsing.
227 */
228 struct fpi *mdextid(tbuf, fpis, ename, estore, pne)
229 UNCH *tbuf;                   /* Work area for tokenization[2*(LITLEN+2)]. */
230 struct fpi *fpis;             /* FPI structure. */
231 UNCH *ename;                  /* Entity or notation name, with EOS, no length.*/
232                               /* NOTE: No PERO on parameter entity name. */
233 UNCH *estore;                 /* DTD, general or parameter entity, DCN. */
234 PNE pne;                      /* Caller's external entity ptr. */
235 {
236      PDCB dcb;                /* Ptr to DCN control block. */
237      int exidtype;            /* External ID type: 0=none 1=system 2=public. */
238      int exetype;             /* External entity type. */
239
240      MEMZERO((UNIV)fpis, (UNS)FPISZ);     /* Initialize fpi structure. */
241      /* Move entity name into fpi (any PERO was stripped by caller). */
242      fpis->fpinm = ename;
243      entlen = 0;              /* Initialize external ID length. */
244
245      /* PARAMETER 1: External identifier keyword or error.
246      */
247      TRACEMD("1: extid keyword");
248      if ((exidtype = mapsrch(exttab, tbuf+1))==0) {
249           mderr(29, (UNCH *)0, (UNCH *)0);
250           return (struct fpi *)0;
251      }
252      if (exidtype==EDSYSTEM) goto parm3;
253
254      /* PARAMETER 2: Public ID literal.
255      */
256      pcbmd.newstate = 0;
257      /* The length of a minimum literal cannot exceed the value of LITLEN
258         in the reference quantity set. */
259      parsemd(pubibuf, NAMECASE, &pcblitv, REFLITLEN);
260      TRACEMD("2: pub ID literal");
261      switch (pcbmd.action) {
262      case LITE:               /* Use alternative literal delimiter. */
263      case LIT:                /* Save literal as public ID string. */
264           entlen = ustrlen(pubibuf);
265           fpis->fpipubis = pubibuf;
266           break;
267      default:
268           mderr(117, (UNCH *)0, (UNCH *)0);
269           return (struct fpi *)0;        /* Signal error to caller. */
270      }
271      /* PARAMETER 3: System ID literal.
272      */
273      parm3:
274      pcbmd.newstate = 0;
275      parsemd(sysibuf, NAMECASE, &pcblitc, LITLEN);
276      TRACEMD("3: sys ID literal");
277      if (pcbmd.action==LIT || pcbmd.action==LITE) {
278           entlen += ustrlen(sysibuf);
279           fpis->fpisysis = sysibuf;
280           pcbmd.newstate = 0;
281           parsemd(tbuf, NAMECASE, &pcblitp, LITLEN);
282      }
283      else memcpy(tbuf, sysibuf, *sysibuf);
284      if (*estore!=ESF || pcbmd.action!=NAS) goto genfpi;
285
286      /* PARAMETER 4: Entity type keyword.
287      */
288      TRACEMD("4: Entity type");
289      if ((exetype = mapsrch(extettab, tbuf+1))==0) {
290           mderr(24, tbuf+1, (UNCH *)0);
291           return (struct fpi *)0;
292      }
293      if (exetype==ESNSUB && SUBDOC == NO) {
294           mderr(90, tbuf+1, (UNCH *)0);
295           return (struct fpi *)0;
296      }
297
298      NEXTYPE(pne) = (UNCH)exetype; /* Save entity type in caller's ne. */
299      *estore = ESN;                /* Signal that entity is a data entity. */
300
301      if (exetype==ESNSUB) {
302           pne->nedcn = 0;
303           pcbmd.newstate = 0;           /* Parse next token for caller. */
304           parsemd(tbuf, NAMECASE, &pcblitp, LITLEN);
305           goto genfpi;
306      }
307      /* PARAMETER 5: Notation name.
308      */
309      pcbmd.newstate = 0;
310      parsemd(lbuf, NAMECASE, &pcblitp, NAMELEN);
311      TRACEMD("5: notation");
312      if (pcbmd.action!=NAS) {mderr(119, tbuf+1, (UNCH *)0); return (struct fpi *)0;}
313      /* Locate the data content notation. */
314      pne->nedcn = dcb = dcndef(lbuf);
315      /* Note that we have defined an entity with this notation.
316         If attributes are later defined for this notation, we'll
317         have to fix up this entity. */
318      dcb->entsw = 1;
319
320      /* PARAMETER 6: Data attribute specification.
321      */
322      pcbmd.newstate = 0;
323      parsemd(lbuf, NAMECASE, &pcblitp, NAMELEN);
324      TRACEMD("6: [att list]");
325      if (pcbmd.action!=MDS) {     /* No attributes specified. */
326           if (dcb->adl == 0)
327                NEAL(pne) = 0;
328           else {
329                initatt(dcb->adl);
330                adlval((int)ADN(al), (struct etd *)0);
331                storedatt(pne);
332           }
333           goto genfpi;
334      }
335      if (dcb->adl==0) {            /* Atts specified, but none defined. */
336           mderr(22, (UNCH *)0, (UNCH *)0);
337           return (struct fpi *)0;
338      }
339      pcbstag.newstate = pcbstan;   /* First separator is optional. */
340      if ((parseatt(dcb->adl, tbuf))==0)/* Empty list. */
341           mderr(91, (UNCH *)0, (UNCH *)0);
342      else {
343           adlval((int)ADN(al), (struct etd *)0);
344           storedatt(pne);
345      }
346      parse(&pcbeal);               /* Parse the list ending. */
347      pcbmd.newstate = 0;           /* Parse next token for caller. */
348      parsemd(tbuf, NAMECASE, &pcblitp, LITLEN);
349
350      /* GENFPI: Builds a formal public identifier structure, including the
351                 entity name, offsets of the components of the public ID, and
352                 other data a system might use to identify the actual file.
353      */
354  genfpi:
355      TRACEMD("7: generate fpi");
356      fpis->fpistore = *estore - ESFM + 1;    /* External entity type: 1-6. */
357      if (*estore == ESN) {
358           if (NEXTYPE(pne) == ESNSUB)
359                fpis->fpinedcn = 0;
360           else
361                fpis->fpinedcn = NEDCN(pne) + 1;
362      }
363      /* Analyze public ID and make structure entries. */
364      if (exidtype==EDPUBLIC) {
365           if (FORMAL==NO)
366                fpis->fpiversw = -1;
367           else if (parsefpi(fpis)>0) {
368                mderr(88, fpis->fpipubis, (UNCH *)0);
369                fpis->fpiversw = -1; /* Signal bad formal public ID. */
370           }
371      }
372      return fpis;
373 }
374
375 /* Store a data attribute. */
376
377 VOID storedatt(pne)
378 PNE pne;
379 {
380      int i;
381      
382      NEAL(pne) = (struct ad *)rmalloc((1+ADN(al))*ADSZ);
383      memcpy((UNIV)NEAL(pne), (UNIV)al, (1+ADN(al))*ADSZ);
384      for (i = 1; i <= (int)ADN(al); i++) {
385           if (GET(ADFLAGS(al, i), ASPEC))
386                ds.attdef += ADLEN(al, i);
387           if (NEAL(pne)[i].addef != 0)
388                NEAL(pne)[i].addef = savestr(NEAL(pne)[i].addef);
389      }
390      ds.attcnt += AN(al);     /* Number of attributes defined. */
391 #if 0
392      /* I can't see any reason to increase AVGRPCNT here. */
393      ds.attgcnt += ADN(al) - AN(al); /* Number of att grp members. */
394 #endif
395 }
396
397 /* PARSEFPI: Parses a formal public identifier and builds a control block.
398              PARSEFPI returns a positive error code (1-10), or 0 if no errors.
399              It set fpiversw if no version was specified in the ID and the
400              public text is in a class that permits display versions.
401              Note: An empty version ("//") can be specified (usually it is
402              the non-device-specific form, such as a definitional entity set).
403 */
404 int parsefpi(f)
405 PFPI f;                       /* Ptr to formal public identifier structure. */
406 {
407      UNCH *l;                 /* Pointer to EOS of public identifier. */
408      UNCH *p, *q;             /* Ptrs to current field in public identifier. */
409      UNS len;                 /* Field length */
410
411      p = f->fpipubis;                   /* Point to start of identifier. */
412      l = p + ustrlen(p);                /* Point to EOS of identifier. */
413      if (*p=='+' || *p=='-') {          /* If owner registered, unregistered. */
414           f->fpiot = *p;                /* Save owner type. */
415           if ((p += 3)>=l) return 1;    /* Get to owner ID field. */
416      }
417      else f->fpiot = '!';               /* Indicate ISO owner identifier. */
418      if ((q = pubfield(p, l, '/', &len))==0)  /* Find end of owner ID field. */
419           return 2;
420      f->fpiol = len;                    /* Save owner ID length. */
421      f->fpio = p - f->fpipubis;         /* Save offset in pubis to owner ID. */
422
423      if ((p = pubfield(q, l, ' ', &len))==0)  /* Find end of text class field. */
424           return 3;
425      *(--p) = EOS;                      /* Temporarily make class a string. */
426      f->fpic = mapsrch(pubcltab, q);    /* Check for valid uc class name.*/
427      *p++ = ' ';                        /* Restore the SPACE delimiter. */
428      if (f->fpic==0) return 4;          /* Error if not valid uc class name.*/
429
430      /* The public text class in a notation identifier must be NOTATION. */
431      if (f->fpistore == ESK - ESFM + 1 && f->fpic != FPINOT) return 10;
432
433      if (*p=='-') {                     /* If text is unavailable public text.*/
434           f->fpitt = *p;                /* Save text type. */
435           if ((p += 3)>=l) return 5;    /* Get to text description field. */
436      }
437      else f->fpitt = '+';               /* Indicate available public text. */
438      if ((q = pubfield(p, l, '/', &len))==0)  /* Find end of text description. */
439           return 6;
440      f->fpitl = len;                    /* Save text description length. */
441      f->fpit = p - f->fpipubis;         /* Save ptr to description.*/
442
443      p = pubfield(q, l, '/', &len);     /* Bound language field. */
444      if (f->fpic != FPICHARS) {
445           int i;
446           /* Language must be all upper-case letters. */
447           /* The standard only says that it *should* be two letters, so
448              don't enforce that. */
449           for (i = 0; i < len; i++) {
450               /* Don't assume ASCII. */  
451                if (!strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ", q[i]))
452                     return 7;
453           }
454      }
455      f->fpill = len;
456      f->fpil = q - f->fpipubis;
457      if (p!=0) {                        /* If there is a version field: */
458           if (f->fpic<FPICMINV)         /* Error if class prohibits versions. */
459                return 8;
460           if ((pubfield(p, l, '/', &len))!=0) /* Bound version field. */
461                return 9;                /* Error if yet another field. */
462           f->fpivl = len;               /* Save version length. */
463           f->fpiv = p - f->fpipubis;    /* Save ptr (in pubis) to version. */
464      }
465      else if (f->fpic>=FPICMINV) f->fpiversw = 1;/* No version: get the best. */
466      return(0);
467 }
468 /* PUBFIELD: Returns ptr to next field, or NULL if ID has ended.
469 */
470 #ifdef USE_PROTOTYPES
471 UNCH *pubfield(UNCH *p, UNCH *l, UNCH d, UNS *lenp)
472 #else
473 UNCH *pubfield(p, l, d, lenp)
474 UNCH *p;                      /* Public identifier field (no length or EOS). */
475 UNCH *l;                      /* Pointer to EOS of public identifier. */
476 UNCH d;                       /* Field delimiter: ' ' or '/'. */
477 UNS *lenp;                    /* Gets field length */
478 #endif
479 {
480      UNCH *psv = p+1;         /* Save starting value of p. */
481
482      while (p<l) {
483           if (*p++==d) {              /* Test for delimiter character. */
484                *lenp = p - psv;       /* Save field length (no len or EOS). */
485                if (d=='/' && *p++!=d) /* Solidus requires a second one. */
486                     continue;
487                return(p);             /* Return ptr to next field. */
488           }
489      }
490      *lenp = p - --psv;      /* Save field length (no len or EOS). */
491      return NULL;
492 }
493 /* MDMS: Process marked section start.
494          If already in special parse, bump the level counters and return
495          without parsing the declaration.
496 */
497 struct parse *mdms(tbuf, pcb)
498 UNCH *tbuf;                   /* Work area for tokenization [NAMELEN+2]. */
499 struct parse *pcb;            /* Parse control block for this parse. */
500 {
501      int key;                 /* Index of keyword in mslist. */
502      int ptype;               /* Parameter token type. */
503      int pcbcode = 0;         /* Parse code: 0=same; 2-4 per defines. */
504
505      if (++mslevel>TAGLVL) {
506           --mslevel;
507           sgmlerr(27, (struct parse *)0, ntoa(TAGLVL), (UNCH *)0);
508      }
509
510      /* If already in IGNORE mode, return without parsing parameters. */
511      if (msplevel) {++msplevel; return(pcb);}
512
513      parmno = 0;                   /* No parameters as yet. */
514      mdessv = es;                  /* Save es for checking entity nesting. */
515      pcbmd.newstate = pcbmdtk;     /* First separator is optional. */
516
517      /* PARAMETERS: TEMP, RCDATA, CDATA, IGNORE, INCLUDE, or MDS. */
518      while ((ptype = parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN))==NAS){
519           if ((key = mapsrch(mstab, tbuf+1))==0) {
520                sgmlerr(64, (struct parse *)0, ntoa(parmno), tbuf+1);
521                continue;
522           }
523           if (key==MSTEMP) continue;       /* TEMP: for documentation. */
524           msplevel = 1;                    /* Special parse required. */
525           if (key>pcbcode) pcbcode = key;  /* Update if higher priority. */
526      }
527      if (ptype!=MDS) {
528           NEWCC;                           /* Syntax error did REPEATCC. */
529           sgmlerr(97, (struct parse *)0, lex.m.dso, (UNCH *)0);
530           REPEATCC;                        /* 1st char of marked section. */
531      }
532      if (es!=mdessv) synerr(37, pcb);
533      TRACEMS(1, pcbcode, mslevel, msplevel);
534      if (pcbcode==MSIGNORE) pcb = &pcbmsi;
535      else if (pcbcode) {
536           pcb = pcbcode==MSCDATA  ? &pcbmsc : (rcessv = es, &pcbmsrc);
537      }
538      return(pcb);              /* Tell caller whether to change the parse. */
539 }
540 /* MDMSE: Process marked section end.
541           Issue an error if no marked section had started.
542 */
543 int mdmse()
544 {
545      int retcode = 0;         /* Return code: 0=same parse; 1=cancel special. */
546
547      if (mslevel) --mslevel;
548      else sgmlerr(26, (struct parse *)0, (UNCH *)0, (UNCH *)0);
549
550      if (msplevel) if (--msplevel==0) retcode = 1;
551      TRACEMS(0, retcode, mslevel, msplevel);
552      return retcode;
553 }
554 /* MDNOT: Process NOTATION declaration.
555 */
556 VOID mdnot(tbuf)
557 UNCH *tbuf;                   /* Work area for tokenization[LITLEN+2]. */
558 {
559      struct fpi fpicb;        /* Formal public identifier structure. */
560      PDCB dcb;                /* Ptr to notation entity in dcntab. */
561      UNCH estore = ESK;       /* Entity storage class. */
562
563      mdname = key[KNOTATION]; /* Identify declaration for messages. */
564      subdcl = NULL;           /* No subject as yet. */
565      parmno = 0;              /* No parameters as yet. */
566      mdessv = es;             /* Save es for checking entity nesting. */
567
568      /* PARAMETER 1: Notation name.
569      */
570      pcbmd.newstate = 0;
571      parsemd(lbuf, NAMECASE, &pcblitp, NAMELEN);
572      TRACEMD("1: name");
573      if (pcbmd.action!=NAS) {mderr(120, (UNCH *)0, (UNCH *)0); return;}
574      subdcl = lbuf+1;         /* Save notation name for error msgs. */
575
576      /* PARAMETER 2: External identifier keyword.
577      */
578      pcbmd.newstate = 0;
579      parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
580      TRACEMD("2: extid");
581      if (pcbmd.action!=NAS) {mderr(29, (UNCH *)0, (UNCH *)0); return;}
582      if (mdextid(tbuf, &fpicb, lbuf+1, &estore, (PNE)0)==0) return;
583
584      /* PARAMETER 3: End of declaration.
585                      Token was parsed by MDEXTID.
586      */
587      TRACEMD(emd);
588      if (pcbmd.action!=EMD) mderr(126, (UNCH *)0, (UNCH *)0);
589      if (es!=mdessv) synerr(37, &pcbmd);
590
591      /* EXECUTE: Store notation name.
592      */
593      if ((dcb = dcnfind(lbuf)) != 0 && dcb->defined) {
594           mderr(56, lbuf+1, (UNCH *)0);
595           return;
596      }
597      /* else */
598      dcb = dcndef(lbuf);
599      dcb->defined = 1;
600      dcb->sysid = fpicb.fpisysis ? savestr(fpicb.fpisysis) : 0;
601      dcb->pubid = fpicb.fpipubis ? savestr(fpicb.fpipubis) : 0;
602      ++ds.dcncnt;
603      ds.dcntext += entlen;
604      TRACEDCN(dcb);
605      return;
606 }
607 /* DCNDEF: Define a notation and return its DCNCB.
608            If caller does not care if it already exists,
609            he should specify NULL for the notation text
610            so we don't clobber the existing text (if any).
611 */
612 struct dcncb *dcndef(nname)
613 UNCH *nname;                  /* Notation name (with length and EOS). */
614 {
615      return((PDCB)hin((THASH)dcntab, nname, 0, DCBSZ));
616 }
617 /* DCNFIND: If a notation was declared, return its DCNCB.
618             Return NULL if it is not defined.
619 */
620 struct dcncb *dcnfind(nname)
621 UNCH *nname;                  /* Notation name (with length and EOS). */
622 {
623      return((PDCB)hfind((THASH)dcntab, nname, 0));
624 }
625 #define SRM(i) (srhptr->srhsrm[i]) /* Current entry in SHORTREF map. */
626 /* MDSRMDEF: Process short reference mapping declaration.
627 */
628 VOID mdsrmdef(tbuf)
629 UNCH *tbuf;                   /* Work area for tokenization[LITLEN+2]. */
630 {
631      struct entity *entcb;    /* Ptr to defined entity. */
632      PSRH srhptr;             /* Ptr to short reference map hdr (in srhtab).*/
633      int srn;                 /* Short reference delimiter number in srdeltab.*/
634      int mapused = 0;         /* Has map already been used? */
635
636      mdname = key[KSHORTREF]; /* Identify declaration for messages. */
637      subdcl = NULL;           /* No subject as yet. */
638      parmno = 0;              /* No parameters as yet. */
639      if (!sd.shortref) {mderr(198, (UNCH *)0, (UNCH *)0); return;}
640      mdessv = es;             /* Save es for checking entity nesting. */
641      /* PARAMETER 1: SHORTREF map name.
642      */
643      pcbmd.newstate = 0;
644      parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
645      TRACEMD("1: map nm");
646      if (pcbmd.action!=NAS) {mderr(120, (UNCH *)0, (UNCH *)0); return;}
647      if ((srhptr = srhfind(tbuf))!=0) {
648           mapused = 1;
649           /* Error if map was declared (not just used). */
650           if (SRM(0)) {mderr(56, tbuf+1, (UNCH *)0); return;}
651      }
652      else srhptr = srhdef(tbuf);  /* Create map with SRs mapped to NULL.*/
653      SRM(0) = (PECB)srhptr;       /* Indicate map was actually declared.*/
654      subdcl = srhptr->ename+1;    /* Save map name for error msgs. */
655
656      while ( pcbmd.newstate = 0,
657              parsemd(tbuf, NAMECASE, &pcblitp, SRMAXLEN)==LIT
658           || pcbmd.action==LITE ) {
659           /* PARAMETER 2: Delimiter string.
660           */
661           TRACEMD("2: SR string");
662           if ((srn = mapsrch(lex.s.dtb, tbuf))==0) {
663                mderr(124, tbuf, (UNCH *)0);
664                goto cleanup;
665           }
666           /* PARAMETER 3: Entity name.
667           */
668           pcbmd.newstate = 0;
669           parsemd(tbuf, ENTCASE, &pcblitp, NAMELEN);
670           TRACEMD("3: entity");
671           if (pcbmd.action!=NAS) {mderr(120, (UNCH *)0, (UNCH *)0); goto cleanup;}
672           if ((entcb = entfind(tbuf))==0) {
673                union etext etx;
674                etx.x = 0;
675                entcb = entdef(tbuf, '\0', &etx);
676           }
677           if (SRM(srn)) {
678                mderr(56, (srn<lex.s.prtmin ? (UNCH *)lex.s.pdtb[srn]
679                                        : lex.s.dtb[srn].mapnm), (UNCH *)0);
680                continue;
681           }
682           SRM(srn) = entcb;
683           if (srn>=lex.s.fce && srn!=lex.s.hyp && srn!=lex.s.hyp2
684               && srn!=lex.s.lbr && srn!=lex.s.rbr)
685                lexcnm[*lex.s.dtb[srn].mapnm] = lex.l.fce;
686           else if (srn==lex.s.spc) lexcnm[' '] = lex.l.spcr;
687      }
688      /* PARAMETER 4: End of declaration.
689      */
690      TRACEMD(emd);
691      if (parmno==2)
692           {mderr((UNS)(pcbmd.action==EMD ? 28:123), (UNCH *)0, (UNCH *)0); goto cleanup;}
693      if (pcbmd.action!=EMD) mderr(126, (UNCH *)0, (UNCH *)0);
694      if (es!=mdessv) synerr(37, &pcbmd);
695      ++ds.srcnt;
696      TRACESRM("SHORTREF", srhptr->srhsrm, (UNCH *)0);
697      return;
698
699  cleanup:
700      /* Don't free the map if the map was in use (because of a USEMAP
701         declaration) before this declaration. */
702      if (mapused)
703           MEMZERO((UNIV)srhptr->srhsrm, sizeof(PECB)*(lex.s.dtb[0].mapdata+1));
704      else {
705           frem((UNIV)srhptr->srhsrm);
706           hout((THASH)srhtab, srhptr->ename, 0);
707           frem((UNIV)srhptr);
708      }
709 }
710 /* MDSRMUSE: Activate a short reference map.
711 */
712 VOID mdsrmuse(tbuf)
713 UNCH *tbuf;                   /* Work area for tokenization[LITLEN+2]. */
714 {
715      PSRH srhptr;             /* Ptr to short reference map hdr (in srhtab).*/
716      TECB srmptr;             /* Ptr to short reference map (in header). */
717      int i;                   /* Loop counter; temporary variable. */
718
719      mdname = key[KUSEMAP];   /* Identify declaration for messages. */
720      subdcl = NULL;           /* No subject as yet. */
721      parmno = 0;              /* No parameters as yet. */
722      mdessv = es;             /* Save es for checking entity nesting. */
723      /* PARAMETER 1: SHORTREF map name or "#EMPTY".
724      */
725      pcbmd.newstate = 0;
726      parsemd(lbuf, NAMECASE, &pcblitp, NAMELEN);
727      TRACEMD("1: map nm");
728      subdcl = lbuf+1;           /* Subject name for error messages. */
729      switch (pcbmd.action) {
730      case RNS:                /* Empty SHORTREF map requested. */
731           if (ustrcmp(lbuf+1, key[KEMPTY])) {
732                mderr(118, lbuf+1, key[KEMPTY]);
733                return;
734           }
735           srmptr = SRMNULL;
736           break;
737      case NAS:                /* Map name specified; save if undefined. */
738           if ((srhptr = srhfind(lbuf))==0) {
739                if (!indtdsw) {mderr(125, (UNCH *)0, (UNCH *)0); return;}
740                srmptr = NULL;
741           }
742           else
743                srmptr = srhptr->srhsrm;
744           break;
745      default:
746           mderr(120, (UNCH *)0, (UNCH *)0);
747           return;
748      }
749      /* PARAMETER 2: Element name or a group of them. (In DTD only.)
750      */
751      pcbmd.newstate = 0;
752      parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
753      TRACEMD("2: GI or grp");
754      switch (pcbmd.action) {
755      case NAS:
756           if (!indtdsw) {mderr(142, (UNCH *)0, (UNCH *)0); return;}
757           nmgrp[0] = etddef(tbuf);
758           nmgrp[1] = (PETD)NULL;
759           break;
760      case GRPS:
761           if (!indtdsw) {mderr(142, (UNCH *)0, (UNCH *)0); return;}
762           parsegrp(nmgrp, &pcbgrnm, tbuf);
763           break;
764      case EMD:
765           if (indtdsw) {mderr(28, (UNCH *)0, (UNCH *)0); return;}
766           tags[ts].tsrm = srmptr;
767           TRACESRM("USEMAP", tags[ts].tsrm, tags[ts].tetd->etdgi+1);
768           goto realemd;
769      default:
770           mderr(indtdsw ? 121 : 126, (UNCH *)0, (UNCH *)0);
771           return;
772      }
773      /* PARAMETER 3: End of declaration.
774      */
775      pcbmd.newstate = 0;
776      parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
777      TRACEMD(emd);
778      if (pcbmd.action!=EMD) mderr(126, (UNCH *)0, (UNCH *)0);
779      /* If map has not yet been defined, do it and get map pointer. */
780      if (!srmptr) srmptr = (srhdef(lbuf))->srhsrm;
781
782      /* Store the map pointer for each element name specified.
783      */
784      TRACEGRP(nmgrp);
785      for (i = -1; nmgrp[++i];) {
786           if (!nmgrp[i]->etdsrm) nmgrp[i]->etdsrm = srmptr;
787           else if (sw.swdupent) mderr(68, nmgrp[i]->etdgi+1, (UNCH *)0);
788      }
789      realemd:
790      if (es!=mdessv) synerr(37, &pcbmd);
791 }
792 /* SRHDEF: Define a SHORTREF map and return ptr to its header.
793            All entries in map are mapped to NULL.
794            Caller must determine whether it already exists.
795 */
796 PSRH srhdef(sname)
797 UNCH *sname;                  /* SHORTREF map name (with length and EOS). */
798 {
799      PSRH srh;                /* Ptr to SHORTREF map hdr in srhtab. */
800
801      (srh = (PSRH)hin((THASH)srhtab, sname, 0, SRHSZ))->srhsrm =
802           (TECB)rmalloc((UNS)(lex.s.dtb[0].mapdata+1)*sizeof(PECB));
803      return(srh);
804 }
805 /* SRHFIND: If a SHORTREF map was declared, return the ptr to its header.
806             Return NULL if it is not defined.
807 */
808 PSRH srhfind(sname)
809 UNCH *sname;                  /* SHORTREF map name (with length and EOS). */
810 {
811      return((PSRH)hfind((THASH)srhtab, sname, 0));
812 }
813 #undef SRM
814
815 /*
816 Local Variables:
817 c-indent-level: 5
818 c-continued-statement-offset: 5
819 c-brace-offset: -5
820 c-argdecl-indent: 0
821 c-label-offset: -5
822 comment-column: 30
823 End:
824 */