summaryrefslogtreecommitdiff
path: root/Build/source/texk/seetexk/error.c
blob: 330eb65a3282ce8bcc021ab84c1c9626bfcfa993 (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
/*
 * 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.
 */

/*
 * Print an error message with an optional system error number, and
 * optionally quit.
 *
 */
#include <stdio.h>

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include "types.h"		/* for HAVE_VPRINTF */
#include "error.h"
#include "tempfile.h"

extern char *ProgName;		/* program name from argv[0] */

#include <errno.h>
#ifndef errno
extern int errno;
#endif

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

#ifndef KPATHSEA
extern char *malloc(), *realloc();
#endif

#if !defined (HAVE_STRERROR) && !defined (strerror)
static char *
strerror (int errnum)
{
  extern char *sys_errlist[];
  extern int sys_nerr;
 
  return 0 < errnum && errnum <= sys_nerr
         ? sys_errlist[errnum] : "Unknown system error";
}
#endif /* not HAVE_STRERROR && not strerror */

/*
 * Read a trapped error into trap_buf.
 * Return a pointer to the (NUL-terminated) text.
 * If something goes wrong, return something else printable.
 */
static const char *
readback(void)
{
	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(int quit, const char *a0, const char *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);
	(void) vfprintf(fp, fmt, l);
	if (e)
		(void) fprintf(fp, ": %s", strerror(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(int quit, int e, const char *fmt, ...)
{
	va_list l;
	va_start(l, fmt);
	if (e < 0)
		e = errno;
	verror(quit, NULL, fmt, l, e);
	va_end(l);
}
/*
 * Panic (print to stderr and abort).
 */
void
panic(const char *fmt, ...)
{
	va_list l;
	va_start(l, fmt);
	verror(0, "panic: ", fmt, l, 0);
	va_end(l);
	abort();
}

/*
 * Enable error trapping: register the function fn as the trapper.
 * If fn is NULL, stop trapping.
 */
void
SetErrorTrap(void (*fn)(int, const char *))
{
	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");
}