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: 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.
28 UNCH *tbuf; /* Work area for tokenization[LITLEN+2]. */
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. */
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.
46 parsemd(nmbuf, ENTCASE, &pcblitp, NAMELEN);
47 TRACEMD("1: entity nm");
48 switch (pcbmd.action) {
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);
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. */
64 case RNS: /* Reserved name started. */
65 if (ustrcmp(nmbuf+1, key[KDEFAULT])) {
66 mderr(118, nmbuf+1, key[KDEFAULT]);
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.*/
74 mderr(122, (UNCH *)0, (UNCH *)0);
77 subdcl = nmbuf+1; /* Subject name for error messages. */
78 /* PARAMETER 2: Entity text keyword (optional).
81 parsemd(tbuf, NAMECASE, &pcblitp, LITLEN);
82 TRACEMD("2: keyword");
83 switch (pcbmd.action) {
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)
90 if (defltsw) etx.x = NULL;
91 else if ((etx.x = entgen(&fpicb))==0) {
93 mderr(148, nmbuf+2, (UNCH *)0);
95 mderr(147, nmbuf+1, (UNCH *)0);
99 if (parmsw && (estore==ESX || estore==ESC)) {
100 mderr(38, tbuf+1, (UNCH *)0);
104 parsemd(tbuf, NAMECASE, &pcblitp, LITLEN);
110 /* PARAMETER 3: Parameter literal.
112 TRACEMD("3: literal");
113 switch (pcbmd.action) {
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);
123 case ESMD: /* MD: parameter literal required. */
124 etx.c = sandwich(tbuf, lex.m.mdo, lex.m.mdc);
126 case ESMS: /* MS: parameter literal required. */
127 etx.c = sandwich(tbuf, lex.m.mss, lex.m.mse);
129 case ESS: /* STARTTAG: parameter literal required. */
130 etx.c = sandwich(tbuf, lex.m.stag, lex.m.tagc);
132 case ESE: /* ENDTAG: parameter literal required. */
133 etx.c = sandwich(tbuf, lex.m.etag, lex.m.tagc);
136 mderr(225, (UNCH *)0, (UNCH *)0);
143 mderr(123, (UNCH *)0, (UNCH *)0);
146 /* PARAMETER 4: End of declaration.
149 parsemd(tbuf, NAMECASE, &pcblitp, LITLEN);
152 if (pcbmd.action!=EMD) mderr(126, (UNCH *)0, (UNCH *)0);
153 if (es!=mdessv) synerr(37, &pcbmd);
155 /* EXECUTE: If the entity already exists, ignore the new definition.
156 If it is a new entity, store the definition.
158 if ((ecb = entfind(nmbuf))!=0 && ecb->estore) {
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);
166 else if (ecb->estore >= ESFM)
167 frem((UNIV)ecb->etx.x);
171 /* Duplicate definition: not an error. */
172 if (sw.swdupent) mderr(68, nmbuf+1, (UNCH *)0);
173 if (estore<ESFM) frem((UNIV)etx.c);
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. */
191 ecbdeflt = ecb; /* If #DEFAULT save ecb. */
193 fpidf.fpipubis = savestr(fpidf.fpipubis);
195 fpidf.fpisysis = savestr(fpidf.fpisysis);
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.
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. */
211 tlen = slen + (*pref - 2) + (*suff - 2);
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);
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.
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. */
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. */
240 MEMZERO((UNIV)fpis, (UNS)FPISZ); /* Initialize fpi structure. */
241 /* Move entity name into fpi (any PERO was stripped by caller). */
243 entlen = 0; /* Initialize external ID length. */
245 /* PARAMETER 1: External identifier keyword or error.
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;
252 if (exidtype==EDSYSTEM) goto parm3;
254 /* PARAMETER 2: Public ID literal.
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;
268 mderr(117, (UNCH *)0, (UNCH *)0);
269 return (struct fpi *)0; /* Signal error to caller. */
271 /* PARAMETER 3: System ID literal.
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;
281 parsemd(tbuf, NAMECASE, &pcblitp, LITLEN);
283 else memcpy(tbuf, sysibuf, *sysibuf);
284 if (*estore!=ESF || pcbmd.action!=NAS) goto genfpi;
286 /* PARAMETER 4: Entity type keyword.
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;
293 if (exetype==ESNSUB && SUBDOC == NO) {
294 mderr(90, tbuf+1, (UNCH *)0);
295 return (struct fpi *)0;
298 NEXTYPE(pne) = (UNCH)exetype; /* Save entity type in caller's ne. */
299 *estore = ESN; /* Signal that entity is a data entity. */
301 if (exetype==ESNSUB) {
303 pcbmd.newstate = 0; /* Parse next token for caller. */
304 parsemd(tbuf, NAMECASE, &pcblitp, LITLEN);
307 /* PARAMETER 5: Notation name.
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. */
320 /* PARAMETER 6: Data attribute specification.
323 parsemd(lbuf, NAMECASE, &pcblitp, NAMELEN);
324 TRACEMD("6: [att list]");
325 if (pcbmd.action!=MDS) { /* No attributes specified. */
330 adlval((int)ADN(al), (struct etd *)0);
335 if (dcb->adl==0) { /* Atts specified, but none defined. */
336 mderr(22, (UNCH *)0, (UNCH *)0);
337 return (struct fpi *)0;
339 pcbstag.newstate = pcbstan; /* First separator is optional. */
340 if ((parseatt(dcb->adl, tbuf))==0)/* Empty list. */
341 mderr(91, (UNCH *)0, (UNCH *)0);
343 adlval((int)ADN(al), (struct etd *)0);
346 parse(&pcbeal); /* Parse the list ending. */
347 pcbmd.newstate = 0; /* Parse next token for caller. */
348 parsemd(tbuf, NAMECASE, &pcblitp, LITLEN);
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.
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)
361 fpis->fpinedcn = NEDCN(pne) + 1;
363 /* Analyze public ID and make structure entries. */
364 if (exidtype==EDPUBLIC) {
367 else if (parsefpi(fpis)>0) {
368 mderr(88, fpis->fpipubis, (UNCH *)0);
369 fpis->fpiversw = -1; /* Signal bad formal public ID. */
375 /* Store a data attribute. */
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);
390 ds.attcnt += AN(al); /* Number of attributes defined. */
392 /* I can't see any reason to increase AVGRPCNT here. */
393 ds.attgcnt += ADN(al) - AN(al); /* Number of att grp members. */
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).
405 PFPI f; /* Ptr to formal public identifier structure. */
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 */
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. */
417 else f->fpiot = '!'; /* Indicate ISO owner identifier. */
418 if ((q = pubfield(p, l, '/', &len))==0) /* Find end of owner ID field. */
420 f->fpiol = len; /* Save owner ID length. */
421 f->fpio = p - f->fpipubis; /* Save offset in pubis to owner ID. */
423 if ((p = pubfield(q, l, ' ', &len))==0) /* Find end of text class field. */
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.*/
430 /* The public text class in a notation identifier must be NOTATION. */
431 if (f->fpistore == ESK - ESFM + 1 && f->fpic != FPINOT) return 10;
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. */
437 else f->fpitt = '+'; /* Indicate available public text. */
438 if ((q = pubfield(p, l, '/', &len))==0) /* Find end of text description. */
440 f->fpitl = len; /* Save text description length. */
441 f->fpit = p - f->fpipubis; /* Save ptr to description.*/
443 p = pubfield(q, l, '/', &len); /* Bound language field. */
444 if (f->fpic != FPICHARS) {
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]))
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. */
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. */
465 else if (f->fpic>=FPICMINV) f->fpiversw = 1;/* No version: get the best. */
468 /* PUBFIELD: Returns ptr to next field, or NULL if ID has ended.
470 #ifdef USE_PROTOTYPES
471 UNCH *pubfield(UNCH *p, UNCH *l, UNCH d, UNS *lenp)
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 */
480 UNCH *psv = p+1; /* Save starting value of p. */
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. */
487 return(p); /* Return ptr to next field. */
490 *lenp = p - --psv; /* Save field length (no len or EOS). */
493 /* MDMS: Process marked section start.
494 If already in special parse, bump the level counters and return
495 without parsing the declaration.
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. */
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. */
505 if (++mslevel>TAGLVL) {
507 sgmlerr(27, (struct parse *)0, ntoa(TAGLVL), (UNCH *)0);
510 /* If already in IGNORE mode, return without parsing parameters. */
511 if (msplevel) {++msplevel; return(pcb);}
513 parmno = 0; /* No parameters as yet. */
514 mdessv = es; /* Save es for checking entity nesting. */
515 pcbmd.newstate = pcbmdtk; /* First separator is optional. */
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);
523 if (key==MSTEMP) continue; /* TEMP: for documentation. */
524 msplevel = 1; /* Special parse required. */
525 if (key>pcbcode) pcbcode = key; /* Update if higher priority. */
528 NEWCC; /* Syntax error did REPEATCC. */
529 sgmlerr(97, (struct parse *)0, lex.m.dso, (UNCH *)0);
530 REPEATCC; /* 1st char of marked section. */
532 if (es!=mdessv) synerr(37, pcb);
533 TRACEMS(1, pcbcode, mslevel, msplevel);
534 if (pcbcode==MSIGNORE) pcb = &pcbmsi;
536 pcb = pcbcode==MSCDATA ? &pcbmsc : (rcessv = es, &pcbmsrc);
538 return(pcb); /* Tell caller whether to change the parse. */
540 /* MDMSE: Process marked section end.
541 Issue an error if no marked section had started.
545 int retcode = 0; /* Return code: 0=same parse; 1=cancel special. */
547 if (mslevel) --mslevel;
548 else sgmlerr(26, (struct parse *)0, (UNCH *)0, (UNCH *)0);
550 if (msplevel) if (--msplevel==0) retcode = 1;
551 TRACEMS(0, retcode, mslevel, msplevel);
554 /* MDNOT: Process NOTATION declaration.
557 UNCH *tbuf; /* Work area for tokenization[LITLEN+2]. */
559 struct fpi fpicb; /* Formal public identifier structure. */
560 PDCB dcb; /* Ptr to notation entity in dcntab. */
561 UNCH estore = ESK; /* Entity storage class. */
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. */
568 /* PARAMETER 1: Notation name.
571 parsemd(lbuf, NAMECASE, &pcblitp, NAMELEN);
573 if (pcbmd.action!=NAS) {mderr(120, (UNCH *)0, (UNCH *)0); return;}
574 subdcl = lbuf+1; /* Save notation name for error msgs. */
576 /* PARAMETER 2: External identifier keyword.
579 parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
581 if (pcbmd.action!=NAS) {mderr(29, (UNCH *)0, (UNCH *)0); return;}
582 if (mdextid(tbuf, &fpicb, lbuf+1, &estore, (PNE)0)==0) return;
584 /* PARAMETER 3: End of declaration.
585 Token was parsed by MDEXTID.
588 if (pcbmd.action!=EMD) mderr(126, (UNCH *)0, (UNCH *)0);
589 if (es!=mdessv) synerr(37, &pcbmd);
591 /* EXECUTE: Store notation name.
593 if ((dcb = dcnfind(lbuf)) != 0 && dcb->defined) {
594 mderr(56, lbuf+1, (UNCH *)0);
600 dcb->sysid = fpicb.fpisysis ? savestr(fpicb.fpisysis) : 0;
601 dcb->pubid = fpicb.fpipubis ? savestr(fpicb.fpipubis) : 0;
603 ds.dcntext += entlen;
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).
612 struct dcncb *dcndef(nname)
613 UNCH *nname; /* Notation name (with length and EOS). */
615 return((PDCB)hin((THASH)dcntab, nname, 0, DCBSZ));
617 /* DCNFIND: If a notation was declared, return its DCNCB.
618 Return NULL if it is not defined.
620 struct dcncb *dcnfind(nname)
621 UNCH *nname; /* Notation name (with length and EOS). */
623 return((PDCB)hfind((THASH)dcntab, nname, 0));
625 #define SRM(i) (srhptr->srhsrm[i]) /* Current entry in SHORTREF map. */
626 /* MDSRMDEF: Process short reference mapping declaration.
629 UNCH *tbuf; /* Work area for tokenization[LITLEN+2]. */
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? */
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.
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) {
649 /* Error if map was declared (not just used). */
650 if (SRM(0)) {mderr(56, tbuf+1, (UNCH *)0); return;}
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. */
656 while ( pcbmd.newstate = 0,
657 parsemd(tbuf, NAMECASE, &pcblitp, SRMAXLEN)==LIT
658 || pcbmd.action==LITE ) {
659 /* PARAMETER 2: Delimiter string.
661 TRACEMD("2: SR string");
662 if ((srn = mapsrch(lex.s.dtb, tbuf))==0) {
663 mderr(124, tbuf, (UNCH *)0);
666 /* PARAMETER 3: Entity name.
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) {
675 entcb = entdef(tbuf, '\0', &etx);
678 mderr(56, (srn<lex.s.prtmin ? (UNCH *)lex.s.pdtb[srn]
679 : lex.s.dtb[srn].mapnm), (UNCH *)0);
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;
688 /* PARAMETER 4: End of declaration.
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);
696 TRACESRM("SHORTREF", srhptr->srhsrm, (UNCH *)0);
700 /* Don't free the map if the map was in use (because of a USEMAP
701 declaration) before this declaration. */
703 MEMZERO((UNIV)srhptr->srhsrm, sizeof(PECB)*(lex.s.dtb[0].mapdata+1));
705 frem((UNIV)srhptr->srhsrm);
706 hout((THASH)srhtab, srhptr->ename, 0);
710 /* MDSRMUSE: Activate a short reference map.
713 UNCH *tbuf; /* Work area for tokenization[LITLEN+2]. */
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. */
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".
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]);
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;}
743 srmptr = srhptr->srhsrm;
746 mderr(120, (UNCH *)0, (UNCH *)0);
749 /* PARAMETER 2: Element name or a group of them. (In DTD only.)
752 parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
753 TRACEMD("2: GI or grp");
754 switch (pcbmd.action) {
756 if (!indtdsw) {mderr(142, (UNCH *)0, (UNCH *)0); return;}
757 nmgrp[0] = etddef(tbuf);
758 nmgrp[1] = (PETD)NULL;
761 if (!indtdsw) {mderr(142, (UNCH *)0, (UNCH *)0); return;}
762 parsegrp(nmgrp, &pcbgrnm, tbuf);
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);
770 mderr(indtdsw ? 121 : 126, (UNCH *)0, (UNCH *)0);
773 /* PARAMETER 3: End of declaration.
776 parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
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;
782 /* Store the map pointer for each element name specified.
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);
790 if (es!=mdessv) synerr(37, &pcbmd);
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.
797 UNCH *sname; /* SHORTREF map name (with length and EOS). */
799 PSRH srh; /* Ptr to SHORTREF map hdr in srhtab. */
801 (srh = (PSRH)hin((THASH)srhtab, sname, 0, SRHSZ))->srhsrm =
802 (TECB)rmalloc((UNS)(lex.s.dtb[0].mapdata+1)*sizeof(PECB));
805 /* SRHFIND: If a SHORTREF map was declared, return the ptr to its header.
806 Return NULL if it is not defined.
809 UNCH *sname; /* SHORTREF map name (with length and EOS). */
811 return((PSRH)hfind((THASH)srhtab, sname, 0));
818 c-continued-statement-offset: 5