1 /* Added exiterr() for terminal errors to prevent SGML.MSG errors. */
2 #include "sgmlincl.h" /* #INCLUDE statements for SGML parser. */
3 static int iorc; /* Return code from io* functions */
4 /* ENTDEF: Process an entity definition and return the pointer to it.
5 The entity text must be in permanent storage.
6 There is no checking to see if the entity already exists;
7 the caller must have done that.
8 */
9 #ifdef USE_PROTOTYPES
entdef(UNCH * ename,UNCH estore,union etext * petx)10 PECB entdef(UNCH *ename, UNCH estore, union etext *petx)
11 #else
12 PECB entdef(ename, estore, petx)
13 UNCH *ename; /* Entity name (with length and EOS). */
14 UNCH estore; /* Entity storage class. */
15 union etext *petx; /* Ptr to entity text union. */
16 #endif
17 {
18 PECB p;
19
20 p = (PECB)hin((THASH)etab, ename, hash(ename, ENTHASH), ENTSZ);
21 memcpy((UNIV)&p->etx, (UNIV)petx, ETEXTSZ);
22 p->estore = estore;
23 TRACEECB("ENTDEF", p);
24 return(p);
25 }
26 /* ENTFIND: If an entity exists, return ptr to its ecb.
27 Return NULL if it is not defined.
28 */
entfind(ename)29 PECB entfind(ename)
30 UNCH *ename; /* Entity name (with length and EOS). */
31 {
32 PECB p;
33
34 p = (PECB)hfind((THASH)etab, ename, hash(ename, ENTHASH));
35 TRACEECB("ENTFIND", p);
36 return p;
37 }
38 /* ENTREF: Process a general or parameter entity reference.
39 If the entity is defined it returns the return code from ENTOPEN.
40 It returns ENTUNDEF for undefined parameter entity references
41 and for general entity references when defaulting is not allowed.
42 Otherwise, it uses the default entity text.
43 */
entref(ename)44 int entref(ename)
45 UNCH *ename; /* Entity name (with length and EOS). */
46 {
47 PECB ecb; /* Entity control block. */
48
49 /* Get the entity control block, if the entity has been defined. */
50 if ((ecb = (PECB)hfind((THASH)etab, ename, hash(ename, ENTHASH)))==0
51 || ecb->estore == 0) {
52 if (ename[1] == lex.d.pero || ecbdeflt == 0) {
53 sgmlerr(35, (struct parse *)0, ename+1, (UNCH *)0);
54 return(ENTUNDEF);
55 }
56 else
57 ecb = usedef(ename);
58 }
59 return(entopen(ecb));
60 }
61 /* ENTOPEN: Open a newly referenced entity.
62 Increment the stack pointer (es) and initialize the new entry.
63 ENTDATA if entity is CDATA or SDATA, ENTPI if it is PI,
64 0 if normal and all o.k.; <0 if not.
65 */
entopen(ecb)66 int entopen(ecb)
67 struct entity *ecb; /* Entity control block. */
68 {
69 int i; /* Loop counter. */
70
71 /* See if we have exceeded the entity nesting level. */
72 if (es>=ENTLVL) {
73 sgmlerr(34, (struct parse *)0, ecb->ename+1, ntoa(ENTLVL));
74 return(ENTMAX);
75 }
76 if (docelsw) sgmlerr(234, (struct parse *)0, (UNCH *)0, (UNCH *)0);
77 /* If entity is an etd, pi, or data, return it without creating an scb. */
78 switch (ecb->estore) {
79 case ESN:
80 if (NEXTYPE(ecb->etx.n)!=ESNSUB) {
81 if (!NEDCNDEFINED(ecb->etx.n))
82 sgmlerr(78, (struct parse *)0, NEDCN(ecb->etx.n)+1,
83 ecb->ename+1);
84 }
85 else {
86 #if 0
87 if (!NEID(ecb->etx.n)) {
88 sgmlerr(149, (struct parse *)0, ecb->ename + 1, (UNCH *)0);
89 return ENTFILE;
90 }
91 #endif
92 if (sw.nopen >= sd.subdoc)
93 sgmlerr(188, (struct parse *)0,
94 (UNCH *)NULL, (UNCH *)NULL);
95 }
96 data = (UNCH *)ecb->etx.n;
97 entdatsw = NDECONT;
98 return(ENTDATA);
99 case ESC:
100 case ESX:
101 datalen = ustrlen(ecb->etx.c);
102 /* Ignore reference to empty CDATA entity. */
103 if (datalen == 0 && ecb->estore == ESC) return(0);
104 data = ecb->etx.c;
105 entdatsw = (ecb->estore==ESC) ? CDECONT : SDECONT;
106 return(ENTDATA);
107 case ESI:
108 datalen = ustrlen(ecb->etx.c);
109 data = ecb->etx.c;
110 entpisw = 4;
111 return(ENTPI);
112 }
113 /* If the same entity is already open, send msg and ignore it.
114 Level 0 needn't be tested, as its entity name is always *DOC.
115 */
116 for (i = 0; ++i<=es;) if (scbs[i].ecb.enext==ecb) {
117 sgmlerr(36, (struct parse *)0, ecb->ename+1, (UNCH *)0);
118 return(ENTLOOP);
119 }
120 /* Update SCB if entity trace is wanted in messages or entity is a file.
121 (Avoid this at start when es==-1 or memory will be corrupted.)
122 */
123 if (es >= 0 && (sw.swenttr || FILESW)) scbset();
124
125 /* Stack the new source control block (we know there is room). */
126 ++es; /* Increment scbs index. */
127 RCNT = CCO = RSCC = 0; /* No records or chars yet. */
128 COPIEDSW = 0;
129 memcpy((UNIV)&ECB, (UNIV)ecb, (UNS)ENTSZ); /* Copy the ecb into the scb. */
130 ECBPTR = ecb; /* Save the ecb pointer in scb.ecb.enext. */
131 TRACEECB("ENTOPEN", ECBPTR);
132
133 /* For memory entities, the read buffer is the entity text.
134 The text starts at FBUF, so FPOS should be FBUF-1
135 because it is bumped before each character is read.
136 */
137 if (ECB.estore<ESFM) {FPOS = (FBUF = ECB.etx.c)-1; return 0;}
138
139 /* For file entities, suspend any open file and do first read. */
140 if (ECB.etx.x == 0) {
141 --es;
142 switch (ecb->estore) {
143 case ESF:
144 sgmlerr(149, (struct parse *)0, ecb->ename + 1, (UNCH *)0);
145 break;
146 case ESP:
147 sgmlerr(229, (struct parse *)0, ecb->ename + 2, (UNCH *)0);
148 break;
149 default:
150 abort();
151 }
152 return ENTFILE;
153 }
154 fileopen(); /* Open new external file. */
155 if (iorc<0) { /* If open not successful: */
156 FPOS = FBUF-1; /* Clean CCNT for OPEN error msg.*/
157 filerr(32, ecb->ename+1);
158 --es; /* Pop the stack. */
159 return(ENTFILE);
160 }
161 filepend(es); /* Suspend any open file. */
162 fileread(); /* First read of file must be ok.*/
163 return 0;
164 }
165 /* ENTGET: Get next record of entity (if there is one).
166 Otherwise, close the file (if entity is a file) and
167 pop the entity stack. If nothing else is on the stack,
168 return -1 to advise the caller.
169 */
entget()170 int entget()
171 {
172 RSCC += (CCO = FPOS-FBUF);
173 /* Characters-in-record (ignore EOB/EOF). */
174 if (es == tages)
175 tagctr += CCO; /* Update tag length counter. */
176 switch (*FPOS) {
177 case EOBCHAR: /* End of file buffer: refill it. */
178 rbufs[-2] = FPOS[-2];
179 rbufs[-1] = FPOS[-1];
180 fileread(); /* Read the file. */
181 if (iorc > 0) break;
182 readerr:
183 filerr(31, ENTITY+1); /* Treat error as EOF. */
184 case EOFCHAR: /* End of file: close it. */
185 fileclos(); /* Call SGMLIO to close file. */
186 conterr:
187 if (es==0) { /* Report if it is primary file. */
188 FPOS = FBUF-1; /* Preserve CCNT for omitted end-tags. */
189 return -1;
190 }
191 case EOS: /* End of memory entity: pop the stack. */
192 TRACEECB("ENTPOP", ECBPTR);
193 if (COPIEDSW) {
194 frem((UNIV)(FBUF + 1));
195 COPIEDSW = 0;
196 }
197 --es; /* Pop the SCB stack. */
198 if (FBUF) break; /* Not a PEND file. */
199 filecont(); /* Resume previous file. */
200 if (iorc<0) { /* If CONT not successful: */
201 filerr(94, ENTITY+1);
202 goto conterr;
203 }
204 fileread(); /* Read the file. */
205 if (iorc<=0) goto readerr; /* If READ not successful: */
206 rbufs[-1] = SCB.pushback;
207 FPOS += CCO;
208 CCO = 0;
209 if (delmscsw && es==0) { /* End of DTD. */
210 delmscsw = 0;
211 *rbufs = lex.d.msc;
212 }
213 break;
214 }
215 return 0;
216 }
217 /* USEDEF: Use the default value for an entity reference.
218 Returns the ECB for the defaulted entity.
219 */
usedef(ename)220 PECB usedef(ename)
221 UNCH *ename; /* Entity name (with length and EOS). */
222 {
223 union etext etx; /* Save return from entgen. */
224 PECB ecb; /* Entity control block. */
225 PNE pne = 0; /* Ptr to NDATA entity control block. */
226 UNCH estore; /* Default entity storage type. */
227
228 if ((estore = ecbdeflt->estore)<ESFM) /* Default is an internal string. */
229 etx.c = ecbdeflt->etx.c;
230 else {
231 /* Move entity name into fpi. */
232 fpidf.fpinm = ename + 1;
233 if ((etx.x = entgen(&fpidf))==0)
234 sgmlerr(150, (struct parse *)0, ename + 1, (UNCH *)0);
235 if (estore==ESN) {
236 memcpy((UNIV)(pne=(PNE)rmalloc((UNS)NESZ)),(UNIV)ecbdeflt->etx.n,(UNS)NESZ);
237 NEID(pne) = etx.x;
238 etx.n = pne;
239 }
240 }
241 if (sw.swrefmsg) sgmlerr(45, (struct parse *)0, ename+1, (UNCH *)0);
242 ++ds.ecbcnt;
243 ecb = entdef(ename, estore, &etx);
244 ecb->dflt = 1;
245 if (pne) NEENAME(pne) = ecb->ename;
246 return(ecb);
247 }
248 /* SCBSET: Set source control block to current location in the current entity.
249 This routine is called by SGML when it returns to the text
250 processor and by ERROR when it reports an error.
251 */
scbset()252 VOID scbset()
253 {
254 if (es >= 0 && FBUF) {
255 CC = *FPOS;
256 if (*FPOS == DELNONCH)
257 NEXTC = FPOS[1];
258 else
259 NEXTC = 0;
260 CCO = FPOS + 1 - FBUF;
261 }
262 }
263 /* FILEOPEN: Call IOOPEN to open an external entity (file).
264 */
fileopen()265 VOID fileopen() /* Open an external entity's file. */
266 {
267 iorc = ioopen(ECB.etx.x, &SCBFCB);
268 }
269 /* FILEREAD: Call IOREAD to read an open external entity (file).
270 */
fileread()271 VOID fileread() /* Read the current external entity's file. */
272 {
273 int newfile;
274 iorc = ioread(SCBFCB, rbufs, &newfile);
275 FPOS = (FBUF = rbufs) - 1; /* Actual read buffer. */
276 if (newfile) RCNT = 0;
277 }
278 /* FILEPEND: Call IOPEND to close an open external entity (file) temporarily.
279 */
filepend(es)280 VOID filepend(es) /* Close the current external entity's file. */
281 int es; /* Local index to scbs. */
282 {
283 while (--es>=0) { /* Find last external file on stack. */
284 int off;
285 if (!FILESW) continue; /* Not an external file. */
286 if (!FBUF) continue; /* Already suspended. */
287 off = CCO;
288 assert(off >= -1);
289 if (off < 0) off = 0;
290 else CCO = 0;
291 FPOS -= CCO;
292 SCB.pushback = FPOS[-1];
293 FBUF = 0; /* Indicate pending file. */
294 RSCC += off; /* Update characters-in-record counter. */
295 if (es == tages)
296 tagctr += off; /* Update tag length counter. */
297 iopend(SCBFCB, off, rbufs);
298 return;
299 }
300 }
301 /* FILECONT: Call IOCONT to reopen an external entity (file).
302 */
filecont()303 VOID filecont() /* Open an external entity's file. */
304 {
305 iorc = iocont(SCBFCB);
306 }
307 /* FILECLOS: Call IOCLOSE to close an open external entity (file).
308 */
fileclos()309 VOID fileclos() /* Close the current external entity's file. */
310 {
311 if (!SCBFCB)
312 return;
313 ioclose(SCBFCB);
314 /* The fcb will have been freed by sgmlio.
315 Make sure we don't access it again. */
316 SCBFCB = NULL;
317 }
318 /* ERROR: Interface to text processor SGML I/O services for error handling.
319 */
error(e)320 VOID error(e)
321 struct error *e;
322 {
323 scbset(); /* Update location in source control block. */
324 msgprint(e);
325 }
326 /* PTRSRCH: Find a pointer in a list and return its index.
327 Search key must be on list as there is no limit test.
328 This routine is internal only -- not for user data.
329 */
330 UNIV mdnmtab[] = {
331 (UNIV)key[KATTLIST],
332 (UNIV)key[KDOCTYPE],
333 (UNIV)key[KELEMENT],
334 (UNIV)key[KENTITY],
335 (UNIV)key[KLINKTYPE],
336 (UNIV)key[KLINK],
337 (UNIV)key[KNOTATION],
338 (UNIV)sgmlkey,
339 (UNIV)key[KSHORTREF],
340 (UNIV)key[KUSELINK],
341 (UNIV)key[KUSEMAP]
342 };
343 UNIV pcbtab[] = {
344 (UNIV)&pcbconc,
345 (UNIV)&pcbcone,
346 (UNIV)&pcbconm,
347 (UNIV)&pcbconr,
348 (UNIV)&pcbetag,
349 (UNIV)&pcbgrcm,
350 (UNIV)&pcbgrcs,
351 (UNIV)&pcbgrnm,
352 (UNIV)&pcbgrnt,
353 (UNIV)&pcblitc,
354 (UNIV)&pcblitp,
355 (UNIV)&pcblitr,
356 (UNIV)&pcblitt,
357 (UNIV)&pcblitv,
358 (UNIV)&pcbmd,
359 (UNIV)&pcbmdc,
360 (UNIV)&pcbmdi,
361 (UNIV)&pcbmds,
362 (UNIV)&pcbmsc,
363 (UNIV)&pcbmsi,
364 (UNIV)&pcbmsrc,
365 (UNIV)&pcbpro,
366 (UNIV)&pcbref,
367 (UNIV)&pcbstag,
368 (UNIV)&pcbval,
369 (UNIV)&pcbeal,
370 (UNIV)&pcbsd,
371 };
ptrsrch(ptrtab,ptr)372 UNS ptrsrch(ptrtab, ptr)
373 UNIV ptrtab[];
374 UNIV ptr;
375 {
376 UNS i;
377
378 for (i = 0; ; ++i)
379 if (ptrtab[i] == ptr)
380 break;
381 return i;
382 }
383 /* MDERR: Process errors for markup declarations.
384 Prepare the special parameters that only exist for
385 markup declaration errors.
386 */
mderr(number,parm1,parm2)387 VOID mderr(number, parm1, parm2)
388 UNS number; /* Error number. */
389 UNCH *parm1; /* Additional parameters (or NULL). */
390 UNCH *parm2; /* Additional parameters (or NULL). */
391 {
392 struct error err;
393 errorinit(&err, subdcl ? MDERR : MDERR2, number);
394 err.parmno = parmno;
395 err.subdcl = subdcl;
396 err.eparm[0] = (UNIV)parm1;
397 err.eparm[1] = (UNIV)parm2;
398 err.errsp = (sizeof(pcbtab)/sizeof(pcbtab[0])) + ptrsrch(mdnmtab,
399 (UNIV)mdname);
400 error(&err);
401 }
402 /* SGMLERR: Process errors for SGML parser.
403 */
sgmlerr(number,pcb,parm1,parm2)404 VOID sgmlerr(number, pcb, parm1, parm2)
405 UNS number; /* Error number. */
406 struct parse *pcb; /* Current parse control block. */
407 UNCH *parm1; /* Error message parameters. */
408 UNCH *parm2; /* Error message parameters. */
409 {
410 struct error err;
411 errorinit(&err, DOCERR, number);
412 if (!pcb) pcb = prologsw ? propcb : conpcb;
413 err.errsp = ptrsrch(pcbtab, (UNIV)pcb);
414 err.eparm[0] = (UNIV)parm1;
415 err.eparm[1] = (UNIV)parm2;
416 error(&err);
417 }
418 /* SAVERR: Save an error for possible later use.
419 */
saverr(number,pcb,parm1,parm2)420 UNIV saverr(number, pcb, parm1, parm2)
421 UNS number; /* Error number. */
422 struct parse *pcb; /* Current parse control block. */
423 UNCH *parm1; /* Error message parameters. */
424 UNCH *parm2; /* Error message parameters. */
425 {
426 struct error err;
427 errorinit(&err, DOCERR, number);
428 if (!pcb) pcb = prologsw ? propcb : conpcb;
429 err.errsp = ptrsrch(pcbtab, (UNIV)pcb);
430 err.eparm[0] = (UNIV)parm1;
431 err.eparm[1] = (UNIV)parm2;
432 scbset();
433 return msgsave(&err);
434 }
435 /* SAVMDERR: Save an md error for possible later use.
436 */
savmderr(number,parm1,parm2)437 UNIV savmderr(number, parm1, parm2)
438 UNS number; /* Error number. */
439 UNCH *parm1; /* Additional parameters (or NULL). */
440 UNCH *parm2; /* Additional parameters (or NULL). */
441 {
442 struct error err;
443 errorinit(&err, subdcl ? MDERR : MDERR2, number);
444 err.parmno = parmno;
445 err.subdcl = subdcl;
446 err.eparm[0] = (UNIV)parm1;
447 err.eparm[1] = (UNIV)parm2;
448 err.errsp = (sizeof(pcbtab)/sizeof(pcbtab[0])) + ptrsrch(mdnmtab,
449 (UNIV)mdname);
450 scbset();
451 return msgsave(&err);
452 }
453 /* SVDERR: Print a saved error.
454 */
svderr(p)455 VOID svderr(p)
456 UNIV p;
457 {
458 msgsprint(p);
459 }
460 /* EXITERR: Process terminal errors for SGML parser.
461 */
exiterr(number,pcb)462 VOID exiterr(number, pcb)
463 UNS number; /* Error number. */
464 struct parse *pcb; /* Current parse control block. */
465 {
466 struct error err;
467 errorinit(&err, EXITERR, number);
468 if (!pcb) pcb = prologsw ? propcb : conpcb;
469 err.errsp = ptrsrch(pcbtab, (UNIV)pcb);
470 error(&err);
471 /* The error handler should have exited. */
472 abort();
473 }
474 /* SYNERR: Process syntax errors for SGML parser.
475 */
synerr(number,pcb)476 VOID synerr(number, pcb)
477 UNS number; /* Error number. */
478 struct parse *pcb; /* Current parse control block. */
479 {
480 struct error err;
481 errorinit(&err, DOCERR, number);
482 err.errsp = ptrsrch(pcbtab, (UNIV)pcb);
483 error(&err);
484 }
485 /* FILERR: Process a file access error.
486 */
filerr(number,parm)487 VOID filerr(number, parm)
488 UNS number;
489 UNCH *parm;
490 {
491 struct error err;
492 errorinit(&err, FILERR, number);
493 err.eparm[0] = (UNIV)parm;
494 err.sverrno = errno;
495 error(&err);
496 }
497 /* ERRORINIT: Constructor for struct error.
498 */
errorinit(e,type,number)499 VOID errorinit(e, type, number)
500 struct error *e;
501 UNS type;
502 UNS number;
503 {
504 int i;
505 e->errtype = type;
506 e->errnum = number;
507 e->errsp = 0;
508 for (i = 0; i < MAXARGS; i++)
509 e->eparm[i] = 0;
510 e->parmno = 0;
511 e->subdcl = 0;
512 }
513 /*
514 Local Variables:
515 c-indent-level: 5
516 c-continued-statement-offset: 5
517 c-brace-offset: -5
518 c-argdecl-indent: 0
519 c-label-offset: -5
520 comment-column: 30
521 End:
522 */
523