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