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; |
d7482997 |
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_noinput: /* no arguments */ |
41 | sprintf(error, "no input files"); |
42 | flags = PREFIX; |
43 | break; |
44 | case err_cantopen: |
45 | sp = va_arg(ap, char *); |
46 | sprintf(error, "unable to open input file `%.200s'", sp); |
47 | flags = PREFIX; |
48 | break; |
49 | case err_nodata: /* no arguments */ |
50 | sprintf(error, "no data in input files"); |
51 | flags = PREFIX; |
52 | break; |
53 | case err_brokencodepara: |
54 | fpos = *va_arg(ap, filepos *); |
55 | sprintf(error, "every line of a code paragraph should begin `\\c'"); |
56 | flags = FILEPOS; |
57 | break; |
58 | case err_kwunclosed: |
59 | fpos = *va_arg(ap, filepos *); |
60 | sprintf(error, "expected `}' after paragraph keyword"); |
61 | flags = FILEPOS; |
62 | break; |
63 | case err_kwexpected: |
64 | fpos = *va_arg(ap, filepos *); |
65 | sprintf(error, "expected a paragraph keyword"); |
66 | flags = FILEPOS; |
67 | break; |
68 | case err_kwillegal: |
69 | fpos = *va_arg(ap, filepos *); |
70 | sprintf(error, "expected no paragraph keyword"); |
71 | flags = FILEPOS; |
72 | break; |
73 | case err_kwtoomany: |
74 | fpos = *va_arg(ap, filepos *); |
75 | sprintf(error, "expected only one paragraph keyword"); |
76 | flags = FILEPOS; |
77 | break; |
78 | case err_bodyillegal: |
79 | fpos = *va_arg(ap, filepos *); |
80 | sprintf(error, "expected no text after paragraph keyword"); |
81 | flags = FILEPOS; |
82 | break; |
83 | case err_badparatype: |
84 | wsp = va_arg(ap, wchar_t *); |
7e976207 |
85 | sp = utoa_locale_dup(wsp); |
d7482997 |
86 | fpos = *va_arg(ap, filepos *); |
87 | sprintf(error, "command `%.200s' unrecognised at start of" |
88 | " paragraph", sp); |
89 | flags = FILEPOS; |
7e976207 |
90 | sfree(sp); |
d7482997 |
91 | break; |
92 | case err_badmidcmd: |
93 | wsp = va_arg(ap, wchar_t *); |
7e976207 |
94 | sp = utoa_locale_dup(wsp); |
d7482997 |
95 | fpos = *va_arg(ap, filepos *); |
96 | sprintf(error, "command `%.200s' unexpected in mid-paragraph", sp); |
97 | flags = FILEPOS; |
7e976207 |
98 | sfree(sp); |
d7482997 |
99 | break; |
100 | case err_unexbrace: |
101 | fpos = *va_arg(ap, filepos *); |
102 | sprintf(error, "brace character unexpected in mid-paragraph"); |
103 | flags = FILEPOS; |
104 | break; |
105 | case err_explbr: |
106 | fpos = *va_arg(ap, filepos *); |
107 | sprintf(error, "expected `{' after command"); |
108 | flags = FILEPOS; |
109 | break; |
110 | case err_commenteof: |
111 | fpos = *va_arg(ap, filepos *); |
112 | sprintf(error, "end of file unexpected inside `\\#{...}' comment"); |
113 | flags = FILEPOS; |
114 | break; |
115 | case err_kwexprbr: |
116 | fpos = *va_arg(ap, filepos *); |
117 | sprintf(error, "expected `}' after cross-reference"); |
118 | flags = FILEPOS; |
119 | break; |
6ff15f2b |
120 | case err_codequote: |
121 | fpos = *va_arg(ap, filepos *); |
122 | sprintf(error, "unable to nest \\q{...} within \\c{...} or \\cw{...}"); |
123 | flags = FILEPOS; |
124 | break; |
d7482997 |
125 | case err_missingrbrace: |
126 | fpos = *va_arg(ap, filepos *); |
127 | sprintf(error, "unclosed braces at end of paragraph"); |
128 | flags = FILEPOS; |
129 | break; |
7136a6c7 |
130 | case err_missingrbrace2: |
131 | fpos = *va_arg(ap, filepos *); |
132 | sprintf(error, "unclosed braces at end of input file"); |
133 | flags = FILEPOS; |
134 | break; |
d7482997 |
135 | case err_nestedstyles: |
136 | fpos = *va_arg(ap, filepos *); |
137 | sprintf(error, "unable to nest text styles"); |
138 | flags = FILEPOS; |
139 | break; |
140 | case err_nestedindex: |
141 | fpos = *va_arg(ap, filepos *); |
142 | sprintf(error, "unable to nest index markings"); |
143 | flags = FILEPOS; |
144 | break; |
da090173 |
145 | case err_indexcase: |
146 | fpos = *va_arg(ap, filepos *); |
147 | wsp = va_arg(ap, wchar_t *); |
148 | sp = utoa_locale_dup(wsp); |
149 | fpos2 = *va_arg(ap, filepos *); |
150 | wsp2 = va_arg(ap, wchar_t *); |
151 | sp2 = utoa_locale_dup(wsp2); |
152 | sprintf(error, "warning: index tag `%.200s' used with ", sp); |
153 | sprintf(error + strlen(error), "different case (`%.200s') at %s:%d", |
154 | sp2, fpos2.filename, fpos2.line); |
155 | flags = FILEPOS; |
156 | sfree(sp); |
157 | sfree(sp2); |
158 | break; |
d7482997 |
159 | case err_nosuchkw: |
160 | fpos = *va_arg(ap, filepos *); |
161 | wsp = va_arg(ap, wchar_t *); |
7e976207 |
162 | sp = utoa_locale_dup(wsp); |
d7482997 |
163 | sprintf(error, "unable to resolve cross-reference to `%.200s'", sp); |
164 | flags = FILEPOS; |
7e976207 |
165 | sfree(sp); |
d7482997 |
166 | break; |
167 | case err_multiBR: |
168 | fpos = *va_arg(ap, filepos *); |
169 | wsp = va_arg(ap, wchar_t *); |
7e976207 |
170 | sp = utoa_locale_dup(wsp); |
d7482997 |
171 | sprintf(error, "multiple `\\BR' entries given for `%.200s'", sp); |
172 | flags = FILEPOS; |
7e976207 |
173 | sfree(sp); |
d7482997 |
174 | break; |
175 | case err_nosuchidxtag: |
7e976207 |
176 | fpos = *va_arg(ap, filepos *); |
d7482997 |
177 | wsp = va_arg(ap, wchar_t *); |
7e976207 |
178 | sp = utoa_locale_dup(wsp); |
d7482997 |
179 | sprintf(error, "`\\IM' on unknown index tag `%.200s'", sp); |
7e976207 |
180 | sfree(sp); |
181 | flags = FILEPOS; |
d7482997 |
182 | break; |
183 | case err_cantopenw: |
184 | sp = va_arg(ap, char *); |
185 | sprintf(error, "unable to open output file `%.200s'", sp); |
186 | flags = PREFIX; |
187 | break; |
188 | case err_macroexists: |
189 | fpos = *va_arg(ap, filepos *); |
190 | wsp = va_arg(ap, wchar_t *); |
7e976207 |
191 | sp = utoa_locale_dup(wsp); |
d7482997 |
192 | sprintf(error, "macro `%.200s' already defined", sp); |
193 | flags = FILEPOS; |
7e976207 |
194 | sfree(sp); |
d7482997 |
195 | break; |
196 | case err_sectjump: |
197 | fpos = *va_arg(ap, filepos *); |
198 | sprintf(error, "expected higher heading levels before this one"); |
199 | flags = FILEPOS; |
200 | break; |
201 | case err_winhelp_ctxclash: |
202 | fpos = *va_arg(ap, filepos *); |
203 | sp = va_arg(ap, char *); |
204 | sp2 = va_arg(ap, char *); |
205 | sprintf(error, "Windows Help context id `%.200s' clashes with " |
206 | "previously defined `%.200s'", sp, sp2); |
207 | flags = FILEPOS; |
208 | break; |
209 | case err_multikw: |
210 | fpos = *va_arg(ap, filepos *); |
211 | fpos2 = *va_arg(ap, filepos *); |
212 | wsp = va_arg(ap, wchar_t *); |
7e976207 |
213 | sp = utoa_locale_dup(wsp); |
d7482997 |
214 | sprintf(error, "paragraph keyword `%.200s' already defined at ", sp); |
215 | sprintf(error + strlen(error), "%s:%d", fpos2.filename, fpos2.line); |
216 | flags = FILEPOS; |
7e976207 |
217 | sfree(sp); |
d7482997 |
218 | break; |
7136a6c7 |
219 | case err_misplacedlcont: |
220 | fpos = *va_arg(ap, filepos *); |
221 | sprintf(error, "\\lcont is only expected after a list item"); |
222 | flags = FILEPOS; |
223 | break; |
2614b01d |
224 | case err_sectmarkerinblock: |
7136a6c7 |
225 | fpos = *va_arg(ap, filepos *); |
2614b01d |
226 | sp = va_arg(ap, char *); |
227 | sprintf(error, "section headings are not supported within \\%.100s", |
228 | sp); |
7136a6c7 |
229 | flags = FILEPOS; |
d4c7e130 |
230 | break; |
231 | case err_infodirentry: |
232 | fpos = *va_arg(ap, filepos *); |
233 | sprintf(error, "\\cfg{info-dir-entry} expects at least three" |
234 | " parameters"); |
235 | flags = FILEPOS; |
236 | break; |
f4551933 |
237 | case err_infonodechar: |
238 | fpos = *va_arg(ap, filepos *); |
239 | c = (char)va_arg(ap, int); |
240 | sprintf(error, "info output format does not support '%c' in" |
241 | " node names; removing", c); |
242 | flags = FILEPOS; |
243 | break; |
db662ca1 |
244 | case err_text_codeline: |
245 | fpos = *va_arg(ap, filepos *); |
246 | i = va_arg(ap, int); |
247 | j = va_arg(ap, int); |
248 | sprintf(error, "warning: code paragraph line is %d chars wide, wider" |
249 | " than body width %d", i, j); |
250 | flags = FILEPOS; |
251 | break; |
d7482997 |
252 | case err_whatever: |
253 | sp = va_arg(ap, char *); |
254 | vsprintf(error, sp, ap); |
255 | flags = PREFIX; |
256 | break; |
257 | } |
258 | |
259 | if (flags & PREFIX) |
260 | fputs("halibut: ", stderr); |
261 | if (flags & FILEPOS) { |
6a0b9d08 |
262 | fprintf(stderr, "%s:", fpos.filename); |
263 | if (fpos.line > 0) |
264 | fprintf(stderr, "%d:", fpos.line); |
d7482997 |
265 | if (fpos.col > 0) |
266 | fprintf(stderr, "%d:", fpos.col); |
267 | fputc(' ', stderr); |
268 | } |
269 | fputs(error, stderr); |
270 | fputc('\n', stderr); |
271 | } |
272 | |
273 | void fatal(int code, ...) { |
274 | va_list ap; |
275 | va_start(ap, code); |
276 | do_error(code, ap); |
277 | va_end(ap); |
278 | exit(EXIT_FAILURE); |
279 | } |
280 | |
281 | void error(int code, ...) { |
282 | va_list ap; |
283 | va_start(ap, code); |
284 | do_error(code, ap); |
285 | va_end(ap); |
286 | } |