Infrastructure changes for character set support. ustrtoa,
[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 auxbuf[256];
19 char c;
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 = ustrtoa(wsp, auxbuf, sizeof(auxbuf), CS_LOCAL);
86 fpos = *va_arg(ap, filepos *);
87 sprintf(error, "command `%.200s' unrecognised at start of"
88 " paragraph", sp);
89 flags = FILEPOS;
90 break;
91 case err_badmidcmd:
92 wsp = va_arg(ap, wchar_t *);
93 sp = ustrtoa(wsp, auxbuf, sizeof(auxbuf), CS_LOCAL);
94 fpos = *va_arg(ap, filepos *);
95 sprintf(error, "command `%.200s' unexpected in mid-paragraph", sp);
96 flags = FILEPOS;
97 break;
98 case err_unexbrace:
99 fpos = *va_arg(ap, filepos *);
100 sprintf(error, "brace character unexpected in mid-paragraph");
101 flags = FILEPOS;
102 break;
103 case err_explbr:
104 fpos = *va_arg(ap, filepos *);
105 sprintf(error, "expected `{' after command");
106 flags = FILEPOS;
107 break;
108 case err_commenteof:
109 fpos = *va_arg(ap, filepos *);
110 sprintf(error, "end of file unexpected inside `\\#{...}' comment");
111 flags = FILEPOS;
112 break;
113 case err_kwexprbr:
114 fpos = *va_arg(ap, filepos *);
115 sprintf(error, "expected `}' after cross-reference");
116 flags = FILEPOS;
117 break;
118 case err_missingrbrace:
119 fpos = *va_arg(ap, filepos *);
120 sprintf(error, "unclosed braces at end of paragraph");
121 flags = FILEPOS;
122 break;
123 case err_missingrbrace2:
124 fpos = *va_arg(ap, filepos *);
125 sprintf(error, "unclosed braces at end of input file");
126 flags = FILEPOS;
127 break;
128 case err_nestedstyles:
129 fpos = *va_arg(ap, filepos *);
130 sprintf(error, "unable to nest text styles");
131 flags = FILEPOS;
132 break;
133 case err_nestedindex:
134 fpos = *va_arg(ap, filepos *);
135 sprintf(error, "unable to nest index markings");
136 flags = FILEPOS;
137 break;
138 case err_nosuchkw:
139 fpos = *va_arg(ap, filepos *);
140 wsp = va_arg(ap, wchar_t *);
141 sp = ustrtoa(wsp, auxbuf, sizeof(auxbuf), CS_LOCAL);
142 sprintf(error, "unable to resolve cross-reference to `%.200s'", sp);
143 flags = FILEPOS;
144 break;
145 case err_multiBR:
146 fpos = *va_arg(ap, filepos *);
147 wsp = va_arg(ap, wchar_t *);
148 sp = ustrtoa(wsp, auxbuf, sizeof(auxbuf), CS_LOCAL);
149 sprintf(error, "multiple `\\BR' entries given for `%.200s'", sp);
150 flags = FILEPOS;
151 break;
152 case err_nosuchidxtag:
153 wsp = va_arg(ap, wchar_t *);
154 sp = ustrtoa(wsp, auxbuf, sizeof(auxbuf), CS_LOCAL);
155 sprintf(error, "`\\IM' on unknown index tag `%.200s'", sp);
156 flags = 0;
157 /* FIXME: need to get a filepos to here somehow */
158 break;
159 case err_cantopenw:
160 sp = va_arg(ap, char *);
161 sprintf(error, "unable to open output file `%.200s'", sp);
162 flags = PREFIX;
163 break;
164 case err_macroexists:
165 fpos = *va_arg(ap, filepos *);
166 wsp = va_arg(ap, wchar_t *);
167 sp = ustrtoa(wsp, auxbuf, sizeof(auxbuf), CS_LOCAL);
168 sprintf(error, "macro `%.200s' already defined", sp);
169 flags = FILEPOS;
170 break;
171 case err_sectjump:
172 fpos = *va_arg(ap, filepos *);
173 sprintf(error, "expected higher heading levels before this one");
174 flags = FILEPOS;
175 break;
176 case err_winhelp_ctxclash:
177 fpos = *va_arg(ap, filepos *);
178 sp = va_arg(ap, char *);
179 sp2 = va_arg(ap, char *);
180 sprintf(error, "Windows Help context id `%.200s' clashes with "
181 "previously defined `%.200s'", sp, sp2);
182 flags = FILEPOS;
183 break;
184 case err_multikw:
185 fpos = *va_arg(ap, filepos *);
186 fpos2 = *va_arg(ap, filepos *);
187 wsp = va_arg(ap, wchar_t *);
188 sp = ustrtoa(wsp, auxbuf, sizeof(auxbuf), CS_LOCAL);
189 sprintf(error, "paragraph keyword `%.200s' already defined at ", sp);
190 sprintf(error + strlen(error), "%s:%d", fpos2.filename, fpos2.line);
191 flags = FILEPOS;
192 break;
193 case err_misplacedlcont:
194 fpos = *va_arg(ap, filepos *);
195 sprintf(error, "\\lcont is only expected after a list item");
196 flags = FILEPOS;
197 break;
198 case err_sectmarkerinblock:
199 fpos = *va_arg(ap, filepos *);
200 sp = va_arg(ap, char *);
201 sprintf(error, "section headings are not supported within \\%.100s",
202 sp);
203 flags = FILEPOS;
204 break;
205 case err_infodirentry:
206 fpos = *va_arg(ap, filepos *);
207 sprintf(error, "\\cfg{info-dir-entry} expects at least three"
208 " parameters");
209 flags = FILEPOS;
210 break;
211 case err_infonodechar:
212 fpos = *va_arg(ap, filepos *);
213 c = (char)va_arg(ap, int);
214 sprintf(error, "info output format does not support '%c' in"
215 " node names; removing", c);
216 flags = FILEPOS;
217 break;
218 case err_whatever:
219 sp = va_arg(ap, char *);
220 vsprintf(error, sp, ap);
221 flags = PREFIX;
222 break;
223 }
224
225 if (flags & PREFIX)
226 fputs("halibut: ", stderr);
227 if (flags & FILEPOS) {
228 fprintf(stderr, "%s:", fpos.filename);
229 if (fpos.line > 0)
230 fprintf(stderr, "%d:", fpos.line);
231 if (fpos.col > 0)
232 fprintf(stderr, "%d:", fpos.col);
233 fputc(' ', stderr);
234 }
235 fputs(error, stderr);
236 fputc('\n', stderr);
237 }
238
239 void fatal(int code, ...) {
240 va_list ap;
241 va_start(ap, code);
242 do_error(code, ap);
243 va_end(ap);
244 exit(EXIT_FAILURE);
245 }
246
247 void error(int code, ...) {
248 va_list ap;
249 va_start(ap, code);
250 do_error(code, ap);
251 va_end(ap);
252 }