Bug in utoi(), which made it ignore a leading minus sign when
[sgt/halibut] / error.c
1 /*
2 * error.c: Halibut error handling
3 */
4
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <stdarg.h>
8 #include "halibut.h"
9
10 /*
11 * Error flags
12 */
13 #define PREFIX 0x0001 /* give `halibut:' prefix */
14 #define FILEPOS 0x0002 /* give file position prefix */
15
16 static void do_error(int code, va_list ap) {
17 char error[1024];
18 char c;
19 int i, j;
20 char *sp, *sp2;
21 wchar_t *wsp, *wsp2;
22 unsigned wc;
23 filepos fpos, fpos2, *fposp;
24 int flags = 0;
25
26 switch(code) {
27 case err_nomemory: /* no arguments */
28 sprintf(error, "out of memory");
29 flags = PREFIX;
30 break;
31 case err_optnoarg:
32 sp = va_arg(ap, char *);
33 sprintf(error, "option `-%.200s' requires an argument", sp);
34 flags = PREFIX;
35 break;
36 case err_nosuchopt:
37 sp = va_arg(ap, char *);
38 sprintf(error, "unrecognised option `-%.200s'", sp);
39 flags = PREFIX;
40 break;
41 case err_cmdcharset:
42 sp = va_arg(ap, char *);
43 sprintf(error, "character set `%.200s' not recognised", sp);
44 flags = PREFIX;
45 break;
46 case err_futileopt:
47 sp = va_arg(ap, char *);
48 sp2 = va_arg(ap, char *);
49 sprintf(error, "warning: option `-%s' has no effect%s", sp, sp2);
50 flags = PREFIX;
51 break;
52 case err_noinput: /* no arguments */
53 sprintf(error, "no input files");
54 flags = PREFIX;
55 break;
56 case err_cantopen:
57 sp = va_arg(ap, char *);
58 sprintf(error, "unable to open input file `%.200s'", sp);
59 flags = PREFIX;
60 break;
61 case err_nodata: /* no arguments */
62 sprintf(error, "no data in input files");
63 flags = PREFIX;
64 break;
65 case err_brokencodepara:
66 fpos = *va_arg(ap, filepos *);
67 sprintf(error, "every line of a code paragraph should begin `\\c'");
68 flags = FILEPOS;
69 break;
70 case err_kwunclosed:
71 fpos = *va_arg(ap, filepos *);
72 sprintf(error, "expected `}' after paragraph keyword");
73 flags = FILEPOS;
74 break;
75 case err_kwexpected:
76 fpos = *va_arg(ap, filepos *);
77 sprintf(error, "expected a paragraph keyword");
78 flags = FILEPOS;
79 break;
80 case err_kwillegal:
81 fpos = *va_arg(ap, filepos *);
82 sprintf(error, "expected no paragraph keyword");
83 flags = FILEPOS;
84 break;
85 case err_kwtoomany:
86 fpos = *va_arg(ap, filepos *);
87 sprintf(error, "expected only one paragraph keyword");
88 flags = FILEPOS;
89 break;
90 case err_bodyillegal:
91 fpos = *va_arg(ap, filepos *);
92 sprintf(error, "expected no text after paragraph keyword");
93 flags = FILEPOS;
94 break;
95 case err_badparatype:
96 wsp = va_arg(ap, wchar_t *);
97 sp = utoa_locale_dup(wsp);
98 fpos = *va_arg(ap, filepos *);
99 sprintf(error, "command `%.200s' unrecognised at start of"
100 " paragraph", sp);
101 flags = FILEPOS;
102 sfree(sp);
103 break;
104 case err_badmidcmd:
105 wsp = va_arg(ap, wchar_t *);
106 sp = utoa_locale_dup(wsp);
107 fpos = *va_arg(ap, filepos *);
108 sprintf(error, "command `%.200s' unexpected in mid-paragraph", sp);
109 flags = FILEPOS;
110 sfree(sp);
111 break;
112 case err_unexbrace:
113 fpos = *va_arg(ap, filepos *);
114 sprintf(error, "brace character unexpected in mid-paragraph");
115 flags = FILEPOS;
116 break;
117 case err_explbr:
118 fpos = *va_arg(ap, filepos *);
119 sprintf(error, "expected `{' after command");
120 flags = FILEPOS;
121 break;
122 case err_commenteof:
123 fpos = *va_arg(ap, filepos *);
124 sprintf(error, "end of file unexpected inside `\\#{...}' comment");
125 flags = FILEPOS;
126 break;
127 case err_kwexprbr:
128 fpos = *va_arg(ap, filepos *);
129 sprintf(error, "expected `}' after cross-reference");
130 flags = FILEPOS;
131 break;
132 case err_codequote:
133 fpos = *va_arg(ap, filepos *);
134 sprintf(error, "unable to nest \\q{...} within \\c{...} or \\cw{...}");
135 flags = FILEPOS;
136 break;
137 case err_missingrbrace:
138 fpos = *va_arg(ap, filepos *);
139 sprintf(error, "unclosed braces at end of paragraph");
140 flags = FILEPOS;
141 break;
142 case err_missingrbrace2:
143 fpos = *va_arg(ap, filepos *);
144 sprintf(error, "unclosed braces at end of input file");
145 flags = FILEPOS;
146 break;
147 case err_nestedstyles:
148 fpos = *va_arg(ap, filepos *);
149 sprintf(error, "unable to nest text styles");
150 flags = FILEPOS;
151 break;
152 case err_nestedindex:
153 fpos = *va_arg(ap, filepos *);
154 sprintf(error, "unable to nest index markings");
155 flags = FILEPOS;
156 break;
157 case err_indexcase:
158 fpos = *va_arg(ap, filepos *);
159 wsp = va_arg(ap, wchar_t *);
160 sp = utoa_locale_dup(wsp);
161 fpos2 = *va_arg(ap, filepos *);
162 wsp2 = va_arg(ap, wchar_t *);
163 sp2 = utoa_locale_dup(wsp2);
164 sprintf(error, "warning: index tag `%.200s' used with ", sp);
165 sprintf(error + strlen(error), "different case (`%.200s') at %s:%d",
166 sp2, fpos2.filename, fpos2.line);
167 flags = FILEPOS;
168 sfree(sp);
169 sfree(sp2);
170 break;
171 case err_nosuchkw:
172 fpos = *va_arg(ap, filepos *);
173 wsp = va_arg(ap, wchar_t *);
174 sp = utoa_locale_dup(wsp);
175 sprintf(error, "unable to resolve cross-reference to `%.200s'", sp);
176 flags = FILEPOS;
177 sfree(sp);
178 break;
179 case err_multiBR:
180 fpos = *va_arg(ap, filepos *);
181 wsp = va_arg(ap, wchar_t *);
182 sp = utoa_locale_dup(wsp);
183 sprintf(error, "multiple `\\BR' entries given for `%.200s'", sp);
184 flags = FILEPOS;
185 sfree(sp);
186 break;
187 case err_nosuchidxtag:
188 fpos = *va_arg(ap, filepos *);
189 wsp = va_arg(ap, wchar_t *);
190 sp = utoa_locale_dup(wsp);
191 sprintf(error, "`\\IM' on unknown index tag `%.200s'", sp);
192 sfree(sp);
193 flags = FILEPOS;
194 break;
195 case err_cantopenw:
196 sp = va_arg(ap, char *);
197 sprintf(error, "unable to open output file `%.200s'", sp);
198 flags = PREFIX;
199 break;
200 case err_macroexists:
201 fpos = *va_arg(ap, filepos *);
202 wsp = va_arg(ap, wchar_t *);
203 sp = utoa_locale_dup(wsp);
204 sprintf(error, "macro `%.200s' already defined", sp);
205 flags = FILEPOS;
206 sfree(sp);
207 break;
208 case err_sectjump:
209 fpos = *va_arg(ap, filepos *);
210 sprintf(error, "expected higher heading levels before this one");
211 flags = FILEPOS;
212 break;
213 case err_winhelp_ctxclash:
214 fpos = *va_arg(ap, filepos *);
215 sp = va_arg(ap, char *);
216 sp2 = va_arg(ap, char *);
217 sprintf(error, "Windows Help context id `%.200s' clashes with "
218 "previously defined `%.200s'", sp, sp2);
219 flags = FILEPOS;
220 break;
221 case err_multikw:
222 fpos = *va_arg(ap, filepos *);
223 fpos2 = *va_arg(ap, filepos *);
224 wsp = va_arg(ap, wchar_t *);
225 sp = utoa_locale_dup(wsp);
226 sprintf(error, "paragraph keyword `%.200s' already defined at ", sp);
227 sprintf(error + strlen(error), "%s:%d", fpos2.filename, fpos2.line);
228 flags = FILEPOS;
229 sfree(sp);
230 break;
231 case err_misplacedlcont:
232 fpos = *va_arg(ap, filepos *);
233 sprintf(error, "\\lcont is only expected after a list item");
234 flags = FILEPOS;
235 break;
236 case err_sectmarkerinblock:
237 fpos = *va_arg(ap, filepos *);
238 sp = va_arg(ap, char *);
239 sprintf(error, "section headings are not supported within \\%.100s",
240 sp);
241 flags = FILEPOS;
242 break;
243 case err_cfginsufarg:
244 fpos = *va_arg(ap, filepos *);
245 sp = va_arg(ap, char *);
246 i = va_arg(ap, int);
247 sprintf(error, "\\cfg{%s} expects at least %d parameter%s", sp,
248 i, (i==1)?"":"s");
249 flags = FILEPOS;
250 break;
251 case err_infonodechar:
252 fposp = va_arg(ap, filepos *);
253 c = (char)va_arg(ap, int);
254 sprintf(error, "info output format does not support '%c' in"
255 " node names; removing", c);
256 if (fposp) {
257 flags = FILEPOS;
258 fpos = *fposp;
259 }
260 break;
261 case err_text_codeline:
262 fpos = *va_arg(ap, filepos *);
263 i = va_arg(ap, int);
264 j = va_arg(ap, int);
265 sprintf(error, "warning: code paragraph line is %d chars wide, wider"
266 " than body width %d", i, j);
267 flags = FILEPOS;
268 break;
269 case err_htmlver:
270 fpos = *va_arg(ap, filepos *);
271 wsp = va_arg(ap, wchar_t *);
272 sp = utoa_locale_dup(wsp);
273 sprintf(error, "unrecognised HTML version keyword `%.200s'", sp);
274 sfree(sp);
275 flags = FILEPOS;
276 break;
277 case err_charset:
278 fpos = *va_arg(ap, filepos *);
279 wsp = va_arg(ap, wchar_t *);
280 sp = utoa_locale_dup(wsp);
281 sprintf(error, "character set `%.200s' not recognised", sp);
282 flags = FILEPOS;
283 sfree(sp);
284 break;
285 case err_nofont:
286 fpos = *va_arg(ap, filepos *);
287 wsp = va_arg(ap, wchar_t *);
288 sp = utoa_locale_dup(wsp);
289 sprintf(error, "font `%.200s' not recognised", sp);
290 flags = FILEPOS;
291 sfree(sp);
292 break;
293 case err_afmeof:
294 fpos = *va_arg(ap, filepos *);
295 sprintf(error, "AFM file ended unexpectedly");
296 flags = FILEPOS;
297 break;
298 case err_afmkey:
299 fpos = *va_arg(ap, filepos *);
300 sp = va_arg(ap, char *);
301 sprintf(error, "required AFM key '%.200s' missing", sp);
302 flags = FILEPOS;
303 break;
304 case err_afmvers:
305 fpos = *va_arg(ap, filepos *);
306 sprintf(error, "unsupported AFM version");
307 flags = FILEPOS;
308 break;
309 case err_afmval:
310 fpos = *va_arg(ap, filepos *);
311 sp = va_arg(ap, char *);
312 i = va_arg(ap, int);
313 if (i == 1)
314 sprintf(error, "AFM key '%.200s' requires a value", sp);
315 else
316 sprintf(error, "AFM key '%.200s' requires %d values", sp, i);
317 flags = FILEPOS;
318 break;
319 case err_pfeof:
320 fpos = *va_arg(ap, filepos *);
321 sprintf(error, "Type 1 font file ended unexpectedly");
322 flags = FILEPOS;
323 break;
324 case err_pfhead:
325 fpos = *va_arg(ap, filepos *);
326 sprintf(error, "Type 1 font file header line invalid");
327 flags = FILEPOS;
328 break;
329 case err_pfbad:
330 fpos = *va_arg(ap, filepos *);
331 sprintf(error, "Type 1 font file invalid");
332 flags = FILEPOS;
333 break;
334 case err_pfnoafm:
335 fpos = *va_arg(ap, filepos *);
336 sp = va_arg(ap, char *);
337 sprintf(error, "no metrics available for Type 1 font '%.200s'", sp);
338 flags = FILEPOS;
339 break;
340 case err_chmnames:
341 sprintf(error, "only one of html-mshtmlhelp-chm and "
342 "html-mshtmlhelp-hhp found");
343 flags = PREFIX;
344 break;
345 case err_sfntnotable:
346 fpos = *va_arg(ap, filepos *);
347 sp = va_arg(ap, char *);
348 sprintf(error, "font has no '%.4s' table", sp);
349 flags = FILEPOS;
350 break;
351 case err_sfntnopsname:
352 fpos = *va_arg(ap, filepos *);
353 sprintf(error, "font has no PostScript name");
354 flags = FILEPOS;
355 break;
356 case err_sfntbadtable:
357 fpos = *va_arg(ap, filepos *);
358 sp = va_arg(ap, char *);
359 sprintf(error, "font has an invalid '%.4s' table", sp);
360 flags = FILEPOS;
361 break;
362 case err_sfntnounicmap:
363 fpos = *va_arg(ap, filepos *);
364 sprintf(error, "font has no UCS-2 character map");
365 flags = FILEPOS;
366 break;
367 case err_sfnttablevers:
368 fpos = *va_arg(ap, filepos *);
369 sp = va_arg(ap, char *);
370 sprintf(error, "font has an unsupported '%.4s' table version", sp);
371 flags = FILEPOS;
372 break;
373 case err_sfntbadhdr:
374 fpos = *va_arg(ap, filepos *);
375 sprintf(error, "font has an invalid header");
376 flags = FILEPOS;
377 break;
378 case err_sfntbadglyph:
379 fpos = *va_arg(ap, filepos *);
380 wc = va_arg(ap, unsigned);
381 sprintf(error,
382 "warning: character U+%04X references an non-existent glyph",
383 wc);
384 flags = FILEPOS;
385 break;
386 case err_whatever:
387 sp = va_arg(ap, char *);
388 vsprintf(error, sp, ap);
389 flags = PREFIX;
390 break;
391 }
392
393 if (flags & PREFIX)
394 fputs("halibut: ", stderr);
395 if (flags & FILEPOS) {
396 fprintf(stderr, "%s:", fpos.filename ? fpos.filename : "<standard input>");
397 if (fpos.line > 0)
398 fprintf(stderr, "%d:", fpos.line);
399 if (fpos.col > 0)
400 fprintf(stderr, "%d:", fpos.col);
401 fputc(' ', stderr);
402 }
403 fputs(error, stderr);
404 fputc('\n', stderr);
405 }
406
407 void fatal(int code, ...) {
408 va_list ap;
409 va_start(ap, code);
410 do_error(code, ap);
411 va_end(ap);
412 exit(EXIT_FAILURE);
413 }
414
415 void error(int code, ...) {
416 va_list ap;
417 va_start(ap, code);
418 do_error(code, ap);
419 va_end(ap);
420 }