886 lines
30 KiB
C
886 lines
30 KiB
C
/*
|
|
* CDE - Common Desktop Environment
|
|
*
|
|
* Copyright (c) 1993-2012, The Open Group. All rights reserved.
|
|
*
|
|
* These libraries and programs are free software; you can
|
|
* redistribute them and/or modify them under the terms of the GNU
|
|
* Lesser General Public License as published by the Free Software
|
|
* Foundation; either version 2 of the License, or (at your option)
|
|
* any later version.
|
|
*
|
|
* These libraries and programs are distributed in the hope that
|
|
* they will be useful, but WITHOUT ANY WARRANTY; without even the
|
|
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
* PURPOSE. See the GNU Lesser General Public License for more
|
|
* details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with these librararies and programs; if not, write
|
|
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
|
|
* Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
/* $XConsortium: md1.c /main/3 1996/06/19 17:16:08 drk $ */
|
|
#include "sgmlincl.h" /* #INCLUDE statements for SGML parser. */
|
|
/* MDADL: Process ATTLIST declaration.
|
|
*/
|
|
VOID mdadl(tbuf)
|
|
UNCH *tbuf; /* Work area for tokenization (tbuf). */
|
|
{
|
|
int i; /* Loop counter; temporary variable. */
|
|
int adlim; /* Number of unused ad slots in al. */
|
|
struct ad *alperm = 0; /* Attribute definition list. */
|
|
int stored = 0;
|
|
|
|
mdname = key[KATTLIST]; /* Identify declaration for messages. */
|
|
subdcl = 0; /* No subject as yet. */
|
|
parmno = 0; /* No parameters as yet. */
|
|
mdessv = es; /* Save es level for entity nesting check. */
|
|
reqadn = noteadn = 0; /* No required attributes yet. */
|
|
idadn = conradn = 0; /* No special atts yet.*/
|
|
AN(al) = 0; /* Number of attributes defined. */
|
|
ADN(al) = 0; /* Number of ad's in al (atts + name vals).*/
|
|
/* PARAMETER 1: Element name or a group of them.
|
|
*/
|
|
parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
|
|
TRACEMD("1: element name or group");
|
|
switch (pcbmd.action) {
|
|
case NAS:
|
|
nmgrp[0] = etddef(tbuf);
|
|
nmgrp[1] = 0;
|
|
break;
|
|
case GRPS:
|
|
parsegrp(nmgrp, &pcbgrnm, tbuf);
|
|
break;
|
|
case RNS: /* Reserved name started. */
|
|
if (ustrcmp(tbuf+1, key[KNOTATION])) {
|
|
mderr(118, tbuf+1, key[KNOTATION]);
|
|
return;
|
|
}
|
|
mdnadl(tbuf);
|
|
return;
|
|
default:
|
|
mderr(121, (UNCH *)0, (UNCH *)0);
|
|
return;
|
|
}
|
|
/* Save first GI for error msgs. */
|
|
if (nmgrp[0])
|
|
subdcl = nmgrp[0]->etdgi+1;
|
|
/* PARAMETER 2: Attribute definition list.
|
|
*/
|
|
parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
|
|
TRACEMD("2: attribute list");
|
|
if (pcbmd.action!=NAS) {
|
|
mderr(120, (UNCH *)0, (UNCH *)0);
|
|
return;
|
|
}
|
|
while (pcbmd.action==NAS) {
|
|
al[ADN(al)+1].adname = savenm(tbuf);
|
|
if ((adlim = ATTCNT-((int)++ADN(al)))<0) {
|
|
mderr(111, (UNCH *)0, (UNCH *)0);
|
|
adlfree(al, 1);
|
|
return;
|
|
}
|
|
++AN(al);
|
|
if (mdattdef(adlim, 0)) {
|
|
adlfree(al, 1);
|
|
return;
|
|
}
|
|
parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
|
|
}
|
|
if (AN(al)>0) { /* Save list only if 1 or more good atts. */
|
|
if (reqadn) SET(ADLF(al), ADLREQ); /* Element must have start-tag. */
|
|
if (noteadn) SET(ADLF(al), ADLNOTE); /* Element cannot be EMPTY. */
|
|
if (conradn) SET(ADLF(al), ADLCONR); /* Element cannot be EMPTY. */
|
|
alperm = (struct ad *)rmalloc((1+ADN(al))*ADSZ);
|
|
memcpy((UNIV)alperm, (UNIV)al, (1+ADN(al))*ADSZ );
|
|
ds.attcnt += AN(al); /* Number of attributes defined. */
|
|
ds.attgcnt += ADN(al) - AN(al); /* Number of att grp members. */
|
|
TRACEADL(alperm);
|
|
}
|
|
/* Clear attribute list for next declaration. */
|
|
MEMZERO((UNIV)al, (1+ADN(al))*ADSZ);
|
|
|
|
/* PARAMETER 3: End of declaration.
|
|
*/
|
|
/* Next pcb.action was set during attribute definition loop. */
|
|
TRACEMD(emd);
|
|
if (pcbmd.action!=EMD) {mderr(126, (UNCH *)0, (UNCH *)0); return;}
|
|
if (es!=mdessv) synerr(37, &pcbmd);
|
|
|
|
/* EXECUTE: Store the definition for each element name specified.
|
|
*/
|
|
TRACEGRP(nmgrp);
|
|
for (i = 0; nmgrp[i]; i++) {
|
|
if (nmgrp[i]->adl) { /* Error if an ADL exists. */
|
|
mderr(112, (UNCH *)0, (UNCH *)0);
|
|
continue;
|
|
}
|
|
nmgrp[i]->adl = alperm; /* If virgin, store the adl ptr. */
|
|
stored = 1;
|
|
if (alperm && nmgrp[i]->etdmod)
|
|
etdadl(nmgrp[i]); /* Check for conflicts with ETD. */
|
|
}
|
|
if (!stored && alperm) {
|
|
adlfree(alperm, 1);
|
|
frem((UNIV)alperm);
|
|
}
|
|
}
|
|
/* ETDADL: Check compatibility between ETD and ADL.
|
|
*/
|
|
VOID etdadl(p)
|
|
struct etd *p; /* Pointer to element type definition. */
|
|
{
|
|
parmno = 0;
|
|
/* Minimizable element cannot have required attribute. */
|
|
if (GET(p->etdmin, SMO) && GET(p->adl[0].adflags, ADLREQ)) {
|
|
mderr(40, (UNCH *)0, (UNCH *)0);
|
|
RESET(p->etdmin, SMO);
|
|
}
|
|
/* Empty element cannot have NOTATION attribute.
|
|
Attribute is not removed (too much trouble), but we trap
|
|
attempts to specify it on the start-tag in adlval().
|
|
*/
|
|
if (GET(p->etdmod->ttype, MNONE)) {
|
|
if (GET(p->adl[0].adflags, ADLNOTE))
|
|
mderr(83, (UNCH *)0, (UNCH *)0);
|
|
|
|
/* Empty element cannot have CONREF attribute.
|
|
Attribute is not removed because it just acts
|
|
like IMPLIED anyway.
|
|
*/
|
|
if (GET(p->adl[0].adflags, ADLCONR))
|
|
mderr(85, (UNCH *)0, (UNCH *)0);
|
|
}
|
|
/* "-" should not be specified for the end-tag minimization if
|
|
the element has a content reference attribute. */
|
|
if (GET(p->adl[0].adflags, ADLCONR) && BITON(p->etdmin, EMM))
|
|
mderr(153, (UNCH *)0, (UNCH *)0);
|
|
}
|
|
/* MDNADL: Process ATTLIST declaration for notation.
|
|
TO DO: Pass deftab and dvtab as parameters so
|
|
that prohibited types can be handled by leaving
|
|
them out of the tables.
|
|
*/
|
|
VOID mdnadl(tbuf)
|
|
UNCH *tbuf; /* Work area for tokenization (tbuf). */
|
|
{
|
|
int i; /* Loop counter; temporary variable. */
|
|
int adlim; /* Number of unused ad slots in al. */
|
|
struct ad *alperm = 0; /* Attribute definition list. */
|
|
int stored = 0;
|
|
|
|
/* PARAMETER 1: Notation name or a group of them.
|
|
*/
|
|
parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
|
|
TRACEMD("1: notation name or group");
|
|
switch (pcbmd.action) {
|
|
case NAS:
|
|
nnmgrp[0] = dcndef(tbuf);
|
|
nnmgrp[1] = 0;
|
|
break;
|
|
case GRPS:
|
|
parsngrp(nnmgrp, &pcbgrnm, tbuf);
|
|
break;
|
|
default:
|
|
mderr(121, (UNCH *)0, (UNCH *)0);
|
|
return;
|
|
}
|
|
subdcl = nnmgrp[0]->ename+1; /* Save first name for error msgs. */
|
|
/* PARAMETER 2: Attribute definition list.
|
|
*/
|
|
parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
|
|
TRACEMD("2: attribute list");
|
|
if (pcbmd.action!=NAS) {
|
|
mderr(120, (UNCH *)0, (UNCH *)0);
|
|
return;
|
|
}
|
|
while (pcbmd.action==NAS) {
|
|
al[ADN(al)+1].adname = savenm(tbuf);
|
|
if ((adlim = ATTCNT-((int)ADN(al)++))<0) {
|
|
mderr(111, (UNCH *)0, (UNCH *)0);
|
|
adlfree(al, 1);
|
|
return;
|
|
}
|
|
++AN(al);
|
|
if (mdattdef(adlim, 1)) {
|
|
adlfree(al, 1);
|
|
return;
|
|
}
|
|
parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
|
|
}
|
|
if (AN(al)>0) { /* Save list only if 1 or more good atts. */
|
|
alperm = (struct ad *)rmalloc((1+ADN(al))*ADSZ);
|
|
memcpy((UNIV)alperm, (UNIV)al, (1+ADN(al))*ADSZ );
|
|
ds.attcnt += AN(al); /* Number of attributes defined. */
|
|
ds.attgcnt += ADN(al) - AN(al); /* Number of att grp members. */
|
|
TRACEADL(alperm);
|
|
}
|
|
/* Clear attribute list for next declaration. */
|
|
MEMZERO((UNIV)al, (1+ADN(al))*ADSZ);
|
|
|
|
/* PARAMETER 3: End of declaration.
|
|
*/
|
|
/* Next pcb.action was set during attribute definition loop. */
|
|
TRACEMD(emd);
|
|
if (pcbmd.action!=EMD) {mderr(126, (UNCH *)0, (UNCH *)0); return;}
|
|
if (es!=mdessv) synerr(37, &pcbmd);
|
|
|
|
/* EXECUTE: Store the definition for each notation name specified.
|
|
*/
|
|
TRACENGR(nnmgrp);
|
|
for (i = 0; nnmgrp[i]; i++) {
|
|
if (nnmgrp[i]->adl) { /* Error if an ADL exists. */
|
|
mderr(112, (UNCH *)0, (UNCH *)0);
|
|
continue;
|
|
}
|
|
nnmgrp[i]->adl = alperm; /* If virgin, store the adl ptr. */
|
|
if (nnmgrp[i]->entsw)
|
|
fixdatt(nnmgrp[i]);
|
|
stored = 1;
|
|
TRACEDCN(nnmgrp[i]);
|
|
}
|
|
if (!stored && alperm) {
|
|
adlfree(alperm, 1);
|
|
frem((UNIV)alperm);
|
|
}
|
|
}
|
|
|
|
/* Data attributes have been specified for notation p, but entities
|
|
have already been declared with notation p. Fix up the definitions of
|
|
all entities with notation p. Generate an error for any data
|
|
attribute that was required. */
|
|
|
|
VOID fixdatt(p)
|
|
struct dcncb *p;
|
|
{
|
|
int i;
|
|
for (i = 0; i < ENTHASH; i++) {
|
|
struct entity *ep;
|
|
for (ep = etab[i]; ep; ep = ep->enext)
|
|
if (ep->estore == ESN && ep->etx.n && ep->etx.n->nedcn == p) {
|
|
int adn;
|
|
initatt(p->adl);
|
|
/* Don't use adlval because if there were required
|
|
attributes the error message wouldn't say what
|
|
entity was involved. */
|
|
for (adn = 1; adn <= ADN(al); adn++) {
|
|
if (GET(ADFLAGS(al,adn), AREQ)) {
|
|
sgmlerr(218, &pcbstag, ADNAME(al,adn),
|
|
ep->ename + 1);
|
|
SET(ADFLAGS(al,adn), AINVALID);
|
|
}
|
|
if (BITON(ADFLAGS(al, adn), AGROUP))
|
|
adn += ADNUM(al, adn);
|
|
}
|
|
storedatt(ep->etx.n);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* MDATTDEF: Process an individual attribute definition.
|
|
The attribute name is parsed by the caller.
|
|
Duplicate attributes are parsed, but removed from list.
|
|
Returns 0 if successful, otherwise returns 1.
|
|
*/
|
|
int mdattdef(adlim, datt)
|
|
int adlim; /* Remaining capacity of al (in tokens).*/
|
|
int datt; /* Non-zero if a data attribute. */
|
|
{
|
|
int deftype; /* Default value type: 0=not keyword. */
|
|
int errsw = 0; /* 1=semantic error; ignore att. */
|
|
int novalsw = 0; /* 1=semantic error; treat as IMPLIED. */
|
|
int attadn = (int)ADN(al); /* Save ad number of this attribute. */
|
|
struct parse *grppcb = NULL; /* PCB for name/token grp parse. */
|
|
int errcode; /* Error type returned by PARSEVAL, ANMTGRP. */
|
|
UNCH *advalsv; /* Save area for permanent value ptr. */
|
|
|
|
/* PARAMETER 1: Attribute name (parsed by caller).
|
|
*/
|
|
TRACEMD("1: attribute name");
|
|
if (anmget((int)ADN(al)-1, al[attadn].adname)) {
|
|
errsw = 1;
|
|
mderr(99, ADNAME(al,attadn), (UNCH *)0);
|
|
}
|
|
ADNUM(al,attadn) = ADFLAGS(al,attadn) = ADLEN(al,attadn) = 0;
|
|
ADVAL(al,attadn) = 0; ADDATA(al,attadn).x = 0; ADTYPE(al,attadn) = ANMTGRP;
|
|
/* PARAMETER 2: Declared value.
|
|
*/
|
|
parsemd(lbuf, NAMECASE, &pcblitp, NAMELEN);
|
|
TRACEMD("2: declared value");
|
|
switch (pcbmd.action) {
|
|
case NAS: /* Keyword for value type. */
|
|
switch (ADTYPE(al,attadn) = (UNCH)mapsrch(dvtab, lbuf+1)) {
|
|
case 0:
|
|
mderr(100, ADNAME(al,attadn), lbuf+1);
|
|
return 1;
|
|
case ANOTEGRP:
|
|
if (datt) {
|
|
errsw = 1;
|
|
mderr(156, (UNCH *)0, (UNCH *)0);
|
|
}
|
|
else if (!noteadn) noteadn = ADN(al);
|
|
else {
|
|
errsw = 1;
|
|
mderr(101, ADNAME(al,attadn), (UNCH *)0);
|
|
}
|
|
grppcb = &pcbgrnm; /* NOTATION requires name grp. */
|
|
parsemd(lbuf, NAMECASE, &pcblitp, NAMELEN);/* Get GRPO*/
|
|
break;
|
|
case AID:
|
|
if (datt) {
|
|
errsw = 1;
|
|
mderr(144, (UNCH *)0, (UNCH *)0);
|
|
}
|
|
else if (!idadn)
|
|
idadn = attadn;
|
|
else {
|
|
errsw = 1;
|
|
mderr(102, ADNAME(al,attadn), (UNCH *)0);
|
|
}
|
|
break;
|
|
case AIDREF:
|
|
case AIDREFS:
|
|
if (datt) {
|
|
errsw = 1;
|
|
mderr(155, (UNCH *)0, (UNCH *)0);
|
|
}
|
|
break;
|
|
case AENTITY:
|
|
case AENTITYS:
|
|
if (datt) {
|
|
errsw = 1;
|
|
mderr(154, (UNCH *)0, (UNCH *)0);
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
case GRPS:
|
|
grppcb = &pcbgrnt; /* Normal grp is name token grp. */
|
|
break;
|
|
case EMD:
|
|
mderr(103, ADNAME(al,attadn), (UNCH *)0);
|
|
return 1;
|
|
default:
|
|
mderr(104, ADNAME(al,attadn), (UNCH *)0);
|
|
return 1;
|
|
}
|
|
/* PARAMETER 2A: Name token group.
|
|
*/
|
|
if (grppcb != NULL) {
|
|
TRACEMD("2A: name group");
|
|
switch (pcbmd.action) {
|
|
case GRPS: /* Name token list. */
|
|
SET(ADFLAGS(al,attadn), AGROUP);
|
|
/* Call routine to parse group, create ad entries in adl. */
|
|
errcode = anmtgrp(grppcb, al+attadn,
|
|
(GRPCNT<adlim ? GRPCNT+1 : adlim+1),
|
|
&al[attadn].adnum, ADN(al));
|
|
if (errcode<=0) {
|
|
if (adlim < GRPCNT)
|
|
mderr(111, (UNCH *)0, (UNCH *)0);
|
|
else
|
|
mderr(105, ADNAME(al,attadn), (UNCH *)0);
|
|
return 1;
|
|
}
|
|
ADN(al) += ADNUM(al,attadn); /* Add grp size to total ad cnt.*/
|
|
break;
|
|
default:
|
|
mderr(106, ADNAME(al,attadn), (UNCH *)0);
|
|
return 1;
|
|
}
|
|
}
|
|
/* PARAMETER 3: Default value keyword.
|
|
*/
|
|
parsemd(lbuf, AVALCASE,
|
|
(ADTYPE(al,attadn)==ACHARS) ? &pcblitr : &pcblitt, LITLEN);
|
|
TRACEMD("3: default keyword");
|
|
switch (pcbmd.action) {
|
|
case RNS: /* Keyword. */
|
|
deftype = mapsrch(deftab, lbuf+1);
|
|
switch (deftype) {
|
|
case DFIXED: /* FIXED */
|
|
SET(ADFLAGS(al,attadn), AFIXED);
|
|
parsemd(lbuf, AVALCASE,
|
|
(ADTYPE(al,attadn)==ACHARS) ? &pcblitr : &pcblitt,
|
|
LITLEN); /* Real default. */
|
|
goto parm3x; /* Go process specified value. */
|
|
case DCURR: /* CURRENT: If ID, treat as IMPLIED. */
|
|
if (ADTYPE(al,attadn)==AID) {
|
|
mderr(80, ADNAME(al,attadn), (UNCH *)0);
|
|
break;
|
|
}
|
|
if (datt) {
|
|
mderr(157, (UNCH *)0, (UNCH *)0);
|
|
break;
|
|
}
|
|
SET(ADFLAGS(al,attadn), ACURRENT);
|
|
break;
|
|
case DREQ: /* REQUIRED */
|
|
SET(ADFLAGS(al,attadn), AREQ); ++reqadn;
|
|
break;
|
|
case DCONR: /* CONREF */
|
|
if (ADTYPE(al,attadn)==AID) {
|
|
mderr(107, ADNAME(al,attadn), (UNCH *)0);
|
|
break;
|
|
}
|
|
if (datt) {
|
|
mderr(158, (UNCH *)0, (UNCH *)0);
|
|
break;
|
|
}
|
|
SET(ADFLAGS(al,attadn), ACONREF); conradn = 1;
|
|
case DNULL: /* IMPLIED */
|
|
break;
|
|
default: /* Unknown keyword is an error. */
|
|
mderr(108, ADNAME(al,attadn), lbuf+1);
|
|
errsw = 1;
|
|
}
|
|
if (errsw) {
|
|
/* Ignore erroneous att. */
|
|
adlfree(al, attadn);
|
|
--AN(al);
|
|
ADN(al) = (UNCH)attadn-1;
|
|
}
|
|
return(0);
|
|
default:
|
|
break;
|
|
}
|
|
/* PARAMETER 3x: Default value (non-keyword).
|
|
*/
|
|
parm3x:
|
|
TRACEMD("3x: default (non-keyword)");
|
|
if (ADTYPE(al,attadn)==AID) { /* If ID, treat as IMPLIED. */
|
|
mderr(81, ADNAME(al,attadn), (UNCH *)0);
|
|
novalsw = 1; /* Keep parsing to keep things straight. */
|
|
}
|
|
switch (pcbmd.action) {
|
|
case LIT: /* Literal. */
|
|
case LITE: /* Literal. */
|
|
/* Null string (except CDATA) is error: msg and treat as IMPLIED. */
|
|
if (*lbuf == '\0' && ADTYPE(al,attadn)!=ACHARS) {
|
|
mderr(82, ADNAME(al,attadn), (UNCH *)0);
|
|
novalsw = 1;
|
|
}
|
|
break;
|
|
case NAS: /* Name character string. */
|
|
case NMT: /* Name character string. */
|
|
case NUM: /* Number or number token string. */
|
|
/* The name won't have a length byte because AVALCASE was specified. */
|
|
break;
|
|
case CDR:
|
|
parsetkn(lbuf, NMC, LITLEN);
|
|
break;
|
|
case EMD:
|
|
mderr(109, ADNAME(al,attadn), (UNCH *)0);
|
|
return 1;
|
|
default:
|
|
mderr(110, ADNAME(al,attadn), (UNCH *)0);
|
|
return 1;
|
|
}
|
|
if (errsw) {
|
|
/* Ignore erroneous att. */
|
|
adlfree(al, attadn);
|
|
--AN(al);
|
|
ADN(al) = (UNCH)attadn-1;
|
|
return(0);
|
|
}
|
|
if (novalsw) return(0);
|
|
|
|
/* PARAMETER 3y: Validate and store default value.
|
|
*/
|
|
if (ADTYPE(al,attadn)==ACHARS) {
|
|
UNS len = vallen(ACHARS, 0, lbuf);
|
|
if (len > LITLEN) {
|
|
/* Treat as implied. */
|
|
sgmlerr(224, &pcbmd, ADNAME(al,attadn), (UNCH *)0);
|
|
return 0;
|
|
}
|
|
/* No more checking for CDATA value. */
|
|
ADNUM(al,attadn) = 0; /* CDATA is 0 tokens. */
|
|
ADVAL(al,attadn) = savestr(lbuf);/* Store default; save ptr. */
|
|
ADLEN(al,attadn) = len;
|
|
ds.attdef += len;
|
|
return 0;
|
|
}
|
|
/* Parse value and save token count (GROUP implies 1 token). */
|
|
advalsv = (UNCH *)rmalloc(ustrlen(lbuf)+2); /* Storage for tokenized value. */
|
|
errcode = parseval(lbuf, (UNS)ADTYPE(al,attadn), advalsv);
|
|
if (BITOFF(ADFLAGS(al,attadn), AGROUP)) ADNUM(al,attadn) = (UNCH)tokencnt;
|
|
|
|
/* If value was invalid, or was a group member that was not in the group,
|
|
issue an appropriate message and set the error switch. */
|
|
if (errcode)
|
|
{sgmlerr((UNS)errcode, &pcbmd, ADNAME(al,attadn), lbuf); errsw = 1;}
|
|
else if ( BITON(ADFLAGS(al,attadn), AGROUP)
|
|
&& !amemget(&al[attadn], (int)ADNUM(al,attadn), advalsv) ) {
|
|
sgmlerr(79, &pcbmd, ADNAME(al,attadn), advalsv+1);
|
|
errsw = 1;
|
|
}
|
|
ADLEN(al,attadn) = vallen(ADTYPE(al,attadn), ADNUM(al,attadn), advalsv);
|
|
if (ADLEN(al,attadn) > LITLEN) {
|
|
sgmlerr(224, &pcbmd, ADNAME(al,attadn), (UNCH *)0);
|
|
ADLEN(al,attadn) = 0;
|
|
errsw = 1;
|
|
}
|
|
/* For valid tokenized value, save it and update statistics. */
|
|
if (!errsw) {
|
|
ADVAL(al,attadn) = advalsv;
|
|
ds.attdef += ADLEN(al,attadn);
|
|
return 0;
|
|
}
|
|
/* If value was bad, free the value's storage and treat as
|
|
IMPLIED or REQUIRED. */
|
|
frem((UNIV)advalsv); /* Release storage for value. */
|
|
ADVAL(al,attadn) = NULL; /* And make value NULL. */
|
|
return 0;
|
|
}
|
|
/* ANMTGRP: Parse a name or name token group, create attribute descriptors
|
|
for its members, and add them to the attribute descriptor list.
|
|
The parse either terminates or returns a good token, so no
|
|
switch is needed.
|
|
*/
|
|
int anmtgrp(pcb, nt, grplim, adn, adsz)
|
|
struct parse *pcb; /* PCB for name or name token grp. */
|
|
struct ad nt[]; /* Buffer for creating name token list. */
|
|
int grplim; /* Maximum size of list (plus 1). */
|
|
UNS *adn; /* Ptr to number of names or tokens in grp. */
|
|
int adsz; /* Size of att def list. */
|
|
{
|
|
UNCH adtype = (UNCH)(pcb==&pcbgrnt ? ANMTGRP:ANOTEGRP);/*Attribute type.*/
|
|
int essv = es; /* Entity stack level when grp started. */
|
|
|
|
*adn = 0; /* Group is empty to start. */
|
|
while (parse(pcb)!=GRPE && *adn<grplim) {
|
|
switch (pcb->action) {
|
|
case NAS_: /* Name or name token (depending on pcb). */
|
|
case NMT_:
|
|
parsenm(lbuf, NAMECASE);
|
|
nt[*adn+1].adname = savenm(lbuf);
|
|
if (antvget((int)(adsz+*adn), nt[*adn+1].adname, (UNCH **)0))
|
|
mderr(98, ntoa((int)*adn+1), nt[*adn+1].adname+1);
|
|
nt[++*adn].adtype = adtype;
|
|
nt[*adn].addef = NULL;
|
|
continue;
|
|
|
|
case EE_: /* Entity ended (correctly or incorrectly). */
|
|
if (es<essv) {synerr(37, pcb); essv = es;}
|
|
continue;
|
|
|
|
case PIE_: /* PI entity reference (invalid). */
|
|
entpisw = 0; /* Reset PI entity indicator. */
|
|
synerr(59, pcb);
|
|
continue;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
if (es!=essv) synerr(37, pcb);
|
|
if (*adn==grplim) return -1;
|
|
else return *adn; /* Return number of tokens. */
|
|
}
|
|
/* MDDTDS: Process start of DOCTYPE declaration (through MSO).
|
|
*/
|
|
VOID mddtds(tbuf)
|
|
UNCH *tbuf; /* Work area for tokenization[LITLEN+2]. */
|
|
{
|
|
struct fpi fpicb; /* Formal public identifier structure. */
|
|
union etext etx; /* Ptr to entity text. */
|
|
UNCH estore = ESD; /* Entity storage class. */
|
|
int emdsw = 0; /* 1=end of declaration found; 0=not yet. */
|
|
|
|
mdname = key[KDOCTYPE]; /* Identify declaration for messages. */
|
|
subdcl = NULL; /* No subject as yet. */
|
|
parmno = 0; /* No parameters as yet. */
|
|
mdessv = es; /* Save es for checking entity nesting. */
|
|
dtdrefsw = 0; /* No external DTD entity as yet. */
|
|
/* PARAMETER 1: Document type name.
|
|
*/
|
|
pcbmd.newstate = 0;
|
|
parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
|
|
TRACEMD("1: doc type name");
|
|
if (pcbmd.action!=NAS) {mderr(120, (UNCH *)0, (UNCH *)0); return;}
|
|
dtype = savenm(tbuf);
|
|
subdcl = dtype+1; /* Subject of declaration for error msgs. */
|
|
|
|
/* PARAMETER 2: External identifier keyword or MDS.
|
|
*/
|
|
pcbmd.newstate = 0;
|
|
parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
|
|
TRACEMD("2: extid or MDS");
|
|
switch (pcbmd.action) {
|
|
case NAS:
|
|
if (mdextid(tbuf, &fpicb, dtype+1, &estore, (PNE)0)==0) return;
|
|
if ((etx.x = entgen(&fpicb))==0)
|
|
mderr(146, dtype+1, (UNCH *)0);
|
|
else
|
|
dtdrefsw = 1; /* Signal external DTD entity. */
|
|
break;
|
|
case MDS:
|
|
goto execute;
|
|
default:
|
|
mderr(128, (UNCH *)0, (UNCH *)0);
|
|
return;
|
|
}
|
|
/* PARAMETER 3: MDS or end of declaration.
|
|
*/
|
|
TRACEMD("3: MDS or EMD");
|
|
switch (pcbmd.action) {
|
|
default: /* Treat as end of declaration. */
|
|
mderr(126, (UNCH *)0, (UNCH *)0);
|
|
case EMD:
|
|
emdsw = 1;
|
|
case MDS:
|
|
break;
|
|
}
|
|
/* EXECUTE: Store entity definition if an external ID was specified.
|
|
*/
|
|
execute:
|
|
if (es!=mdessv) synerr(37, &pcbmd);
|
|
propcb = &pcbmds; /* Prepare to parse doc type definition (MDS). */
|
|
if (dtdrefsw) {
|
|
/* TO DO: If concurrent DTD's supported, free existing
|
|
etext for all but first DTD (or reuse it). */
|
|
entdef(indtdent, estore, &etx);
|
|
++ds.ecbcnt; ds.ecbtext += entlen;
|
|
if (emdsw) {
|
|
REPEATCC; /* Push back the MDC. */
|
|
*FPOS = lex.d.msc; /* Simulate end of DTD subset. */
|
|
REPEATCC; /* Back up to read MSC next. */
|
|
delmscsw = 1; /* Insert MSC after referenced DTD. */
|
|
}
|
|
}
|
|
indtdsw = 1; /* Allow "DTD only" parameters. */
|
|
return;
|
|
}
|
|
/* MDDTDE: Process DOCTYPE declaration end.
|
|
*/
|
|
VOID mddtde(tbuf)
|
|
UNCH *tbuf; /* Work area for tokenization. */
|
|
{
|
|
mdessv = es; /* Save es for checking entity nesting. */
|
|
propcb = &pcbpro; /* Restore normal prolog parse. */
|
|
indtdsw = 0; /* Prohibit "DTD only" parameters. */
|
|
|
|
mdname = key[KDOCTYPE]; /* Identify declaration for messages. */
|
|
subdcl = dtype+1; /* Subject of declaration for error msgs. */
|
|
parmno = 0; /* No parameters as yet. */
|
|
/* PARAMETER 4: End of declaration.
|
|
*/
|
|
pcbmd.newstate = 0;
|
|
parsemd(tbuf, NAMECASE, &pcblitp, LITLEN);
|
|
TRACEMD(emd);
|
|
if (pcbmd.action!=EMD) mderr(126, (UNCH *)0, (UNCH *)0);
|
|
if (es!=mdessv) synerr(37, &pcbmd);
|
|
}
|
|
/* MDELEM: Process ELEMENT declaration.
|
|
*/
|
|
VOID mdelem(tbuf)
|
|
UNCH *tbuf; /* Work area for tokenization (tbuf). */
|
|
{
|
|
UNCH *ranksuff = lbuf; /* Rank suffix. */
|
|
UNS dctype = 0; /* Declared content type (from dctab). */
|
|
UNCH fmin = 0; /* Minimization bit flags. */
|
|
int i; /* Loop counter. */
|
|
UNS u; /* Temporary variable. */
|
|
struct etd **mexgrp, **pexgrp; /* Ptr to model exceptions array. */
|
|
struct thdr *cmod, *cmodsv; /* Ptr to content model. */
|
|
UNCH *etdgi; /* GI of current etd (when going through group).*/
|
|
int minomitted = 0; /* Tag minimization parameters omitted. */
|
|
|
|
mdname = key[KELEMENT]; /* Identify declaration for messages. */
|
|
subdcl = NULL; /* No subject as yet. */
|
|
parmno = 0; /* No parameters as yet. */
|
|
mdessv = es; /* Save es level for entity nesting check. */
|
|
ranksuff[0] = 0;
|
|
mexgrp = pexgrp = 0;
|
|
|
|
/* PARAMETER 1: Element name or a group of them.
|
|
*/
|
|
parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
|
|
TRACEMD("1: element name or grp");
|
|
switch (pcbmd.action) {
|
|
case NAS:
|
|
nmgrp[0] = etddef(tbuf);
|
|
nmgrp[1] = 0;
|
|
break;
|
|
case GRPS:
|
|
parsegrp(nmgrp, &pcbgrnm, tbuf);
|
|
break;
|
|
default:
|
|
mderr(121, (UNCH *)0, (UNCH *)0);
|
|
return;
|
|
}
|
|
/* Save first GI for trace and error messages. */
|
|
if (nmgrp[0])
|
|
subdcl = nmgrp[0]->etdgi+1;
|
|
|
|
/* PARAMETER 1A: Rank suffix (optional).
|
|
*/
|
|
parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
|
|
TRACEMD("1A: rank suffix");
|
|
switch (pcbmd.action) {
|
|
case NUM:
|
|
ustrcpy(ranksuff, tbuf);
|
|
parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
|
|
default:
|
|
break;
|
|
}
|
|
/* PARAMETER 2A: Start-tag minimization.
|
|
*/
|
|
TRACEMD("2A: start min");
|
|
switch (pcbmd.action) {
|
|
case CDR:
|
|
break;
|
|
case NAS:
|
|
if (!ustrcmp(tbuf+1, key[KO])) {
|
|
if (OMITTAG==YES) SET(fmin, SMO);
|
|
break;
|
|
}
|
|
/* fall through */
|
|
default:
|
|
if (OMITTAG==NO) {minomitted=1; break;}
|
|
mderr(129, tbuf+1, (UNCH *)0);
|
|
return;
|
|
}
|
|
/* Must omit omitted end-tag minimization, if omitted
|
|
start-tag minimization was omitted (because OMITTAG == NO). */
|
|
if (!minomitted) {
|
|
/* PARAMETER 2B: End-tag minimization.
|
|
*/
|
|
parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
|
|
TRACEMD("2B: end min");
|
|
switch (pcbmd.action) {
|
|
case NAS:
|
|
if (ustrcmp(tbuf+1, key[KO])) {mderr(129, tbuf+1, (UNCH *)0); return;}
|
|
if (OMITTAG==YES) SET(fmin, EMO);
|
|
break;
|
|
case CDR:
|
|
SET(fmin, EMM);
|
|
break;
|
|
default:
|
|
mderr(129, tbuf+1, (UNCH *)0);
|
|
return;
|
|
}
|
|
/* PARAMETER 3: Declared content.
|
|
*/
|
|
parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
|
|
}
|
|
TRACEMD("3: declared content");
|
|
switch (pcbmd.action) {
|
|
case NAS:
|
|
dctype = mapsrch(dctab, tbuf+1);
|
|
if (!dctype) {mderr(24, tbuf+1, (UNCH *)0); return;}
|
|
/* Eliminate incompatibilities among parameters. */
|
|
if (GET(fmin, SMO) && GET(dctype, MNONE+MCDATA+MRCDATA)) {
|
|
mderr(58, (UNCH *)0, (UNCH *)0);
|
|
RESET(fmin, SMO);
|
|
}
|
|
if (GET(dctype, MNONE) && BITON(fmin, EMM)) {
|
|
mderr(87, (UNCH *)0, (UNCH *)0);
|
|
SET(fmin, EMO);
|
|
}
|
|
/* If valid, process like a content model. */
|
|
case GRPS:
|
|
cmodsv = parsemod((int)(pcbmd.action==GRPS ? 0 : dctype));
|
|
if (cmodsv==0) return;
|
|
u = (dctype ? 1 : cmodsv->tu.tnum+2) * THSZ;
|
|
cmod = (struct thdr *)rmalloc(u);
|
|
memcpy((UNIV)cmod , (UNIV)cmodsv, u );
|
|
ds.modcnt += cmod->tu.tnum;
|
|
TRACEMOD(cmod);
|
|
break;
|
|
default:
|
|
mderr(130, (UNCH *)0, (UNCH *)0);
|
|
return;
|
|
}
|
|
/* PARAMETERS 3A, 3B: Exceptions or end.
|
|
*/
|
|
parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
|
|
if (BITOFF(cmod->ttype, MCDATA+MRCDATA+MNONE)) {
|
|
/* PARAMETER 3A: Minus exceptions.
|
|
*/
|
|
TRACEMD("3A: -grp");
|
|
switch (pcbmd.action) {
|
|
case MGRP:
|
|
/* We cheat and use nnmgrp for this. */
|
|
mexgrp = copygrp((PETD *)nnmgrp,
|
|
u = parsegrp((PETD *)nnmgrp, &pcbgrnm, tbuf));
|
|
++ds.pmexgcnt; ds.pmexcnt += u-1;
|
|
TRACEGRP(mexgrp);
|
|
parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
|
|
default:
|
|
break;
|
|
}
|
|
/* PARAMETER 3B: Plus exceptions.
|
|
*/
|
|
TRACEMD("3B: +grp");
|
|
switch (pcbmd.action) {
|
|
case PGRP:
|
|
pexgrp = copygrp((PETD *)nnmgrp,
|
|
u = parsegrp((PETD *)nnmgrp, &pcbgrnm, tbuf));
|
|
++ds.pmexgcnt; ds.pmexcnt += u-1;
|
|
TRACEGRP(pexgrp);
|
|
parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
/* PARAMETER 4: End of declaration.
|
|
*/
|
|
TRACEMD(emd);
|
|
if (pcbmd.action!=EMD) mderr(126, (UNCH *)0, (UNCH *)0);
|
|
if (es!=mdessv) synerr(37, &pcbmd);
|
|
|
|
/* EXECUTE: Store the definition for each element name specified.
|
|
*/
|
|
TRACEGRP(nmgrp);
|
|
for (i = -1; nmgrp[++i];) {
|
|
etdgi = nmgrp[i]->etdgi;
|
|
if (*ranksuff) {
|
|
if ((tbuf[0] = *etdgi + ustrlen(ranksuff)) - 2 > NAMELEN) {
|
|
mderr(131, etdgi+1, ranksuff);
|
|
continue;
|
|
}
|
|
memcpy(tbuf+1, etdgi+1, *etdgi-1);
|
|
ustrcpy(tbuf+*etdgi-1, ranksuff);
|
|
etdcan(etdgi);
|
|
nmgrp[i] = etddef(tbuf);
|
|
}
|
|
if (nmgrp[i]->etdmod) {mderr(56, etdgi+1, (UNCH *)0); continue;}
|
|
etdset(nmgrp[i], fmin+ETDDCL, cmod, mexgrp, pexgrp, nmgrp[i]->etdsrm);
|
|
++ds.etdcnt;
|
|
if (nmgrp[i]->adl) etdadl(nmgrp[i]); /* Check ETD conflicts. */
|
|
TRACEETD(nmgrp[i]);
|
|
}
|
|
}
|
|
|
|
VOID adlfree(al, aln)
|
|
struct ad *al;
|
|
int aln;
|
|
{
|
|
for (; aln <= ADN(al); aln++) {
|
|
frem((UNIV)al[aln].adname);
|
|
if (ADVAL(al, aln))
|
|
frem((UNIV)ADVAL(al, aln));
|
|
if (BITON(ADFLAGS(al, aln), AGROUP)) {
|
|
int i;
|
|
for (i = 0; i < ADNUM(al, aln); i++)
|
|
frem((UNIV)al[aln + i + 1].adname);
|
|
aln += ADNUM(al, aln);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
Local Variables:
|
|
c-indent-level: 5
|
|
c-continued-statement-offset: 5
|
|
c-brace-offset: -5
|
|
c-argdecl-indent: 0
|
|
c-label-offset: -5
|
|
comment-column: 30
|
|
End:
|
|
*/
|