summaryrefslogtreecommitdiff
path: root/dviware/dvibook/libtex/error.c
blob: 7d745108b8d21315df9991886a8427ee46630445 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
/*
 * Copyright (c) 1987, 1989 University of Maryland
 * Department of Computer Science.  All rights reserved.
 * Permission to copy for any purpose is hereby granted
 * so long as this copyright notice remains intact.
 */

#ifndef lint
static char rcsid[] = "$Header: /usr/src/local/tex/local/mctex/lib/RCS/error.c,v 2.8 89/08/22 21:49:12 chris Exp $";
#endif

/*
 * Print an error message with an optional system error number, and
 * optionally quit.
 *
 * THIS CODE IS SYSTEM DEPENDENT UNLESS varargs WORKS WITH vprintf
 * OR _doprnt.  It should work properly under System V using vprintf.
 * (If you have vprintf, define HAVE_VPRINTF in ../h/types.h.)
 */

#include "types.h"		/* for HAVE_VPRINTF */
#include "error.h"
#include <stdio.h>
#include <varargs.h>

#if defined(lint) && !defined(LINT_ANYWAY)

/* ARGSUSED */
void SetErrorTrap(fn) void (*fn)(); {;}

/* VARARGS3 ARGSUSED */
void error(quit, e, fmt) int quit, e; char *fmt; {;}

/* VARARGS1 ARGSUSED */
void panic(fmt) char *fmt; { exit(1); /* NOTREACHED */ }

#else lint

extern char *ProgName;		/* program name from argv[0] */
extern int errno;		/* Unix system-call error */
extern char *sys_errlist[];	/* table of error number => string */
extern int sys_nerr;		/* size of table */

static FILE *trap_file;		/* error diversion file, if any */
static void (*trap_fn)();	/* trap function */
static char *trap_buf;		/* buffer for trapped error strings */
static int trap_size;		/* size of trap_buf */

extern char *malloc(), *realloc();

/*
 * Enable error trapping: register the function fn as the trapper.
 * If fn is NULL, stop trapping.
 */
void
SetErrorTrap(fn)
	void (*fn)();
{
	int tempfd;
	char fname[BUFSIZ];

	/* shut down any existing error trap */
	if (trap_file) {
		(void) fclose(trap_file);
		trap_file = NULL;
	}
	if ((trap_fn = fn) == NULL)
		return;
	/* begin trapping */
	if ((tempfd = MakeRWTempFile(fname)) < 0)
		error(1, -1, "cannot create temporary file %s", fname);
	if (trap_size == 0) {
		trap_buf = malloc((unsigned)(trap_size = 1000));
		if (trap_buf == 0)
			error(1, -1,
			    "cannot get space for error buffer");
	}
	if ((trap_file = fdopen(tempfd, "r+")) == NULL)
		error(1, -1, "cannot get stdio file for error trap");
}

/*
 * Read a trapped error into trap_buf.
 * Return a pointer to the (NUL-terminated) text.
 * If something goes wrong, return something else printable.
 */
static char *
readback()
{
	int nbytes = ftell(trap_file) + 1;

	if (nbytes > trap_size) {
		if (trap_buf == NULL)
			trap_buf = malloc((unsigned)nbytes);
		else
			trap_buf = realloc(trap_buf, (unsigned)nbytes);
		if (trap_buf == NULL) {
			trap_size = 0;
			return ("Ouch!  Lost error text: out of memory?");
		}
	}
	rewind(trap_file);	/* now can read */
	nbytes = fread(trap_buf, 1, nbytes, trap_file);
	if (nbytes < 0)
		return ("Ouch!  Trouble reading error text!");
	trap_buf[nbytes] = 0;
	return (trap_buf);
}

/*
 * Print an error message to the error output (either stderr, or
 * if trapping errors, to the error trap file).  We precede this
 * with the program's name and an optional string (a0), then use
 * the format and variable argument list, then append an optional
 * Unix error string.  Finally, if errors are being trapped, we
 * pass the error text and the quit flag to the trap function.
 *
 * In the interest of `look and feel', if errors are being trapped,
 * the program name is omitted.
 */
static void
verror(quit, a0, fmt, l, e)
	char *a0, *fmt;
	va_list l;
	int e;
{
	register FILE *fp = trap_file;

	/* print to the trap file, if any, else stderr */
	if ((fp = trap_file) != NULL)
		rewind(fp);		/* now can write */
	else {
		fp = stderr;
		(void) fflush(fp);
	}
	if (trap_file == NULL)
		(void) fprintf(fp, "%s: ", ProgName);
	if (a0)
		(void) fprintf(fp, "%s", a0);
#ifdef HAVE_VPRINTF
	(void) vfprintf(fp, fmt, l);
#else
	(void) _doprnt(fmt, l, fp);
#endif
	if (e) {
		if (e < sys_nerr)
			(void) fprintf(fp, ": %s", sys_errlist[e]);
		else
			(void) fprintf(fp, ": Unknown error code %d", e);
	}
	(void) putc('\n', fp);
	(void) fflush(fp);
	if (trap_file != NULL)
		(*trap_fn)(quit, readback());
	if (quit)
		exit(quit);
}

/*
 * Print an error message and optionally quit.
 */
void
error(va_alist)
	va_dcl
{
	va_list l;
	int quit, e;
	char *fmt;

	va_start(l);
	quit = va_arg(l, int);
	if ((e = va_arg(l, int)) < 0)
		e = errno;
	fmt = va_arg(l, char *);
	verror(quit, (char *)NULL, fmt, l, e);
	va_end(l);
}

/*
 * Panic (print to stderr and abort).
 */
void
panic(va_alist)
	va_dcl
{
	va_list l;
	char *fmt;

	SetErrorTrap((void (*)())NULL);	/* shut down any trap */
	va_start(l);
	fmt = va_arg(l, char *);
	verror(0, "panic: ", fmt, l, 0);
	va_end(l);
	abort();
}

#endif /* lint */