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