523 lines
17 KiB
C
523 lines
17 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 libraries and programs; if not, write
|
|
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
|
|
* Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
/* $XConsortium: sgml2.c /main/3 1996/06/19 17:17:20 drk $ */
|
|
/* Added exiterr() for terminal errors to prevent SGML.MSG errors. */
|
|
#include "sgmlincl.h" /* #INCLUDE statements for SGML parser. */
|
|
static int iorc; /* Return code from io* functions */
|
|
/* ENTDEF: Process an entity definition and return the pointer to it.
|
|
The entity text must be in permanent storage.
|
|
There is no checking to see if the entity already exists;
|
|
the caller must have done that.
|
|
*/
|
|
#ifdef USE_PROTOTYPES
|
|
PECB entdef(UNCH *ename, UNCH estore, union etext *petx)
|
|
#else
|
|
PECB entdef(ename, estore, petx)
|
|
UNCH *ename; /* Entity name (with length and EOS). */
|
|
UNCH estore; /* Entity storage class. */
|
|
union etext *petx; /* Ptr to entity text union. */
|
|
#endif
|
|
{
|
|
PECB p;
|
|
|
|
p = (PECB)hin((THASH)etab, ename, hash(ename, ENTHASH), ENTSZ);
|
|
memcpy((UNIV)&p->etx, (UNIV)petx, ETEXTSZ);
|
|
p->estore = estore;
|
|
TRACEECB("ENTDEF", p);
|
|
return(p);
|
|
}
|
|
/* ENTFIND: If an entity exists, return ptr to its ecb.
|
|
Return NULL if it is not defined.
|
|
*/
|
|
PECB entfind(ename)
|
|
UNCH *ename; /* Entity name (with length and EOS). */
|
|
{
|
|
PECB p;
|
|
|
|
p = (PECB)hfind((THASH)etab, ename, hash(ename, ENTHASH));
|
|
TRACEECB("ENTFIND", p);
|
|
return p;
|
|
}
|
|
/* ENTREF: Process a general or parameter entity reference.
|
|
If the entity is defined it returns the return code from ENTOPEN.
|
|
It returns ENTUNDEF for undefined parameter entity references
|
|
and for general entity references when defaulting is not allowed.
|
|
Otherwise, it uses the default entity text.
|
|
*/
|
|
int entref(ename)
|
|
UNCH *ename; /* Entity name (with length and EOS). */
|
|
{
|
|
PECB ecb; /* Entity control block. */
|
|
|
|
/* Get the entity control block, if the entity has been defined. */
|
|
if ((ecb = (PECB)hfind((THASH)etab, ename, hash(ename, ENTHASH)))==0
|
|
|| ecb->estore == 0) {
|
|
if ( ename[1]==lex.d.pero
|
|
|| ecbdeflt==0
|
|
|| (ecb = usedef(ename))==0 ) {
|
|
sgmlerr(ename[1] == lex.d.pero || ecbdeflt == 0 ? 35 : 150,
|
|
(struct parse *)0, ename+1, (UNCH *)0);
|
|
return(ENTUNDEF);
|
|
}
|
|
}
|
|
return(entopen(ecb));
|
|
}
|
|
/* ENTOPEN: Open a newly referenced entity.
|
|
Increment the stack pointer (es) and initialize the new entry.
|
|
ENTDATA if entity is CDATA or SDATA, ENTPI if it is PI,
|
|
0 if normal and all o.k.; <0 if not.
|
|
*/
|
|
int entopen(ecb)
|
|
struct entity *ecb; /* Entity control block. */
|
|
{
|
|
int i; /* Loop counter. */
|
|
|
|
/* See if we have exceeded the entity nesting level. */
|
|
if (es>=ENTLVL) {
|
|
sgmlerr(34, (struct parse *)0, ecb->ename+1, ntoa(ENTLVL));
|
|
return(ENTMAX);
|
|
}
|
|
/* If entity is an etd, pi, or data, return it without creating an scb. */
|
|
switch (ecb->estore) {
|
|
case ESN:
|
|
if (NEXTYPE(ecb->etx.n)!=ESNSUB) {
|
|
if (!NEDCNDEFINED(ecb->etx.n))
|
|
sgmlerr(78, (struct parse *)0, NEDCN(ecb->etx.n)+1,
|
|
ecb->ename+1);
|
|
}
|
|
else {
|
|
#if 0
|
|
if (!NEID(ecb->etx.n)) {
|
|
sgmlerr(149, (struct parse *)0, ecb->ename + 1, (UNCH *)0);
|
|
return ENTFILE;
|
|
}
|
|
#endif
|
|
if (sw.nopen >= sd.subdoc)
|
|
sgmlerr(188, (struct parse *)0,
|
|
(UNCH *)NULL, (UNCH *)NULL);
|
|
}
|
|
data = (UNCH *)ecb->etx.n;
|
|
entdatsw = NDECONT;
|
|
return(ENTDATA);
|
|
case ESC:
|
|
case ESX:
|
|
datalen = ustrlen(ecb->etx.c);
|
|
data = ecb->etx.c;
|
|
entdatsw = (ecb->estore==ESC) ? CDECONT : SDECONT;
|
|
return(ENTDATA);
|
|
case ESI:
|
|
datalen = ustrlen(ecb->etx.c);
|
|
data = ecb->etx.c;
|
|
entpisw = 4;
|
|
return(ENTPI);
|
|
}
|
|
/* If the same entity is already open, send msg and ignore it.
|
|
Level 0 needn't be tested, as its entity name is always *DOC.
|
|
*/
|
|
for (i = 0; ++i<=es;) if (scbs[i].ecb.enext==ecb) {
|
|
sgmlerr(36, (struct parse *)0, ecb->ename+1, (UNCH *)0);
|
|
return(ENTLOOP);
|
|
}
|
|
/* Update SCB if entity trace is wanted in messages or entity is a file.
|
|
(Avoid this at start when es==-1 or memory will be corrupted.)
|
|
*/
|
|
if (es >= 0 && (sw.swenttr || FILESW)) scbset();
|
|
|
|
/* Stack the new source control block (we know there is room). */
|
|
++es; /* Increment scbs index. */
|
|
RCNT = CCO = RSCC = 0; /* No records or chars yet. */
|
|
COPIEDSW = 0;
|
|
memcpy((UNIV)&ECB, (UNIV)ecb, (UNS)ENTSZ); /* Copy the ecb into the scb. */
|
|
ECBPTR = ecb; /* Save the ecb pointer in scb.ecb.enext. */
|
|
TRACEECB("ENTOPEN", ECBPTR);
|
|
|
|
/* For memory entities, the read buffer is the entity text.
|
|
The text starts at FBUF, so FPOS should be FBUF-1
|
|
because it is bumped before each character is read.
|
|
*/
|
|
if (ECB.estore<ESFM) {FPOS = (FBUF = ECB.etx.c)-1; return 0;}
|
|
|
|
/* For file entities, suspend any open file and do first read. */
|
|
if (ECB.etx.x == 0) {
|
|
--es;
|
|
switch (ecb->estore) {
|
|
case ESF:
|
|
sgmlerr(149, (struct parse *)0, ecb->ename + 1, (UNCH *)0);
|
|
break;
|
|
case ESP:
|
|
sgmlerr(229, (struct parse *)0, ecb->ename + 2, (UNCH *)0);
|
|
break;
|
|
default:
|
|
abort();
|
|
}
|
|
return ENTFILE;
|
|
}
|
|
fileopen(); /* Open new external file. */
|
|
if (iorc<0) { /* If open not successful: */
|
|
FPOS = FBUF-1; /* Clean CCNT for OPEN error msg.*/
|
|
filerr(32, ecb->ename+1);
|
|
--es; /* Pop the stack. */
|
|
return(ENTFILE);
|
|
}
|
|
filepend(es); /* Suspend any open file. */
|
|
fileread(); /* First read of file must be ok.*/
|
|
return 0;
|
|
}
|
|
/* ENTGET: Get next record of entity (if there is one).
|
|
Otherwise, close the file (if entity is a file) and
|
|
pop the entity stack. If nothing else is on the stack,
|
|
return -1 to advise the caller.
|
|
*/
|
|
int entget()
|
|
{
|
|
RSCC += (CCO = FPOS-FBUF);
|
|
/* Characters-in-record (ignore EOB/EOF). */
|
|
tagctr += CCO; /* Update tag length counter. */
|
|
switch (*FPOS) {
|
|
case EOBCHAR: /* End of file buffer: refill it. */
|
|
rbufs[-2] = FPOS[-2];
|
|
rbufs[-1] = FPOS[-1];
|
|
fileread(); /* Read the file. */
|
|
if (iorc > 0) break;
|
|
readerr:
|
|
filerr(31, ENTITY+1); /* Treat error as EOF. */
|
|
case EOFCHAR: /* End of file: close it. */
|
|
fileclos(); /* Call SGMLIO to close file. */
|
|
conterr:
|
|
if (es==0) { /* Report if it is primary file. */
|
|
FPOS = FBUF-1; /* Preserve CCNT for omitted end-tags. */
|
|
return -1;
|
|
}
|
|
case EOS: /* End of memory entity: pop the stack. */
|
|
TRACEECB("ENTPOP", ECBPTR);
|
|
if (COPIEDSW) {
|
|
frem((UNIV)(FBUF + 1));
|
|
COPIEDSW = 0;
|
|
}
|
|
--es; /* Pop the SCB stack. */
|
|
if (FBUF) break; /* Not a PEND file. */
|
|
filecont(); /* Resume previous file. */
|
|
if (iorc<0) { /* If CONT not successful: */
|
|
filerr(94, ENTITY+1);
|
|
goto conterr;
|
|
}
|
|
fileread(); /* Read the file. */
|
|
if (iorc<=0) goto readerr; /* If READ not successful: */
|
|
rbufs[-1] = SCB.pushback;
|
|
FPOS += CCO;
|
|
CCO = 0;
|
|
if (delmscsw && es==0) { /* End of DTD. */
|
|
delmscsw = 0;
|
|
*rbufs = lex.d.msc;
|
|
}
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
/* USEDEF: Use the default value for an entity reference.
|
|
Returns the ECB for the defaulted entity.
|
|
*/
|
|
PECB usedef(ename)
|
|
UNCH *ename; /* Entity name (with length and EOS). */
|
|
{
|
|
union etext etx; /* Save return from entgen. */
|
|
PECB ecb; /* Entity control block. */
|
|
PNE pne = 0; /* Ptr to NDATA entity control block. */
|
|
UNCH estore; /* Default entity storage type. */
|
|
|
|
if ((estore = ecbdeflt->estore)<ESFM) /* Default is an internal string. */
|
|
etx.c = ecbdeflt->etx.c;
|
|
else {
|
|
/* Move entity name into fpi. */
|
|
fpidf.fpinm = ename + 1;
|
|
if ((etx.x = entgen(&fpidf))==0) return (PECB)0;
|
|
if (estore==ESN) {
|
|
memcpy((UNIV)(pne=(PNE)rmalloc((UNS)NESZ)),(UNIV)ecbdeflt->etx.n,(UNS)NESZ);
|
|
NEID(pne) = etx.x;
|
|
etx.n = pne;
|
|
}
|
|
}
|
|
if (sw.swrefmsg) sgmlerr(45, (struct parse *)0, ename+1, (UNCH *)0);
|
|
++ds.ecbcnt;
|
|
ecb = entdef(ename, estore, &etx);
|
|
ecb->dflt = 1;
|
|
if (pne) NEENAME(pne) = ecb->ename;
|
|
return(ecb);
|
|
}
|
|
/* SCBSET: Set source control block to current location in the current entity.
|
|
This routine is called by SGML when it returns to the text
|
|
processor and by ERROR when it reports an error.
|
|
*/
|
|
VOID scbset()
|
|
{
|
|
if (es >= 0 && FBUF) {
|
|
CC = *FPOS;
|
|
if (*FPOS == DELNONCH)
|
|
NEXTC = FPOS[1];
|
|
else
|
|
NEXTC = 0;
|
|
CCO = FPOS + 1 - FBUF;
|
|
}
|
|
}
|
|
/* FILEOPEN: Call IOOPEN to open an external entity (file).
|
|
*/
|
|
VOID fileopen() /* Open an external entity's file. */
|
|
{
|
|
iorc = ioopen(ECB.etx.x, &SCBFCB);
|
|
}
|
|
/* FILEREAD: Call IOREAD to read an open external entity (file).
|
|
*/
|
|
VOID fileread() /* Read the current external entity's file. */
|
|
{
|
|
int newfile;
|
|
iorc = ioread(SCBFCB, rbufs, &newfile);
|
|
FPOS = (FBUF = rbufs) - 1; /* Actual read buffer. */
|
|
if (newfile) RCNT = 0;
|
|
}
|
|
/* FILEPEND: Call IOPEND to close an open external entity (file) temporarily.
|
|
*/
|
|
VOID filepend(es) /* Close the current external entity's file. */
|
|
int es; /* Local index to scbs. */
|
|
{
|
|
while (--es>=0) { /* Find last external file on stack. */
|
|
int off;
|
|
if (!FILESW) continue; /* Not an external file. */
|
|
if (!FBUF) continue; /* Already suspended. */
|
|
off = CCO;
|
|
assert(off >= -1);
|
|
if (off < 0) off = 0;
|
|
else CCO = 0;
|
|
FPOS -= CCO;
|
|
SCB.pushback = FPOS[-1];
|
|
FBUF = 0; /* Indicate pending file. */
|
|
RSCC += off; /* Update characters-in-record counter. */
|
|
tagctr += off; /* Update tag length counter. */
|
|
iopend(SCBFCB, off, rbufs);
|
|
return;
|
|
}
|
|
}
|
|
/* FILECONT: Call IOCONT to reopen an external entity (file).
|
|
*/
|
|
VOID filecont() /* Open an external entity's file. */
|
|
{
|
|
iorc = iocont(SCBFCB);
|
|
}
|
|
/* FILECLOS: Call IOCLOSE to close an open external entity (file).
|
|
*/
|
|
VOID fileclos() /* Close the current external entity's file. */
|
|
{
|
|
if (!SCBFCB)
|
|
return;
|
|
ioclose(SCBFCB);
|
|
/* The fcb will have been freed by sgmlio.
|
|
Make sure we don't access it again. */
|
|
SCBFCB = NULL;
|
|
}
|
|
/* ERROR: Interface to text processor SGML I/O services for error handling.
|
|
*/
|
|
VOID error(e)
|
|
struct error *e;
|
|
{
|
|
scbset(); /* Update location in source control block. */
|
|
msgprint(e);
|
|
}
|
|
/* PTRSRCH: Find a pointer in a list and return its index.
|
|
Search key must be on list as there is no limit test.
|
|
This routine is internal only -- not for user data.
|
|
*/
|
|
UNIV mdnmtab[] = {
|
|
(UNIV)key[KATTLIST],
|
|
(UNIV)key[KDOCTYPE],
|
|
(UNIV)key[KELEMENT],
|
|
(UNIV)key[KENTITY],
|
|
(UNIV)key[KLINKTYPE],
|
|
(UNIV)key[KLINK],
|
|
(UNIV)key[KNOTATION],
|
|
(UNIV)sgmlkey,
|
|
(UNIV)key[KSHORTREF],
|
|
(UNIV)key[KUSELINK],
|
|
(UNIV)key[KUSEMAP]
|
|
};
|
|
UNIV pcbtab[] = {
|
|
(UNIV)&pcbconc,
|
|
(UNIV)&pcbcone,
|
|
(UNIV)&pcbconm,
|
|
(UNIV)&pcbconr,
|
|
(UNIV)&pcbetag,
|
|
(UNIV)&pcbgrcm,
|
|
(UNIV)&pcbgrcs,
|
|
(UNIV)&pcbgrnm,
|
|
(UNIV)&pcbgrnt,
|
|
(UNIV)&pcblitc,
|
|
(UNIV)&pcblitp,
|
|
(UNIV)&pcblitr,
|
|
(UNIV)&pcblitt,
|
|
(UNIV)&pcblitv,
|
|
(UNIV)&pcbmd,
|
|
(UNIV)&pcbmdc,
|
|
(UNIV)&pcbmdi,
|
|
(UNIV)&pcbmds,
|
|
(UNIV)&pcbmsc,
|
|
(UNIV)&pcbmsi,
|
|
(UNIV)&pcbmsrc,
|
|
(UNIV)&pcbpro,
|
|
(UNIV)&pcbref,
|
|
(UNIV)&pcbstag,
|
|
(UNIV)&pcbval,
|
|
(UNIV)&pcbeal,
|
|
(UNIV)&pcbsd,
|
|
};
|
|
UNS ptrsrch(ptrtab, ptr)
|
|
UNIV ptrtab[];
|
|
UNIV ptr;
|
|
{
|
|
UNS i;
|
|
|
|
for (i = 0; ; ++i)
|
|
if (ptrtab[i] == ptr)
|
|
break;
|
|
return i;
|
|
}
|
|
/* MDERR: Process errors for markup declarations.
|
|
Prepare the special parameters that only exist for
|
|
markup declaration errors.
|
|
*/
|
|
VOID mderr(number, parm1, parm2)
|
|
UNS number; /* Error number. */
|
|
UNCH *parm1; /* Additional parameters (or NULL). */
|
|
UNCH *parm2; /* Additional parameters (or NULL). */
|
|
{
|
|
struct error err;
|
|
errorinit(&err, subdcl ? MDERR : MDERR2, number);
|
|
err.parmno = parmno;
|
|
err.subdcl = subdcl;
|
|
err.eparm[0] = (UNIV)parm1;
|
|
err.eparm[1] = (UNIV)parm2;
|
|
err.errsp = (sizeof(pcbtab)/sizeof(pcbtab[0])) + ptrsrch(mdnmtab,
|
|
(UNIV)mdname);
|
|
error(&err);
|
|
}
|
|
/* SGMLERR: Process errors for SGML parser.
|
|
*/
|
|
VOID sgmlerr(number, pcb, parm1, parm2)
|
|
UNS number; /* Error number. */
|
|
struct parse *pcb; /* Current parse control block. */
|
|
UNCH *parm1; /* Error message parameters. */
|
|
UNCH *parm2; /* Error message parameters. */
|
|
{
|
|
struct error err;
|
|
errorinit(&err, DOCERR, number);
|
|
if (!pcb) pcb = prologsw ? propcb : conpcb;
|
|
err.errsp = ptrsrch(pcbtab, (UNIV)pcb);
|
|
err.eparm[0] = (UNIV)parm1;
|
|
err.eparm[1] = (UNIV)parm2;
|
|
error(&err);
|
|
}
|
|
/* SAVERR: Save an error for possible later use.
|
|
*/
|
|
UNIV saverr(number, pcb, parm1, parm2)
|
|
UNS number; /* Error number. */
|
|
struct parse *pcb; /* Current parse control block. */
|
|
UNCH *parm1; /* Error message parameters. */
|
|
UNCH *parm2; /* Error message parameters. */
|
|
{
|
|
struct error err;
|
|
errorinit(&err, DOCERR, number);
|
|
if (!pcb) pcb = prologsw ? propcb : conpcb;
|
|
err.errsp = ptrsrch(pcbtab, (UNIV)pcb);
|
|
err.eparm[0] = (UNIV)parm1;
|
|
err.eparm[1] = (UNIV)parm2;
|
|
scbset();
|
|
return msgsave(&err);
|
|
}
|
|
/* SVDERR: Print a saved error.
|
|
*/
|
|
VOID svderr(p)
|
|
UNIV p;
|
|
{
|
|
msgsprint(p);
|
|
}
|
|
/* EXITERR: Process terminal errors for SGML parser.
|
|
*/
|
|
VOID exiterr(number, pcb)
|
|
UNS number; /* Error number. */
|
|
struct parse *pcb; /* Current parse control block. */
|
|
{
|
|
struct error err;
|
|
errorinit(&err, EXITERR, number);
|
|
if (!pcb) pcb = prologsw ? propcb : conpcb;
|
|
err.errsp = ptrsrch(pcbtab, (UNIV)pcb);
|
|
error(&err);
|
|
/* The error handler should have exited. */
|
|
abort();
|
|
}
|
|
/* SYNERR: Process syntax errors for SGML parser.
|
|
*/
|
|
VOID synerr(number, pcb)
|
|
UNS number; /* Error number. */
|
|
struct parse *pcb; /* Current parse control block. */
|
|
{
|
|
struct error err;
|
|
errorinit(&err, DOCERR, number);
|
|
err.errsp = ptrsrch(pcbtab, (UNIV)pcb);
|
|
error(&err);
|
|
}
|
|
/* FILERR: Process a file access error.
|
|
*/
|
|
VOID filerr(number, parm)
|
|
UNS number;
|
|
UNCH *parm;
|
|
{
|
|
struct error err;
|
|
errorinit(&err, FILERR, number);
|
|
err.eparm[0] = (UNIV)parm;
|
|
err.sverrno = errno;
|
|
error(&err);
|
|
}
|
|
/* ERRORINIT: Constructor for struct error.
|
|
*/
|
|
VOID errorinit(e, type, number)
|
|
struct error *e;
|
|
UNS type;
|
|
UNS number;
|
|
{
|
|
int i;
|
|
e->errtype = type;
|
|
e->errnum = number;
|
|
e->errsp = 0;
|
|
for (i = 0; i < MAXARGS; i++)
|
|
e->eparm[i] = 0;
|
|
e->parmno = 0;
|
|
e->subdcl = 0;
|
|
}
|
|
/*
|
|
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:
|
|
*/
|