538 lines
12 KiB
C
538 lines
12 KiB
C
/*
|
|
* CDE - Common Desktop Environment
|
|
*
|
|
* Copyright (c) 1993-2012, The Open Group. All rights reserved.
|
|
*
|
|
* These libraries and programs are free software; you can
|
|
* redistribute them and/or modify them under the terms of the GNU
|
|
* Lesser General Public License as published by the Free Software
|
|
* Foundation; either version 2 of the License, or (at your option)
|
|
* any later version.
|
|
*
|
|
* These libraries and programs are distributed in the hope that
|
|
* they will be useful, but WITHOUT ANY WARRANTY; without even the
|
|
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
* PURPOSE. See the GNU Lesser General Public License for more
|
|
* details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with these librararies and programs; if not, write
|
|
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
|
|
* Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
/* $XConsortium: sgmlmsg.c /main/3 1996/06/19 17:17:57 drk $ */
|
|
/* sgmlmsg.c -
|
|
message handling for core parser
|
|
|
|
Written by James Clark (jjc@jclark.com).
|
|
*/
|
|
|
|
#include "config.h"
|
|
#include "sgmlaux.h"
|
|
#include "msg.h"
|
|
|
|
static nl_catd catd;
|
|
|
|
#define TEXT_SET 1 /* message set number for text of messages */
|
|
#define HEADER_SET 2 /* message set number for header strings */
|
|
#define PARM_SET 3 /* message set number for special parameters */
|
|
|
|
#ifdef HAVE_EXTENDED_PRINTF
|
|
#define xfprintf fprintf
|
|
#else
|
|
extern int xfprintf VP((FILE *, char *,...));
|
|
#endif
|
|
|
|
#define SIZEOF(v) (sizeof(v)/sizeof(v[0]))
|
|
|
|
static char *gettext P((int));
|
|
static char *getheader P((int));
|
|
static char *getparm P((int));
|
|
static VOID elttrace P((FILE *, int));
|
|
static int printit P((FILE *, struct error *));
|
|
static char *transparm P((UNCH *, char *));
|
|
static VOID spaces P((FILE *, int));
|
|
|
|
#define PARMBUFSIZ 50
|
|
static char parmbuf[PARMBUFSIZ*2];
|
|
static char *parmbuf1 = parmbuf;
|
|
static char *parmbuf2 = parmbuf + PARMBUFSIZ;
|
|
|
|
static char *prog; /* program name */
|
|
static int sweltr; /* non-zero means print an element trace */
|
|
static int swenttr; /* non-zero means print an entity trace */
|
|
static int cnterr = 0;
|
|
static VOID (*die) P((void));
|
|
|
|
static char *headers[] = {
|
|
"In file included",
|
|
"SGML error", /* parameters: type, severity, number */
|
|
"Unsupported feature", /* type U errors */
|
|
"Error", /* for type R errors */
|
|
"Warning", /* severity type I */
|
|
" at %s, %.0sline %lu", /* ignore entity name and ccnt */
|
|
" at entity %s, line %lu",
|
|
"%.0s%.0s in declaration parameter %d", /* ignore first two parameters */
|
|
"%.0s in declaration parameter %d", /* ignore first parameter */
|
|
"%.0s", /* parse mode */
|
|
" at end of file",
|
|
" at end of entity",
|
|
" at record start",
|
|
" at record end",
|
|
" at \"%c\"",
|
|
" at \"\\%03o\"",
|
|
" accessing \"%s\"",
|
|
"Element structure:"
|
|
};
|
|
|
|
/* Indexes into headers[] */
|
|
|
|
#define HDRPFX 0
|
|
#define HDRALL 1
|
|
#define HDRUNSUP 2
|
|
#define HDRSYS 3
|
|
#define HDRWARN 4
|
|
#define HDRLOC 5
|
|
#define HDRELOC 6
|
|
#define HDRMD 7
|
|
#define HDRMD2 8
|
|
#define HDRMODE 9
|
|
#define HDREOF 10
|
|
#define HDREE 11
|
|
#define HDRRS 12
|
|
#define HDRRE 13
|
|
#define HDRPRT 14
|
|
#define HDRCTL 15
|
|
#define HDRFIL 16
|
|
#define HDRELT 17
|
|
|
|
/* Special parameters (error::errsp) */
|
|
static char *parms[] = {
|
|
"character data",
|
|
"element content",
|
|
"mixed content",
|
|
"replaceable character data",
|
|
"tag close",
|
|
"content model group",
|
|
"content model occurrence indicator",
|
|
"name group",
|
|
"name token group",
|
|
"system data",
|
|
"parameter literal",
|
|
"attribute value literal",
|
|
"tokenized attribute value literal",
|
|
"minimum literal",
|
|
"markup declaration",
|
|
"markup declaration comment",
|
|
"ignored markup declaration",
|
|
"declaration subset",
|
|
"CDATA marked section",
|
|
"IGNORE marked section",
|
|
"RCDATA marked section",
|
|
"prolog",
|
|
"reference",
|
|
"attribute specification list",
|
|
"tokenized attribute value",
|
|
"attribute specification list close",
|
|
"SGML declaration",
|
|
"attribute definition list",
|
|
"document type",
|
|
"element",
|
|
"entity",
|
|
"link type",
|
|
"link set",
|
|
"notation",
|
|
"SGML",
|
|
"short reference mapping",
|
|
"link set use",
|
|
"short reference use",
|
|
};
|
|
|
|
static FILE *tfp; /* temporary file for saved messages */
|
|
|
|
struct saved {
|
|
long start;
|
|
long end;
|
|
char exiterr;
|
|
char countit;
|
|
};
|
|
|
|
VOID msgprint(e)
|
|
struct error *e;
|
|
{
|
|
if (printit(stderr, e))
|
|
++cnterr;
|
|
fflush(stderr);
|
|
if (e->errtype == EXITERR) {
|
|
if (die) {
|
|
(*die)();
|
|
abort();
|
|
}
|
|
else
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
}
|
|
|
|
/* Save an error message. */
|
|
|
|
UNIV msgsave(e)
|
|
struct error *e;
|
|
{
|
|
struct saved *sv;
|
|
|
|
sv = (struct saved *)rmalloc(sizeof(struct saved));
|
|
if (!tfp) {
|
|
tfp = tmpfile();
|
|
if (!tfp)
|
|
exiterr(160, (struct parse *)0);
|
|
}
|
|
sv->start = ftell(tfp);
|
|
sv->countit = (char)printit(tfp, e);
|
|
sv->end = ftell(tfp);
|
|
sv->exiterr = (char)(e->errtype == EXITERR);
|
|
return (UNIV)sv;
|
|
}
|
|
|
|
/* Print a saved error message. */
|
|
|
|
VOID msgsprint(p)
|
|
UNIV p;
|
|
{
|
|
struct saved *sv = (struct saved *)p;
|
|
long cnt;
|
|
|
|
assert(p != 0);
|
|
assert(tfp != 0);
|
|
if (fseek(tfp, sv->start, SEEK_SET) < 0)
|
|
return;
|
|
/* Temporary files are opened in binary mode, so this is portable. */
|
|
cnt = sv->end - sv->start;
|
|
while (--cnt >= 0) {
|
|
int c = getc(tfp);
|
|
if (c == EOF)
|
|
break;
|
|
putc(c, stderr);
|
|
}
|
|
fflush(stderr);
|
|
if (sv->countit)
|
|
++cnterr;
|
|
if (sv->exiterr)
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
/* Free a sved error message. */
|
|
|
|
VOID msgsfree(p)
|
|
UNIV p;
|
|
{
|
|
frem(p);
|
|
}
|
|
|
|
/* Return 1 if it should be counted as an error. */
|
|
|
|
static int printit(efp, e)
|
|
FILE *efp;
|
|
struct error *e;
|
|
{
|
|
int indent;
|
|
int countit;
|
|
int hdrcode;
|
|
int filelevel = -1, prevfilelevel = -1, toplevel;
|
|
struct location loc;
|
|
char type[2], severity[2];
|
|
|
|
assert(e->errnum < SIZEOF(messages));
|
|
assert(messages[e->errnum].text != NULL);
|
|
if (prog) {
|
|
fprintf(efp, "%s: ", prog);
|
|
indent = strlen(prog) + 2; /* don't rely on return value of fprintf */
|
|
/* Don't want to waste too much space on indenting. */
|
|
if (indent > 10)
|
|
indent = 4;
|
|
}
|
|
else
|
|
indent = 4;
|
|
|
|
for (toplevel = 0; getlocation(toplevel, &loc); toplevel++)
|
|
if (loc.filesw) {
|
|
prevfilelevel = filelevel;
|
|
filelevel = toplevel;
|
|
}
|
|
toplevel--;
|
|
|
|
if (e->errtype == FILERR) {
|
|
toplevel--;
|
|
filelevel = prevfilelevel;
|
|
}
|
|
if (swenttr && filelevel > 0) {
|
|
int level = 0;
|
|
int middle = 0; /* in the middle of a line */
|
|
do {
|
|
(void)getlocation(level, &loc);
|
|
if (loc.filesw) {
|
|
if (middle) {
|
|
fputs(":\n", efp);
|
|
spaces(efp, indent);
|
|
}
|
|
else
|
|
middle = 1;
|
|
xfprintf(efp, getheader(HDRPFX));
|
|
xfprintf(efp, getheader(HDRLOC), ioflid(loc.fcb),
|
|
loc.ename, loc.rcnt, loc.ccnt);
|
|
}
|
|
else if (middle)
|
|
xfprintf(efp, getheader(HDRELOC),
|
|
loc.ename, loc.rcnt + 1, loc.ccnt);
|
|
}
|
|
while (++level != filelevel);
|
|
if (middle) {
|
|
fputs(":\n", efp);
|
|
spaces(efp, indent);
|
|
}
|
|
}
|
|
|
|
/* We use strings for the type and severity,
|
|
so that the format can use %.0s to ignore them. */
|
|
|
|
type[0] = messages[e->errnum].type;
|
|
type[1] = '\0';
|
|
severity[0] = messages[e->errnum].severity;
|
|
severity[1] = '\0';
|
|
|
|
countit = (severity[0] != 'I');
|
|
if (!countit)
|
|
hdrcode = HDRWARN;
|
|
else if (type[0] == 'R')
|
|
hdrcode = HDRSYS;
|
|
else if (type[0] == 'U')
|
|
hdrcode = HDRUNSUP;
|
|
else
|
|
hdrcode = HDRALL;
|
|
|
|
xfprintf(efp, getheader(hdrcode), type, severity, e->errnum);
|
|
|
|
if (filelevel >= 0) {
|
|
(void)getlocation(filelevel, &loc);
|
|
xfprintf(efp, getheader(HDRLOC),
|
|
ioflid(loc.fcb), loc.ename, loc.rcnt, loc.ccnt);
|
|
while (filelevel < toplevel) {
|
|
++filelevel;
|
|
if (swenttr) {
|
|
(void)getlocation(filelevel, &loc);
|
|
xfprintf(efp, getheader(HDRELOC),
|
|
loc.ename, loc.rcnt + 1, loc.ccnt);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* It is necessary to copy the result of getparm() because
|
|
the specification of catgets() says in can return a
|
|
pointer to a static buffer which may get overwritten
|
|
by the next call to catgets(). */
|
|
|
|
switch (e->errtype) {
|
|
case MDERR:
|
|
strncpy(parmbuf, getparm(e->errsp), PARMBUFSIZ*2 - 1);
|
|
xfprintf(efp, getheader(HDRMD), parmbuf,
|
|
(e->subdcl ? e->subdcl : (UNCH *)""), e->parmno);
|
|
break;
|
|
case MDERR2:
|
|
/* no subdcl parameter */
|
|
strncpy(parmbuf, getparm(e->errsp), PARMBUFSIZ*2 - 1);
|
|
xfprintf(efp, getheader(HDRMD2), parmbuf, e->parmno);
|
|
break;
|
|
case DOCERR:
|
|
case EXITERR:
|
|
if (toplevel < 0)
|
|
break;
|
|
strncpy(parmbuf, getparm(e->errsp), PARMBUFSIZ*2 - 1);
|
|
xfprintf(efp, getheader(HDRMODE), parmbuf);
|
|
switch (loc.curchar) {
|
|
case EOFCHAR:
|
|
xfprintf(efp, getheader(HDREOF));
|
|
break;
|
|
case RSCHAR:
|
|
xfprintf(efp, getheader(HDRRS));
|
|
break;
|
|
case RECHAR:
|
|
xfprintf(efp, getheader(HDRRE));
|
|
break;
|
|
case DELNONCH:
|
|
xfprintf(efp, getheader(HDRCTL), UNSHIFTNON(loc.nextchar));
|
|
break;
|
|
case EOS:
|
|
xfprintf(efp, getheader(HDREE));
|
|
break;
|
|
case EOBCHAR:
|
|
break;
|
|
default:
|
|
if (ISASCII(loc.curchar) && isprint(loc.curchar))
|
|
xfprintf(efp, getheader(HDRPRT), loc.curchar);
|
|
else
|
|
xfprintf(efp, getheader(HDRCTL), loc.curchar);
|
|
break;
|
|
}
|
|
break;
|
|
case FILERR:
|
|
if (getlocation(toplevel + 1, &loc))
|
|
xfprintf(efp, getheader(HDRFIL), ioflid(loc.fcb));
|
|
break;
|
|
}
|
|
fputs(":\n", efp);
|
|
|
|
if (e->errtype == FILERR && e->sverrno != 0) {
|
|
char *errstr = strerror(e->sverrno);
|
|
UNS len = strlen(errstr);
|
|
/* Strip a trailing newline if there is one. */
|
|
if (len > 0 && errstr[len - 1] == '\n')
|
|
len--;
|
|
spaces(efp, indent);
|
|
for (; len > 0; len--, errstr++)
|
|
putc(*errstr, efp);
|
|
fputs(":\n", efp);
|
|
}
|
|
|
|
spaces(efp, indent);
|
|
|
|
xfprintf(efp, gettext(e->errnum),
|
|
transparm((UNCH *)e->eparm[0], parmbuf1),
|
|
transparm((UNCH *)e->eparm[1], parmbuf2));
|
|
putc('\n', efp);
|
|
|
|
if (sweltr)
|
|
elttrace(efp, indent);
|
|
return countit;
|
|
}
|
|
|
|
/* Print an element trace. */
|
|
static VOID elttrace(efp, indent)
|
|
FILE *efp;
|
|
int indent;
|
|
{
|
|
int i = 1;
|
|
UNCH *gi;
|
|
|
|
gi = getgi(i);
|
|
if (!gi)
|
|
return;
|
|
spaces(efp, indent);
|
|
xfprintf(efp, getheader(HDRELT));
|
|
do {
|
|
fprintf(efp, " %s", gi);
|
|
gi = getgi(++i);
|
|
} while (gi);
|
|
putc('\n', efp);
|
|
}
|
|
|
|
static VOID spaces(efp, indent)
|
|
FILE *efp;
|
|
int indent;
|
|
{
|
|
while (--indent >= 0)
|
|
putc(' ', efp);
|
|
}
|
|
|
|
VOID msginit(swp)
|
|
struct switches *swp;
|
|
{
|
|
catd = swp->catd;
|
|
prog = swp->prog;
|
|
sweltr = swp->sweltr;
|
|
swenttr = swp->swenttr;
|
|
die = swp->die;
|
|
}
|
|
|
|
/* Return the error count. */
|
|
|
|
int msgcnterr()
|
|
{
|
|
return cnterr;
|
|
}
|
|
|
|
/* Transform a parameter into a form suitable for printing. */
|
|
|
|
static char *transparm(s, buf)
|
|
UNCH *s;
|
|
char *buf;
|
|
{
|
|
char *ptr;
|
|
int cnt;
|
|
|
|
if (!s)
|
|
return 0;
|
|
|
|
ptr = buf;
|
|
cnt = PARMBUFSIZ - 4; /* space for `...\0' */
|
|
|
|
while (*s) {
|
|
UNCH ch = *s++;
|
|
if (ch == DELNONCH) {
|
|
if (*s == '\0')
|
|
break;
|
|
ch = UNSHIFTNON(*s);
|
|
s++;
|
|
}
|
|
if (ch == DELCDATA || ch == DELSDATA)
|
|
;
|
|
else if (ch == '\\') {
|
|
if (cnt < 2)
|
|
break;
|
|
*ptr++ = '\\';
|
|
*ptr++ = '\\';
|
|
cnt -= 2;
|
|
}
|
|
else if (ISASCII(ch) && isprint(ch)) {
|
|
if (cnt < 1)
|
|
break;
|
|
*ptr++ = ch;
|
|
cnt--;
|
|
}
|
|
else {
|
|
if (cnt < 4)
|
|
break;
|
|
sprintf(ptr, "\\%03o", ch);
|
|
ptr += 4;
|
|
cnt -= 4;
|
|
}
|
|
}
|
|
if (!*s)
|
|
*ptr = '\0';
|
|
else
|
|
strcpy(ptr, "...");
|
|
return buf;
|
|
}
|
|
|
|
/* The message and set numbers in the catgets function must be > 0. */
|
|
|
|
static char *gettext(n)
|
|
int n;
|
|
{
|
|
assert(n > 0 && n < SIZEOF(messages));
|
|
assert(messages[n].text != 0);
|
|
return catgets(catd, TEXT_SET, n, messages[n].text);
|
|
}
|
|
|
|
static char *getheader(n)
|
|
int n;
|
|
{
|
|
assert(n >= 0 && n < SIZEOF(headers));
|
|
return catgets(catd, HEADER_SET, n + 1, headers[n]);
|
|
}
|
|
|
|
static char *getparm(n)
|
|
int n;
|
|
{
|
|
assert(n >= 0 && n < SIZEOF(parms));
|
|
return catgets(catd, PARM_SET, n + 1, parms[n]);
|
|
}
|
|
|
|
/*
|
|
Local Variables:
|
|
c-indent-level: 5
|
|
c-continued-statement-offset: 5
|
|
c-brace-offset: -5
|
|
c-argdecl-indent: 0
|
|
c-label-offset: -5
|
|
End:
|
|
*/
|