d7482997 |
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]; |
f4551933 |
18 | char c; |
db662ca1 |
19 | int i, j; |
d7482997 |
20 | char *sp, *sp2; |
9e0fd4a7 |
21 | wchar_t *wsp, *wsp2; |
22 | unsigned wc; |
f6220253 |
23 | filepos fpos, fpos2, *fposp; |
e10118c4 |
24 | int flags = 0; |
d7482997 |
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; |
675958c3 |
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; |
d7482997 |
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 *); |
7e976207 |
97 | sp = utoa_locale_dup(wsp); |
d7482997 |
98 | fpos = *va_arg(ap, filepos *); |
99 | sprintf(error, "command `%.200s' unrecognised at start of" |
100 | " paragraph", sp); |
101 | flags = FILEPOS; |
7e976207 |
102 | sfree(sp); |
d7482997 |
103 | break; |
104 | case err_badmidcmd: |
105 | wsp = va_arg(ap, wchar_t *); |
7e976207 |
106 | sp = utoa_locale_dup(wsp); |
d7482997 |
107 | fpos = *va_arg(ap, filepos *); |
108 | sprintf(error, "command `%.200s' unexpected in mid-paragraph", sp); |
109 | flags = FILEPOS; |
7e976207 |
110 | sfree(sp); |
d7482997 |
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; |
6ff15f2b |
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; |
d7482997 |
137 | case err_missingrbrace: |
138 | fpos = *va_arg(ap, filepos *); |
139 | sprintf(error, "unclosed braces at end of paragraph"); |
140 | flags = FILEPOS; |
141 | break; |
7136a6c7 |
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; |
d7482997 |
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; |
da090173 |
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; |
d7482997 |
171 | case err_nosuchkw: |
172 | fpos = *va_arg(ap, filepos *); |
173 | wsp = va_arg(ap, wchar_t *); |
7e976207 |
174 | sp = utoa_locale_dup(wsp); |
d7482997 |
175 | sprintf(error, "unable to resolve cross-reference to `%.200s'", sp); |
176 | flags = FILEPOS; |
7e976207 |
177 | sfree(sp); |
d7482997 |
178 | break; |
179 | case err_multiBR: |
180 | fpos = *va_arg(ap, filepos *); |
181 | wsp = va_arg(ap, wchar_t *); |
7e976207 |
182 | sp = utoa_locale_dup(wsp); |
d7482997 |
183 | sprintf(error, "multiple `\\BR' entries given for `%.200s'", sp); |
184 | flags = FILEPOS; |
7e976207 |
185 | sfree(sp); |
d7482997 |
186 | break; |
187 | case err_nosuchidxtag: |
7e976207 |
188 | fpos = *va_arg(ap, filepos *); |
d7482997 |
189 | wsp = va_arg(ap, wchar_t *); |
7e976207 |
190 | sp = utoa_locale_dup(wsp); |
d7482997 |
191 | sprintf(error, "`\\IM' on unknown index tag `%.200s'", sp); |
7e976207 |
192 | sfree(sp); |
193 | flags = FILEPOS; |
d7482997 |
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 *); |
7e976207 |
203 | sp = utoa_locale_dup(wsp); |
d7482997 |
204 | sprintf(error, "macro `%.200s' already defined", sp); |
205 | flags = FILEPOS; |
7e976207 |
206 | sfree(sp); |
d7482997 |
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 *); |
7e976207 |
225 | sp = utoa_locale_dup(wsp); |
d7482997 |
226 | sprintf(error, "paragraph keyword `%.200s' already defined at ", sp); |
227 | sprintf(error + strlen(error), "%s:%d", fpos2.filename, fpos2.line); |
228 | flags = FILEPOS; |
7e976207 |
229 | sfree(sp); |
d7482997 |
230 | break; |
7136a6c7 |
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; |
2614b01d |
236 | case err_sectmarkerinblock: |
7136a6c7 |
237 | fpos = *va_arg(ap, filepos *); |
2614b01d |
238 | sp = va_arg(ap, char *); |
239 | sprintf(error, "section headings are not supported within \\%.100s", |
240 | sp); |
7136a6c7 |
241 | flags = FILEPOS; |
d4c7e130 |
242 | break; |
12f0ee84 |
243 | case err_cfginsufarg: |
d4c7e130 |
244 | fpos = *va_arg(ap, filepos *); |
12f0ee84 |
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"); |
d4c7e130 |
249 | flags = FILEPOS; |
250 | break; |
f4551933 |
251 | case err_infonodechar: |
f6220253 |
252 | fposp = va_arg(ap, filepos *); |
f4551933 |
253 | c = (char)va_arg(ap, int); |
254 | sprintf(error, "info output format does not support '%c' in" |
255 | " node names; removing", c); |
f6220253 |
256 | if (fposp) { |
257 | flags = FILEPOS; |
258 | fpos = *fposp; |
259 | } |
f4551933 |
260 | break; |
db662ca1 |
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; |
27bdc5ab |
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; |
0960a3d8 |
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; |
c419cb97 |
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; |
ba0fe3ec |
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; |
c885c2ff |
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 *); |
f2ef00b5 |
337 | sprintf(error, "no metrics available for Type 1 font '%.200s'", sp); |
c885c2ff |
338 | flags = FILEPOS; |
339 | break; |
f2ef00b5 |
340 | case err_chmnames: |
341 | sprintf(error, "only one of html-mshtmlhelp-chm and " |
342 | "html-mshtmlhelp-hhp found"); |
343 | flags = PREFIX; |
344 | break; |
d41ae9ad |
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; |
e997256c |
378 | case err_sfntbadglyph: |
379 | fpos = *va_arg(ap, filepos *); |
9e0fd4a7 |
380 | wc = va_arg(ap, unsigned); |
e997256c |
381 | sprintf(error, |
382 | "warning: character U+%04X references an non-existent glyph", |
383 | wc); |
384 | flags = FILEPOS; |
385 | break; |
d7482997 |
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) { |
d26171a6 |
396 | fprintf(stderr, "%s:", fpos.filename ? fpos.filename : "<standard input>"); |
6a0b9d08 |
397 | if (fpos.line > 0) |
398 | fprintf(stderr, "%d:", fpos.line); |
d7482997 |
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 | } |