Enforce that \q may not be used anywhere within \c. It shouldn't be
[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;
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 *);
85 sp = utoa_locale_dup(wsp);
86 fpos = *va_arg(ap, filepos *);
87 sprintf(error, "command `%.200s' unrecognised at start of"
88 " paragraph", sp);
89 flags = FILEPOS;
90 sfree(sp);
91 break;
92 case err_badmidcmd:
93 wsp = va_arg(ap, wchar_t *);
94 sp = utoa_locale_dup(wsp);
95 fpos = *va_arg(ap, filepos *);
96 sprintf(error, "command `%.200s' unexpected in mid-paragraph", sp);
97 flags = FILEPOS;
98 sfree(sp);
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;
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;
125 case err_missingrbrace:
126 fpos = *va_arg(ap, filepos *);
127 sprintf(error, "unclosed braces at end of paragraph");
128 flags = FILEPOS;
129 break;
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;
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;
145 case err_nosuchkw:
146 fpos = *va_arg(ap, filepos *);
147 wsp = va_arg(ap, wchar_t *);
148 sp = utoa_locale_dup(wsp);
149 sprintf(error, "unable to resolve cross-reference to `%.200s'", sp);
150 flags = FILEPOS;
151 sfree(sp);
152 break;
153 case err_multiBR:
154 fpos = *va_arg(ap, filepos *);
155 wsp = va_arg(ap, wchar_t *);
156 sp = utoa_locale_dup(wsp);
157 sprintf(error, "multiple `\\BR' entries given for `%.200s'", sp);
158 flags = FILEPOS;
159 sfree(sp);
160 break;
161 case err_nosuchidxtag:
162 fpos = *va_arg(ap, filepos *);
163 wsp = va_arg(ap, wchar_t *);
164 sp = utoa_locale_dup(wsp);
165 sprintf(error, "`\\IM' on unknown index tag `%.200s'", sp);
166 sfree(sp);
167 flags = FILEPOS;
168 break;
169 case err_cantopenw:
170 sp = va_arg(ap, char *);
171 sprintf(error, "unable to open output file `%.200s'", sp);
172 flags = PREFIX;
173 break;
174 case err_macroexists:
175 fpos = *va_arg(ap, filepos *);
176 wsp = va_arg(ap, wchar_t *);
177 sp = utoa_locale_dup(wsp);
178 sprintf(error, "macro `%.200s' already defined", sp);
179 flags = FILEPOS;
180 sfree(sp);
181 break;
182 case err_sectjump:
183 fpos = *va_arg(ap, filepos *);
184 sprintf(error, "expected higher heading levels before this one");
185 flags = FILEPOS;
186 break;
187 case err_winhelp_ctxclash:
188 fpos = *va_arg(ap, filepos *);
189 sp = va_arg(ap, char *);
190 sp2 = va_arg(ap, char *);
191 sprintf(error, "Windows Help context id `%.200s' clashes with "
192 "previously defined `%.200s'", sp, sp2);
193 flags = FILEPOS;
194 break;
195 case err_multikw:
196 fpos = *va_arg(ap, filepos *);
197 fpos2 = *va_arg(ap, filepos *);
198 wsp = va_arg(ap, wchar_t *);
199 sp = utoa_locale_dup(wsp);
200 sprintf(error, "paragraph keyword `%.200s' already defined at ", sp);
201 sprintf(error + strlen(error), "%s:%d", fpos2.filename, fpos2.line);
202 flags = FILEPOS;
203 sfree(sp);
204 break;
205 case err_misplacedlcont:
206 fpos = *va_arg(ap, filepos *);
207 sprintf(error, "\\lcont is only expected after a list item");
208 flags = FILEPOS;
209 break;
210 case err_sectmarkerinblock:
211 fpos = *va_arg(ap, filepos *);
212 sp = va_arg(ap, char *);
213 sprintf(error, "section headings are not supported within \\%.100s",
214 sp);
215 flags = FILEPOS;
216 break;
217 case err_infodirentry:
218 fpos = *va_arg(ap, filepos *);
219 sprintf(error, "\\cfg{info-dir-entry} expects at least three"
220 " parameters");
221 flags = FILEPOS;
222 break;
223 case err_infonodechar:
224 fpos = *va_arg(ap, filepos *);
225 c = (char)va_arg(ap, int);
226 sprintf(error, "info output format does not support '%c' in"
227 " node names; removing", c);
228 flags = FILEPOS;
229 break;
230 case err_text_codeline:
231 fpos = *va_arg(ap, filepos *);
232 i = va_arg(ap, int);
233 j = va_arg(ap, int);
234 sprintf(error, "warning: code paragraph line is %d chars wide, wider"
235 " than body width %d", i, j);
236 flags = FILEPOS;
237 break;
238 case err_whatever:
239 sp = va_arg(ap, char *);
240 vsprintf(error, sp, ap);
241 flags = PREFIX;
242 break;
243 }
244
245 if (flags & PREFIX)
246 fputs("halibut: ", stderr);
247 if (flags & FILEPOS) {
248 fprintf(stderr, "%s:", fpos.filename);
249 if (fpos.line > 0)
250 fprintf(stderr, "%d:", fpos.line);
251 if (fpos.col > 0)
252 fprintf(stderr, "%d:", fpos.col);
253 fputc(' ', stderr);
254 }
255 fputs(error, stderr);
256 fputc('\n', stderr);
257 }
258
259 void fatal(int code, ...) {
260 va_list ap;
261 va_start(ap, code);
262 do_error(code, ap);
263 va_end(ap);
264 exit(EXIT_FAILURE);
265 }
266
267 void error(int code, ...) {
268 va_list ap;
269 va_start(ap, code);
270 do_error(code, ap);
271 va_end(ap);
272 }