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