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