Charset support for the man page backend (\cfg{man-charset}).
[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
43341922 14static const struct pre_backend {
15 void *(*func)(paragraph *, keywordlist *, indexdata *);
16 int bitfield;
17} pre_backends[] = {
18 {paper_pre_backend, 0x0001}
19};
20
c8fb54d2 21static const struct backend {
22 char *name;
43341922 23 void (*func)(paragraph *, keywordlist *, indexdata *, void *);
ba9c1487 24 paragraph *(*filename)(char *filename);
43341922 25 int bitfield, prebackend_bitfield;
c8fb54d2 26} backends[] = {
43341922 27 {"text", text_backend, text_config_filename, 0x0001, 0},
28 {"xhtml", xhtml_backend, xhtml_config_filename, 0x0002, 0},
29 {"html", xhtml_backend, xhtml_config_filename, 0x0002, 0},
30 {"hlp", whlp_backend, whlp_config_filename, 0x0004, 0},
31 {"whlp", whlp_backend, whlp_config_filename, 0x0004, 0},
32 {"winhelp", whlp_backend, whlp_config_filename, 0x0004, 0},
33 {"man", man_backend, man_config_filename, 0x0008, 0},
34 {"info", info_backend, info_config_filename, 0x0010, 0},
35 {"ps", ps_backend, ps_config_filename, 0x0020, 0x0001},
36 {"pdf", pdf_backend, pdf_config_filename, 0x0040, 0x0001},
c8fb54d2 37};
38
d7482997 39int main(int argc, char **argv) {
40 char **infiles;
d7482997 41 int nfiles;
42 int nogo;
43 int errs;
44 int reportcols;
45 int debug;
43341922 46 int backendbits, prebackbits;
c8fb54d2 47 int k, b;
6a0b9d08 48 paragraph *cfg, *cfg_tail;
43341922 49 void *pre_backend_data[16];
d7482997 50
51 /*
52 * Set up initial (default) parameters.
53 */
54 infiles = mknewa(char *, argc);
d7482997 55 nfiles = 0;
56 nogo = errs = FALSE;
57 reportcols = 0;
58 debug = 0;
c8fb54d2 59 backendbits = 0;
6a0b9d08 60 cfg = cfg_tail = NULL;
d7482997 61
62 if (argc == 1) {
63 usage();
64 exit(EXIT_SUCCESS);
65 }
66
67 /*
68 * Parse command line arguments.
69 */
70 while (--argc) {
71 char *p = *++argv;
72 if (*p == '-') {
73 /*
74 * An option.
75 */
76 while (p && *++p) {
77 char c = *p;
78 switch (c) {
79 case '-':
80 /*
81 * Long option.
82 */
83 {
84 char *opt, *val;
85 opt = p++; /* opt will have _one_ leading - */
86 while (*p && *p != '=')
87 p++; /* find end of option */
88 if (*p == '=') {
89 *p++ = '\0';
90 val = p;
91 } else
92 val = NULL;
c8fb54d2 93
94 assert(opt[0] == '-');
95 for (k = 0; k < (int)lenof(backends); k++)
96 if (!strcmp(opt+1, backends[k].name)) {
97 backendbits |= backends[k].bitfield;
ba9c1487 98 if (val) {
99 paragraph *p = backends[k].filename(val);
100 assert(p);
101 if (cfg_tail)
102 cfg_tail->next = p;
103 else
104 cfg = p;
105 while (p->next)
106 p = p->next;
107 cfg_tail = p;
108 }
c8fb54d2 109 break;
110 }
111 if (k < (int)lenof(backends)) {
112 /* do nothing */;
113 } else if (!strcmp(opt, "-help")) {
d7482997 114 help();
115 nogo = TRUE;
116 } else if (!strcmp(opt, "-version")) {
117 showversion();
118 nogo = TRUE;
119 } else if (!strcmp(opt, "-licence") ||
120 !strcmp(opt, "-license")) {
121 licence();
122 nogo = TRUE;
d7482997 123 } else if (!strcmp(opt, "-precise")) {
124 reportcols = 1;
125 } else {
126 errs = TRUE, error(err_nosuchopt, opt);
127 }
128 }
129 p = NULL;
130 break;
131 case 'h':
132 case 'V':
133 case 'L':
134 case 'P':
135 case 'd':
136 /*
137 * Option requiring no parameter.
138 */
139 switch (c) {
140 case 'h':
141 help();
142 nogo = TRUE;
143 break;
144 case 'V':
145 showversion();
146 nogo = TRUE;
147 break;
148 case 'L':
149 licence();
150 nogo = TRUE;
151 break;
152 case 'P':
153 reportcols = 1;
154 break;
155 case 'd':
156 debug = TRUE;
157 break;
158 }
159 break;
6a0b9d08 160 case 'C':
d7482997 161 /*
162 * Option requiring parameter.
163 */
164 p++;
165 if (!*p && argc > 1)
166 --argc, p = *++argv;
167 else if (!*p) {
168 char opt[2];
169 opt[0] = c;
170 opt[1] = '\0';
171 errs = TRUE, error(err_optnoarg, opt);
172 }
173 /*
174 * Now c is the option and p is the parameter.
175 */
176 switch (c) {
6a0b9d08 177 case 'C':
178 /*
179 * -C means we split our argument up into
180 * colon-separated chunks and assemble them
181 * into a config paragraph.
182 */
183 {
e4ea58f8 184 char *s = dupstr(p), *q, *r;
6a0b9d08 185 paragraph *para;
186
e4ea58f8 187 para = cmdline_cfg_new();
6a0b9d08 188
e4ea58f8 189 q = r = s;
6a0b9d08 190 while (*q) {
191 if (*q == ':') {
e4ea58f8 192 *r = '\0';
193 cmdline_cfg_add(para, s);
194 r = s;
6a0b9d08 195 } else {
196 if (*q == '\\' && q[1])
197 q++;
e4ea58f8 198 *r++ = *q;
6a0b9d08 199 }
200 q++;
201 }
57e17355 202 *r = '\0';
e4ea58f8 203 cmdline_cfg_add(para, s);
6a0b9d08 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;
e34ba5c3 263 in.defcharset = CS_ASCII;
d7482997 264
265 idx = make_index();
266
267 sourceform = read_input(&in, idx);
268 if (!sourceform)
269 exit(EXIT_FAILURE);
270
6a0b9d08 271 /*
272 * Append the config directives acquired from the command
273 * line.
274 */
275 {
276 paragraph *end;
277
278 end = sourceform;
279 while (end && end->next)
280 end = end->next;
281 assert(end);
282
283 end->next = cfg;
284 }
285
d7482997 286 sfree(in.pushback);
287
288 mark_attr_ends(sourceform);
289
290 sfree(infiles);
291
292 keywords = get_keywords(sourceform);
293 if (!keywords)
294 exit(EXIT_FAILURE);
295 gen_citations(sourceform, keywords);
296 subst_keywords(sourceform, keywords);
297
298 for (p = sourceform; p; p = p->next)
299 if (p->type == para_IM)
f4551933 300 index_merge(idx, TRUE, p->keyword, p->words, &p->fpos);
d7482997 301
302 build_index(idx);
303
304 if (debug) {
305 index_debug(idx);
306 dbg_prtkws(keywords);
307 dbg_prtsource(sourceform);
308 }
309
c8fb54d2 310 /*
43341922 311 * Select and run the pre-backends.
312 */
313 prebackbits = 0;
314 for (k = 0; k < (int)lenof(backends); k++)
315 if (backendbits == 0 || (backendbits & backends[k].bitfield))
316 prebackbits |= backends[k].prebackend_bitfield;
317 for (k = 0; k < (int)lenof(pre_backends); k++)
318 if (prebackbits & pre_backends[k].bitfield) {
319 assert(k < (int)lenof(pre_backend_data));
320 pre_backend_data[k] =
321 pre_backends[k].func(sourceform, keywords, idx);
322 }
323
324 /*
c8fb54d2 325 * Run the selected set of backends.
326 */
327 for (k = b = 0; k < (int)lenof(backends); k++)
328 if (b != backends[k].bitfield) {
329 b = backends[k].bitfield;
43341922 330 if (backendbits == 0 || (backendbits & b)) {
331 void *pbd = NULL;
332 int pbb = backends[k].prebackend_bitfield;
333 int m;
334
335 for (m = 0; m < (int)lenof(pre_backends); m++)
336 if (pbb & pre_backends[m].bitfield) {
337 assert(m < (int)lenof(pre_backend_data));
338 pbd = pre_backend_data[m];
339 break;
340 }
341
342 backends[k].func(sourceform, keywords, idx, pbd);
343 }
c8fb54d2 344 }
d7482997 345
346 free_para_list(sourceform);
347 free_keywords(keywords);
348 cleanup_index(idx);
349 }
350
351 return 0;
352}
353
354static void dbg_prtsource(paragraph *sourceform) {
355 /*
356 * Output source form in debugging format.
357 */
358
359 paragraph *p;
360 for (p = sourceform; p; p = p->next) {
361 wchar_t *wp;
362 printf("para %d ", p->type);
363 if (p->keyword) {
364 wp = p->keyword;
365 while (*wp) {
366 putchar('\"');
367 for (; *wp; wp++)
368 putchar(*wp);
369 putchar('\"');
370 if (*++wp)
371 printf(", ");
372 }
373 } else
374 printf("(no keyword)");
375 printf(" {\n");
376 dbg_prtwordlist(1, p->words);
377 printf("}\n");
378 }
379}
380
381static void dbg_prtkws(keywordlist *kws) {
382 /*
383 * Output keywords in debugging format.
384 */
385
386 int i;
387 keyword *kw;
388
389 for (i = 0; (kw = index234(kws->keys, i)) != NULL; i++) {
390 wchar_t *wp;
391 printf("keyword ");
392 wp = kw->key;
393 while (*wp) {
394 putchar('\"');
395 for (; *wp; wp++)
396 putchar(*wp);
397 putchar('\"');
398 if (*++wp)
399 printf(", ");
400 }
401 printf(" {\n");
402 dbg_prtwordlist(1, kw->text);
403 printf("}\n");
404 }
405}
406
407static void dbg_prtwordlist(int level, word *w) {
408 for (; w; w = w->next) {
409 wchar_t *wp;
410 printf("%*sword %d ", level*4, "", w->type);
411 if (w->text) {
412 printf("\"");
413 for (wp = w->text; *wp; wp++)
414 putchar(*wp);
415 printf("\"");
416 } else
417 printf("(no text)");
418 if (w->alt) {
419 printf(" alt = {\n");
420 dbg_prtwordlist(level+1, w->alt);
421 printf("%*s}", level*4, "");
422 }
423 printf("\n");
424 }
425}