Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / programs / dtdocbook / sgmls / sgmlmsg.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: sgmlmsg.c /main/3 1996/06/19 17:17:57 drk $ */
24 /* sgmlmsg.c -
25    message handling for core parser
26
27    Written by James Clark (jjc@jclark.com).
28 */
29
30 #include "config.h"
31 #include "sgmlaux.h"
32 #include "msg.h"
33
34 static nl_catd catd;
35
36 #define TEXT_SET 1              /* message set number for text of messages */
37 #define HEADER_SET 2            /* message set number for header strings */
38 #define PARM_SET 3              /* message set number for special parameters */
39
40 #ifdef HAVE_EXTENDED_PRINTF
41 #define xfprintf fprintf
42 #else
43 extern int xfprintf VP((FILE *, char *,...));
44 #endif
45
46 #define SIZEOF(v) (sizeof(v)/sizeof(v[0]))
47
48 static char *gettext P((int));
49 static char *getheader P((int));
50 static char *getparm P((int));
51 static VOID elttrace P((FILE *, int));
52 static int printit P((FILE *, struct error *));
53 static char *transparm P((UNCH *, char *));
54 static VOID spaces P((FILE *, int));
55
56 #define PARMBUFSIZ 50
57 static char parmbuf[PARMBUFSIZ*2];
58 static char *parmbuf1 = parmbuf;
59 static char *parmbuf2 = parmbuf + PARMBUFSIZ;
60
61 static char *prog;              /* program name */
62 static int sweltr;              /* non-zero means print an element trace */
63 static int swenttr;             /* non-zero means print an entity trace */
64 static int cnterr = 0;
65 static VOID (*die) P((void));
66
67 static char *headers[] = {
68 "In file included",
69 "SGML error",                         /* parameters: type, severity, number */
70 "Unsupported feature",                /* type U errors */
71 "Error",                              /* for type R errors */
72 "Warning",                            /* severity type I */
73 " at %s, %.0sline %lu",               /* ignore entity name and ccnt */
74 " at entity %s, line %lu",
75 "%.0s%.0s in declaration parameter %d", /* ignore first two parameters */
76 "%.0s in declaration parameter %d",     /* ignore first parameter */
77 "%.0s",                                 /* parse mode */
78 " at end of file",
79 " at end of entity",
80 " at record start",
81 " at record end",
82 " at \"%c\"",
83 " at \"\\%03o\"",
84 " accessing \"%s\"",
85 "Element structure:"
86 };
87
88 /* Indexes into headers[] */
89
90 #define HDRPFX 0 
91 #define HDRALL 1 
92 #define HDRUNSUP 2 
93 #define HDRSYS 3 
94 #define HDRWARN 4 
95 #define HDRLOC 5 
96 #define HDRELOC 6 
97 #define HDRMD 7 
98 #define HDRMD2 8 
99 #define HDRMODE 9 
100 #define HDREOF 10
101 #define HDREE 11
102 #define HDRRS 12
103 #define HDRRE 13
104 #define HDRPRT 14
105 #define HDRCTL 15
106 #define HDRFIL 16
107 #define HDRELT 17
108
109 /* Special parameters (error::errsp) */
110 static char *parms[] = {
111 "character data",
112 "element content",
113 "mixed content",
114 "replaceable character data",
115 "tag close",
116 "content model group",
117 "content model occurrence indicator",
118 "name group",
119 "name token group",
120 "system data",
121 "parameter literal",
122 "attribute value literal",
123 "tokenized attribute value literal",
124 "minimum literal",
125 "markup declaration",
126 "markup declaration comment",
127 "ignored markup declaration",
128 "declaration subset",
129 "CDATA marked section",
130 "IGNORE marked section",
131 "RCDATA marked section",
132 "prolog",
133 "reference",
134 "attribute specification list",
135 "tokenized attribute value",
136 "attribute specification list close",
137 "SGML declaration",
138 "attribute definition list",
139 "document type",
140 "element",
141 "entity",
142 "link type",
143 "link set",
144 "notation",
145 "SGML",
146 "short reference mapping",
147 "link set use",
148 "short reference use",
149 };
150
151 static FILE *tfp;               /* temporary file for saved messages */
152
153 struct saved {
154      long start;
155      long end;
156      char exiterr;
157      char countit;
158 };
159
160 VOID msgprint(e)
161 struct error *e;
162 {
163      if (printit(stderr, e))
164           ++cnterr;
165      fflush(stderr);
166      if (e->errtype == EXITERR) {
167           if (die) {
168                (*die)();
169                abort();
170           }
171           else
172                exit(EXIT_FAILURE);
173      }
174 }
175
176 /* Save an error message. */
177
178 UNIV msgsave(e)
179 struct error *e;
180 {
181      struct saved *sv;
182
183      sv = (struct saved *)rmalloc(sizeof(struct saved));
184      if (!tfp) {
185           tfp = tmpfile();
186           if (!tfp)
187                exiterr(160, (struct parse *)0);
188      }
189      sv->start = ftell(tfp);
190      sv->countit = (char)printit(tfp, e);
191      sv->end = ftell(tfp);
192      sv->exiterr = (char)(e->errtype == EXITERR);
193      return (UNIV)sv;
194 }
195
196 /* Print a saved error message. */
197
198 VOID msgsprint(p)
199 UNIV p;
200 {
201      struct saved *sv = (struct saved *)p;
202      long cnt;
203
204      assert(p != 0);
205      assert(tfp != 0);
206      if (fseek(tfp, sv->start, SEEK_SET) < 0)
207           return;
208      /* Temporary files are opened in binary mode, so this is portable. */
209      cnt = sv->end - sv->start;
210      while (--cnt >= 0) {
211           int c = getc(tfp);
212           if (c == EOF)
213                break;
214           putc(c, stderr);
215      }
216      fflush(stderr);
217      if (sv->countit)
218           ++cnterr;
219      if (sv->exiterr)
220           exit(EXIT_FAILURE);
221 }
222
223 /* Free a sved error message. */
224
225 VOID msgsfree(p)
226 UNIV p;
227 {
228      frem(p);
229 }
230
231 /* Return 1 if it should be counted as an error. */
232
233 static int printit(efp, e)
234 FILE *efp;
235 struct error *e;
236 {
237      int indent;
238      int countit;
239      int hdrcode;
240      int filelevel = -1, prevfilelevel = -1, toplevel;
241      struct location loc;
242      char type[2], severity[2];
243
244      assert(e->errnum < SIZEOF(messages));
245      assert(messages[e->errnum].text != NULL);
246      if (prog) {
247           fprintf(efp, "%s: ", prog);
248           indent = strlen(prog) + 2; /* don't rely on return value of fprintf */
249           /* Don't want to waste too much space on indenting. */
250           if (indent > 10)
251                indent = 4;
252      }
253      else
254           indent = 4;
255      
256      for (toplevel = 0; getlocation(toplevel, &loc); toplevel++)
257           if (loc.filesw) {
258                prevfilelevel = filelevel;
259                filelevel = toplevel;
260           }
261      toplevel--;
262
263      if (e->errtype == FILERR) {
264           toplevel--;
265           filelevel = prevfilelevel;
266      }
267      if (swenttr && filelevel > 0) {
268           int level = 0;
269           int middle = 0;       /* in the middle of a line */
270           do {
271                (void)getlocation(level, &loc);
272                if (loc.filesw) {
273                     if (middle) {
274                          fputs(":\n", efp);
275                          spaces(efp, indent);
276                     }
277                     else
278                          middle = 1;
279                     xfprintf(efp, getheader(HDRPFX));
280                     xfprintf(efp, getheader(HDRLOC), ioflid(loc.fcb),
281                              loc.ename, loc.rcnt, loc.ccnt);
282                }
283                else if (middle)
284                     xfprintf(efp, getheader(HDRELOC),
285                              loc.ename, loc.rcnt + 1, loc.ccnt);
286           }
287           while (++level != filelevel);
288           if (middle) {
289                fputs(":\n", efp);
290                spaces(efp, indent);
291           }
292      }
293
294      /* We use strings for the type and severity,
295         so that the format can use %.0s to ignore them. */
296
297      type[0] = messages[e->errnum].type;
298      type[1] = '\0';
299      severity[0] = messages[e->errnum].severity;
300      severity[1] = '\0';
301
302      countit = (severity[0] != 'I');
303      if (!countit)
304           hdrcode = HDRWARN;
305      else if (type[0] == 'R')
306           hdrcode = HDRSYS;
307      else if (type[0] == 'U')
308           hdrcode = HDRUNSUP;
309      else
310           hdrcode = HDRALL;
311           
312      xfprintf(efp, getheader(hdrcode), type, severity, e->errnum);
313
314      if (filelevel >= 0) {
315           (void)getlocation(filelevel, &loc);
316           xfprintf(efp, getheader(HDRLOC),
317                    ioflid(loc.fcb), loc.ename, loc.rcnt, loc.ccnt);
318           while (filelevel < toplevel) {
319                ++filelevel;
320                if (swenttr) {
321                     (void)getlocation(filelevel, &loc);
322                     xfprintf(efp, getheader(HDRELOC),
323                              loc.ename, loc.rcnt + 1, loc.ccnt);
324                }
325           }
326      }
327      
328      /* It is necessary to copy the result of getparm() because
329         the specification of catgets() says in can return a 
330         pointer to a static buffer which may get overwritten
331         by the next call to catgets(). */
332
333      switch (e->errtype) {
334      case MDERR:
335           strncpy(parmbuf, getparm(e->errsp), PARMBUFSIZ*2 - 1);
336           xfprintf(efp, getheader(HDRMD), parmbuf,
337                    (e->subdcl ? e->subdcl : (UNCH *)""), e->parmno);
338           break;
339      case MDERR2:
340           /* no subdcl parameter */
341           strncpy(parmbuf, getparm(e->errsp), PARMBUFSIZ*2 - 1);
342           xfprintf(efp, getheader(HDRMD2), parmbuf, e->parmno);
343           break;
344      case DOCERR:
345      case EXITERR:
346           if (toplevel < 0)
347                break;
348           strncpy(parmbuf, getparm(e->errsp), PARMBUFSIZ*2 - 1);
349           xfprintf(efp, getheader(HDRMODE), parmbuf);
350           switch (loc.curchar) {
351           case EOFCHAR:
352                xfprintf(efp, getheader(HDREOF));
353                break;
354           case RSCHAR:
355                xfprintf(efp, getheader(HDRRS));
356                break;
357           case RECHAR:
358                xfprintf(efp, getheader(HDRRE));
359                break;
360           case DELNONCH:
361                xfprintf(efp, getheader(HDRCTL), UNSHIFTNON(loc.nextchar));
362                break;
363           case EOS:
364                xfprintf(efp, getheader(HDREE));
365                break;
366           case EOBCHAR:
367                break;
368           default:
369                if (ISASCII(loc.curchar) && isprint(loc.curchar))
370                     xfprintf(efp, getheader(HDRPRT), loc.curchar);
371                else
372                     xfprintf(efp, getheader(HDRCTL), loc.curchar);
373                break;
374           }
375           break;
376      case FILERR:
377           if (getlocation(toplevel + 1, &loc))
378                xfprintf(efp, getheader(HDRFIL), ioflid(loc.fcb));
379           break;
380      }
381      fputs(":\n", efp);
382
383      if (e->errtype == FILERR && e->sverrno != 0) {
384           char *errstr = strerror(e->sverrno);
385           UNS len = strlen(errstr);
386           /* Strip a trailing newline if there is one. */
387           if (len > 0 && errstr[len - 1] == '\n')
388                len--;
389           spaces(efp, indent);
390           for (; len > 0; len--, errstr++)
391                putc(*errstr, efp);
392           fputs(":\n", efp);
393      }
394
395      spaces(efp, indent);
396
397      xfprintf(efp, gettext(e->errnum),
398               transparm((UNCH *)e->eparm[0], parmbuf1),
399               transparm((UNCH *)e->eparm[1], parmbuf2));
400      putc('\n', efp);
401
402      if (sweltr)
403           elttrace(efp, indent);
404      return countit;
405 }
406
407 /* Print an element trace. */
408 static VOID elttrace(efp, indent)
409 FILE *efp;
410 int indent;
411 {
412      int i = 1;
413      UNCH *gi;
414      
415      gi = getgi(i);
416      if (!gi)
417           return;
418      spaces(efp, indent);
419      xfprintf(efp, getheader(HDRELT));
420      do {
421           fprintf(efp, " %s", gi);
422           gi = getgi(++i);
423      } while (gi);
424      putc('\n', efp);
425 }
426
427 static VOID spaces(efp, indent)
428 FILE *efp;
429 int indent;
430 {
431      while (--indent >= 0)
432           putc(' ', efp);
433 }
434
435 VOID msginit(swp)
436 struct switches *swp;
437 {
438      catd = swp->catd;
439      prog = swp->prog;
440      sweltr = swp->sweltr;
441      swenttr = swp->swenttr;
442      die = swp->die;
443 }
444
445 /* Return the error count. */
446
447 int msgcnterr()
448 {
449      return cnterr;
450 }
451
452 /* Transform a parameter into a form suitable for printing. */
453
454 static char *transparm(s, buf)
455 UNCH *s;
456 char *buf;
457 {
458      char *ptr;
459      int cnt;
460
461      if (!s)
462           return 0;
463
464      ptr = buf;
465      cnt = PARMBUFSIZ - 4;      /* space for `...\0'  */
466
467      while (*s) {
468           UNCH ch = *s++;
469           if (ch == DELNONCH) {
470                if (*s == '\0')
471                     break;
472                ch = UNSHIFTNON(*s);
473                s++;
474           }
475           if (ch == DELCDATA || ch == DELSDATA)
476                ;
477           else if (ch == '\\') {
478                if (cnt < 2)
479                     break;
480                *ptr++ = '\\';
481                *ptr++ = '\\';
482                cnt -= 2;
483           }
484           else if (ISASCII(ch) && isprint(ch)) {
485                if (cnt < 1)
486                     break;
487                *ptr++ = ch;
488                cnt--;
489           }
490           else {
491                if (cnt < 4)
492                     break;
493                sprintf(ptr, "\\%03o", ch);
494                ptr += 4;
495                cnt -= 4;
496           }
497      }
498      if (!*s)
499           *ptr = '\0';
500      else
501           strcpy(ptr, "...");
502      return buf;
503 }
504
505 /* The message and set numbers in the catgets function must be > 0. */
506
507 static char *gettext(n)
508 int n;
509 {
510      assert(n > 0 && n < SIZEOF(messages));
511      assert(messages[n].text != 0);
512      return catgets(catd, TEXT_SET, n, messages[n].text);
513 }
514
515 static char *getheader(n)
516 int n;
517 {
518      assert(n >= 0 && n < SIZEOF(headers));
519      return catgets(catd, HEADER_SET, n + 1, headers[n]);
520 }
521
522 static char *getparm(n)
523 int n;
524 {
525      assert(n >= 0 && n < SIZEOF(parms));
526      return catgets(catd, PARM_SET, n + 1, parms[n]);
527 }
528
529 /*
530 Local Variables:
531 c-indent-level: 5
532 c-continued-statement-offset: 5
533 c-brace-offset: -5
534 c-argdecl-indent: 0
535 c-label-offset: -5
536 End:
537 */