Ability to specify multiple arguments to \cfg{html-template-fragment};
[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 filepos fpos, fpos2;
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;
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;
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 *);
96 sp = utoa_locale_dup(wsp);
97 fpos = *va_arg(ap, filepos *);
98 sprintf(error, "command `%.200s' unrecognised at start of"
99 " paragraph", sp);
100 flags = FILEPOS;
101 sfree(sp);
102 break;
103 case err_badmidcmd:
104 wsp = va_arg(ap, wchar_t *);
105 sp = utoa_locale_dup(wsp);
106 fpos = *va_arg(ap, filepos *);
107 sprintf(error, "command `%.200s' unexpected in mid-paragraph", sp);
108 flags = FILEPOS;
109 sfree(sp);
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;
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;
136 case err_missingrbrace:
137 fpos = *va_arg(ap, filepos *);
138 sprintf(error, "unclosed braces at end of paragraph");
139 flags = FILEPOS;
140 break;
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;
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;
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;
170 case err_nosuchkw:
171 fpos = *va_arg(ap, filepos *);
172 wsp = va_arg(ap, wchar_t *);
173 sp = utoa_locale_dup(wsp);
174 sprintf(error, "unable to resolve cross-reference to `%.200s'", sp);
175 flags = FILEPOS;
176 sfree(sp);
177 break;
178 case err_multiBR:
179 fpos = *va_arg(ap, filepos *);
180 wsp = va_arg(ap, wchar_t *);
181 sp = utoa_locale_dup(wsp);
182 sprintf(error, "multiple `\\BR' entries given for `%.200s'", sp);
183 flags = FILEPOS;
184 sfree(sp);
185 break;
186 case err_nosuchidxtag:
187 fpos = *va_arg(ap, filepos *);
188 wsp = va_arg(ap, wchar_t *);
189 sp = utoa_locale_dup(wsp);
190 sprintf(error, "`\\IM' on unknown index tag `%.200s'", sp);
191 sfree(sp);
192 flags = FILEPOS;
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 *);
202 sp = utoa_locale_dup(wsp);
203 sprintf(error, "macro `%.200s' already defined", sp);
204 flags = FILEPOS;
205 sfree(sp);
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 *);
224 sp = utoa_locale_dup(wsp);
225 sprintf(error, "paragraph keyword `%.200s' already defined at ", sp);
226 sprintf(error + strlen(error), "%s:%d", fpos2.filename, fpos2.line);
227 flags = FILEPOS;
228 sfree(sp);
229 break;
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;
235 case err_sectmarkerinblock:
236 fpos = *va_arg(ap, filepos *);
237 sp = va_arg(ap, char *);
238 sprintf(error, "section headings are not supported within \\%.100s",
239 sp);
240 flags = FILEPOS;
241 break;
242 case err_cfginsufarg:
243 fpos = *va_arg(ap, filepos *);
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");
248 flags = FILEPOS;
249 break;
250 case err_infonodechar:
251 fpos = *va_arg(ap, filepos *);
252 c = (char)va_arg(ap, int);
253 sprintf(error, "info output format does not support '%c' in"
254 " node names; removing", c);
255 flags = FILEPOS;
256 break;
257 case err_text_codeline:
258 fpos = *va_arg(ap, filepos *);
259 i = va_arg(ap, int);
260 j = va_arg(ap, int);
261 sprintf(error, "warning: code paragraph line is %d chars wide, wider"
262 " than body width %d", i, j);
263 flags = FILEPOS;
264 break;
265 case err_htmlver:
266 fpos = *va_arg(ap, filepos *);
267 wsp = va_arg(ap, wchar_t *);
268 sp = utoa_locale_dup(wsp);
269 sprintf(error, "unrecognised HTML version keyword `%.200s'", sp);
270 sfree(sp);
271 flags = FILEPOS;
272 break;
273 case err_charset:
274 fpos = *va_arg(ap, filepos *);
275 wsp = va_arg(ap, wchar_t *);
276 sp = utoa_locale_dup(wsp);
277 sprintf(error, "character set `%.200s' not recognised", sp);
278 flags = FILEPOS;
279 sfree(sp);
280 break;
281 case err_whatever:
282 sp = va_arg(ap, char *);
283 vsprintf(error, sp, ap);
284 flags = PREFIX;
285 break;
286 }
287
288 if (flags & PREFIX)
289 fputs("halibut: ", stderr);
290 if (flags & FILEPOS) {
291 fprintf(stderr, "%s:", fpos.filename);
292 if (fpos.line > 0)
293 fprintf(stderr, "%d:", fpos.line);
294 if (fpos.col > 0)
295 fprintf(stderr, "%d:", fpos.col);
296 fputc(' ', stderr);
297 }
298 fputs(error, stderr);
299 fputc('\n', stderr);
300 }
301
302 void fatal(int code, ...) {
303 va_list ap;
304 va_start(ap, code);
305 do_error(code, ap);
306 va_end(ap);
307 exit(EXIT_FAILURE);
308 }
309
310 void error(int code, ...) {
311 va_list ap;
312 va_start(ap, code);
313 do_error(code, ap);
314 va_end(ap);
315 }