It would probably help to add a test of the INFO-DIR-ENTRY mechanism
[sgt/halibut] / main.c
CommitLineData
d7482997 1/*
2 * main.c: command line parsing and top level
3 */
4
c8fb54d2 5#include <assert.h>
d7482997 6#include <stdio.h>
7#include <stdlib.h>
8#include "halibut.h"
9
10static void dbg_prtsource(paragraph *sourceform);
11static void dbg_prtwordlist(int level, word *w);
12static void dbg_prtkws(keywordlist *kws);
13
c8fb54d2 14static const struct backend {
15 char *name;
16 void (*func)(paragraph *, keywordlist *, indexdata *);
ba9c1487 17 paragraph *(*filename)(char *filename);
c8fb54d2 18 int bitfield;
19} backends[] = {
ba9c1487 20 {"text", text_backend, text_config_filename, 0x0001},
21 {"xhtml", xhtml_backend, xhtml_config_filename, 0x0002},
22 {"html", xhtml_backend, xhtml_config_filename, 0x0002},
23 {"hlp", whlp_backend, whlp_config_filename, 0x0004},
24 {"whlp", whlp_backend, whlp_config_filename, 0x0004},
25 {"winhelp", whlp_backend, whlp_config_filename, 0x0004},
26 {"man", man_backend, man_config_filename, 0x0008},
5dd44dce 27 {"info", info_backend, info_config_filename, 0x0010},
c8fb54d2 28};
29
d7482997 30int main(int argc, char **argv) {
31 char **infiles;
d7482997 32 int nfiles;
33 int nogo;
34 int errs;
35 int reportcols;
36 int debug;
c8fb54d2 37 int backendbits;
38 int k, b;
6a0b9d08 39 paragraph *cfg, *cfg_tail;
d7482997 40
41 /*
42 * Set up initial (default) parameters.
43 */
44 infiles = mknewa(char *, argc);
d7482997 45 nfiles = 0;
46 nogo = errs = FALSE;
47 reportcols = 0;
48 debug = 0;
c8fb54d2 49 backendbits = 0;
6a0b9d08 50 cfg = cfg_tail = NULL;
d7482997 51
52 if (argc == 1) {
53 usage();
54 exit(EXIT_SUCCESS);
55 }
56
57 /*
58 * Parse command line arguments.
59 */
60 while (--argc) {
61 char *p = *++argv;
62 if (*p == '-') {
63 /*
64 * An option.
65 */
66 while (p && *++p) {
67 char c = *p;
68 switch (c) {
69 case '-':
70 /*
71 * Long option.
72 */
73 {
74 char *opt, *val;
75 opt = p++; /* opt will have _one_ leading - */
76 while (*p && *p != '=')
77 p++; /* find end of option */
78 if (*p == '=') {
79 *p++ = '\0';
80 val = p;
81 } else
82 val = NULL;
c8fb54d2 83
84 assert(opt[0] == '-');
85 for (k = 0; k < (int)lenof(backends); k++)
86 if (!strcmp(opt+1, backends[k].name)) {
87 backendbits |= backends[k].bitfield;
ba9c1487 88 if (val) {
89 paragraph *p = backends[k].filename(val);
90 assert(p);
91 if (cfg_tail)
92 cfg_tail->next = p;
93 else
94 cfg = p;
95 while (p->next)
96 p = p->next;
97 cfg_tail = p;
98 }
c8fb54d2 99 break;
100 }
101 if (k < (int)lenof(backends)) {
102 /* do nothing */;
103 } else if (!strcmp(opt, "-help")) {
d7482997 104 help();
105 nogo = TRUE;
106 } else if (!strcmp(opt, "-version")) {
107 showversion();
108 nogo = TRUE;
109 } else if (!strcmp(opt, "-licence") ||
110 !strcmp(opt, "-license")) {
111 licence();
112 nogo = TRUE;
d7482997 113 } else if (!strcmp(opt, "-precise")) {
114 reportcols = 1;
115 } else {
116 errs = TRUE, error(err_nosuchopt, opt);
117 }
118 }
119 p = NULL;
120 break;
121 case 'h':
122 case 'V':
123 case 'L':
124 case 'P':
125 case 'd':
126 /*
127 * Option requiring no parameter.
128 */
129 switch (c) {
130 case 'h':
131 help();
132 nogo = TRUE;
133 break;
134 case 'V':
135 showversion();
136 nogo = TRUE;
137 break;
138 case 'L':
139 licence();
140 nogo = TRUE;
141 break;
142 case 'P':
143 reportcols = 1;
144 break;
145 case 'd':
146 debug = TRUE;
147 break;
148 }
149 break;
6a0b9d08 150 case 'C':
d7482997 151 /*
152 * Option requiring parameter.
153 */
154 p++;
155 if (!*p && argc > 1)
156 --argc, p = *++argv;
157 else if (!*p) {
158 char opt[2];
159 opt[0] = c;
160 opt[1] = '\0';
161 errs = TRUE, error(err_optnoarg, opt);
162 }
163 /*
164 * Now c is the option and p is the parameter.
165 */
166 switch (c) {
6a0b9d08 167 case 'C':
168 /*
169 * -C means we split our argument up into
170 * colon-separated chunks and assemble them
171 * into a config paragraph.
172 */
173 {
174 wchar_t *keywords;
175 char *q;
176 wchar_t *u;
177 paragraph *para;
178
179 keywords = mknewa(wchar_t, 2+strlen(p));
180
181 u = keywords;
182 q = p;
183
184 while (*q) {
185 if (*q == ':') {
186 *u++ = L'\0';
187 } else {
188 if (*q == '\\' && q[1])
189 q++;
190 /* FIXME: lacks charset flexibility */
191 *u++ = *q;
192 }
193 q++;
194 }
195 *u = L'\0';
196
197 para = mknew(paragraph);
198 memset(para, 0, sizeof(*para));
199 para->type = para_Config;
200 para->keyword = keywords;
201 para->next = NULL;
202 para->fpos.filename = "<command line>";
203 para->fpos.line = para->fpos.col = -1;
204
205 if (cfg_tail)
206 cfg_tail->next = para;
207 else
208 cfg = para;
209 cfg_tail = para;
210 }
d7482997 211 break;
212 }
213 p = NULL; /* prevent continued processing */
214 break;
215 default:
216 /*
217 * Unrecognised option.
218 */
219 {
220 char opt[2];
221 opt[0] = c;
222 opt[1] = '\0';
223 errs = TRUE, error(err_nosuchopt, opt);
224 }
225 }
226 }
227 } else {
228 /*
229 * A non-option argument.
230 */
231 infiles[nfiles++] = p;
232 }
233 }
234
235 if (errs)
236 exit(EXIT_FAILURE);
237 if (nogo)
238 exit(EXIT_SUCCESS);
239
240 /*
241 * Do the work.
242 */
243 if (nfiles == 0) {
244 error(err_noinput);
245 usage();
246 exit(EXIT_FAILURE);
247 }
248
249 {
250 input in;
251 paragraph *sourceform, *p;
252 indexdata *idx;
253 keywordlist *keywords;
254
255 in.filenames = infiles;
256 in.nfiles = nfiles;
257 in.currfp = NULL;
258 in.currindex = 0;
259 in.npushback = in.pushbacksize = 0;
260 in.pushback = NULL;
261 in.reportcols = reportcols;
262 in.stack = NULL;
263
264 idx = make_index();
265
266 sourceform = read_input(&in, idx);
267 if (!sourceform)
268 exit(EXIT_FAILURE);
269
6a0b9d08 270 /*
271 * Append the config directives acquired from the command
272 * line.
273 */
274 {
275 paragraph *end;
276
277 end = sourceform;
278 while (end && end->next)
279 end = end->next;
280 assert(end);
281
282 end->next = cfg;
283 }
284
d7482997 285 sfree(in.pushback);
286
287 mark_attr_ends(sourceform);
288
289 sfree(infiles);
290
291 keywords = get_keywords(sourceform);
292 if (!keywords)
293 exit(EXIT_FAILURE);
294 gen_citations(sourceform, keywords);
295 subst_keywords(sourceform, keywords);
296
297 for (p = sourceform; p; p = p->next)
298 if (p->type == para_IM)
299 index_merge(idx, TRUE, p->keyword, p->words);
300
301 build_index(idx);
302
303 if (debug) {
304 index_debug(idx);
305 dbg_prtkws(keywords);
306 dbg_prtsource(sourceform);
307 }
308
c8fb54d2 309 /*
310 * Run the selected set of backends.
311 */
312 for (k = b = 0; k < (int)lenof(backends); k++)
313 if (b != backends[k].bitfield) {
314 b = backends[k].bitfield;
315 if (backendbits == 0 || (backendbits & b))
316 backends[k].func(sourceform, keywords, idx);
317 }
d7482997 318
319 free_para_list(sourceform);
320 free_keywords(keywords);
321 cleanup_index(idx);
322 }
323
324 return 0;
325}
326
327static void dbg_prtsource(paragraph *sourceform) {
328 /*
329 * Output source form in debugging format.
330 */
331
332 paragraph *p;
333 for (p = sourceform; p; p = p->next) {
334 wchar_t *wp;
335 printf("para %d ", p->type);
336 if (p->keyword) {
337 wp = p->keyword;
338 while (*wp) {
339 putchar('\"');
340 for (; *wp; wp++)
341 putchar(*wp);
342 putchar('\"');
343 if (*++wp)
344 printf(", ");
345 }
346 } else
347 printf("(no keyword)");
348 printf(" {\n");
349 dbg_prtwordlist(1, p->words);
350 printf("}\n");
351 }
352}
353
354static void dbg_prtkws(keywordlist *kws) {
355 /*
356 * Output keywords in debugging format.
357 */
358
359 int i;
360 keyword *kw;
361
362 for (i = 0; (kw = index234(kws->keys, i)) != NULL; i++) {
363 wchar_t *wp;
364 printf("keyword ");
365 wp = kw->key;
366 while (*wp) {
367 putchar('\"');
368 for (; *wp; wp++)
369 putchar(*wp);
370 putchar('\"');
371 if (*++wp)
372 printf(", ");
373 }
374 printf(" {\n");
375 dbg_prtwordlist(1, kw->text);
376 printf("}\n");
377 }
378}
379
380static void dbg_prtwordlist(int level, word *w) {
381 for (; w; w = w->next) {
382 wchar_t *wp;
383 printf("%*sword %d ", level*4, "", w->type);
384 if (w->text) {
385 printf("\"");
386 for (wp = w->text; *wp; wp++)
387 putchar(*wp);
388 printf("\"");
389 } else
390 printf("(no text)");
391 if (w->alt) {
392 printf(" alt = {\n");
393 dbg_prtwordlist(level+1, w->alt);
394 printf("%*s}", level*4, "");
395 }
396 printf("\n");
397 }
398}