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