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; |
da090173 |
21 | wchar_t *wsp, *wsp2; |
f6220253 |
22 | filepos fpos, fpos2, *fposp; |
d7482997 |
23 | int flags; |
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; |
d7482997 |
318 | case err_whatever: |
319 | sp = va_arg(ap, char *); |
320 | vsprintf(error, sp, ap); |
321 | flags = PREFIX; |
322 | break; |
323 | } |
324 | |
325 | if (flags & PREFIX) |
326 | fputs("halibut: ", stderr); |
327 | if (flags & FILEPOS) { |
6a0b9d08 |
328 | fprintf(stderr, "%s:", fpos.filename); |
329 | if (fpos.line > 0) |
330 | fprintf(stderr, "%d:", fpos.line); |
d7482997 |
331 | if (fpos.col > 0) |
332 | fprintf(stderr, "%d:", fpos.col); |
333 | fputc(' ', stderr); |
334 | } |
335 | fputs(error, stderr); |
336 | fputc('\n', stderr); |
337 | } |
338 | |
339 | void fatal(int code, ...) { |
340 | va_list ap; |
341 | va_start(ap, code); |
342 | do_error(code, ap); |
343 | va_end(ap); |
344 | exit(EXIT_FAILURE); |
345 | } |
346 | |
347 | void error(int code, ...) { |
348 | va_list ap; |
349 | va_start(ap, code); |
350 | do_error(code, ap); |
351 | va_end(ap); |
352 | } |