Import mdocml-1.11.3
[dragonfly.git] / contrib / mdocml / main.c
CommitLineData
a4c7eb57 1/* $Id: main.c,v 1.163 2011/05/20 15:51:18 kristaps Exp $ */
80387638
SW
2/*
3 * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
60e1e752 4 * Copyright (c) 2010, 2011 Ingo Schwarze <schwarze@openbsd.org>
80387638
SW
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18#ifdef HAVE_CONFIG_H
19#include "config.h"
20#endif
21
80387638 22#include <assert.h>
80387638
SW
23#include <stdio.h>
24#include <stdint.h>
25#include <stdlib.h>
26#include <string.h>
27#include <unistd.h>
28
29#include "mandoc.h"
30#include "main.h"
31#include "mdoc.h"
32#include "man.h"
80387638
SW
33
34#if !defined(__GNUC__) || (__GNUC__ < 2)
35# if !defined(lint)
36# define __attribute__(x)
37# endif
38#endif /* !defined(__GNUC__) || (__GNUC__ < 2) */
39
40typedef void (*out_mdoc)(void *, const struct mdoc *);
41typedef void (*out_man)(void *, const struct man *);
42typedef void (*out_free)(void *);
43
80387638 44enum outt {
60e1e752 45 OUTT_ASCII = 0, /* -Tascii */
a4c7eb57
SW
46 OUTT_LOCALE, /* -Tlocale */
47 OUTT_UTF8, /* -Tutf8 */
60e1e752
SW
48 OUTT_TREE, /* -Ttree */
49 OUTT_HTML, /* -Thtml */
50 OUTT_XHTML, /* -Txhtml */
51 OUTT_LINT, /* -Tlint */
52 OUTT_PS, /* -Tps */
53 OUTT_PDF /* -Tpdf */
80387638
SW
54};
55
56struct curparse {
60e1e752
SW
57 struct mparse *mp;
58 enum mandoclevel wlevel; /* ignore messages below this */
59 int wstop; /* stop after a file with a warning */
80387638
SW
60 enum outt outtype; /* which output to use */
61 out_mdoc outmdoc; /* mdoc output ptr */
62 out_man outman; /* man output ptr */
63 out_free outfree; /* free output ptr */
64 void *outdata; /* data for output */
65 char outopts[BUFSIZ]; /* buf of output opts */
66};
67
60e1e752
SW
68static int moptions(enum mparset *, char *);
69static void mmsg(enum mandocerr, enum mandoclevel,
70 const char *, int, int, const char *);
71static void parse(struct curparse *, int,
72 const char *, enum mandoclevel *);
80387638
SW
73static int toptions(struct curparse *, char *);
74static void usage(void) __attribute__((noreturn));
75static void version(void) __attribute__((noreturn));
76static int woptions(struct curparse *, char *);
77
78static const char *progname;
80387638
SW
79
80int
81main(int argc, char *argv[])
82{
83 int c;
84 struct curparse curp;
60e1e752
SW
85 enum mparset type;
86 enum mandoclevel rc;
80387638
SW
87
88 progname = strrchr(argv[0], '/');
89 if (progname == NULL)
90 progname = argv[0];
91 else
92 ++progname;
93
94 memset(&curp, 0, sizeof(struct curparse));
95
60e1e752 96 type = MPARSE_AUTO;
80387638
SW
97 curp.outtype = OUTT_ASCII;
98 curp.wlevel = MANDOCLEVEL_FATAL;
99
100 /* LINTED */
101 while (-1 != (c = getopt(argc, argv, "m:O:T:VW:")))
102 switch (c) {
103 case ('m'):
60e1e752 104 if ( ! moptions(&type, optarg))
80387638
SW
105 return((int)MANDOCLEVEL_BADARG);
106 break;
107 case ('O'):
108 (void)strlcat(curp.outopts, optarg, BUFSIZ);
109 (void)strlcat(curp.outopts, ",", BUFSIZ);
110 break;
111 case ('T'):
112 if ( ! toptions(&curp, optarg))
113 return((int)MANDOCLEVEL_BADARG);
114 break;
115 case ('W'):
116 if ( ! woptions(&curp, optarg))
117 return((int)MANDOCLEVEL_BADARG);
118 break;
119 case ('V'):
120 version();
121 /* NOTREACHED */
122 default:
123 usage();
124 /* NOTREACHED */
125 }
126
60e1e752
SW
127 curp.mp = mparse_alloc(type, curp.wlevel, mmsg, &curp);
128
80387638
SW
129 argc -= optind;
130 argv += optind;
131
60e1e752 132 rc = MANDOCLEVEL_OK;
80387638 133
60e1e752
SW
134 if (NULL == *argv)
135 parse(&curp, STDIN_FILENO, "<stdin>", &rc);
80387638
SW
136
137 while (*argv) {
60e1e752
SW
138 parse(&curp, -1, *argv, &rc);
139 if (MANDOCLEVEL_OK != rc && curp.wstop)
80387638
SW
140 break;
141 ++argv;
142 }
143
144 if (curp.outfree)
145 (*curp.outfree)(curp.outdata);
60e1e752
SW
146 if (curp.mp)
147 mparse_free(curp.mp);
80387638 148
60e1e752 149 return((int)rc);
80387638
SW
150}
151
80387638
SW
152static void
153version(void)
154{
155
60e1e752 156 printf("%s %s\n", progname, VERSION);
80387638
SW
157 exit((int)MANDOCLEVEL_OK);
158}
159
80387638
SW
160static void
161usage(void)
162{
163
60e1e752 164 fprintf(stderr, "usage: %s "
80387638
SW
165 "[-V] "
166 "[-foption] "
167 "[-mformat] "
168 "[-Ooption] "
169 "[-Toutput] "
60e1e752 170 "[-Wlevel] "
80387638
SW
171 "[file...]\n",
172 progname);
173
174 exit((int)MANDOCLEVEL_BADARG);
175}
176
177static void
60e1e752
SW
178parse(struct curparse *curp, int fd,
179 const char *file, enum mandoclevel *level)
80387638 180{
60e1e752
SW
181 enum mandoclevel rc;
182 struct mdoc *mdoc;
183 struct man *man;
80387638 184
60e1e752 185 /* Begin by parsing the file itself. */
80387638 186
60e1e752
SW
187 assert(file);
188 assert(fd >= -1);
80387638 189
60e1e752 190 rc = mparse_readfd(curp->mp, fd, file);
80387638 191
60e1e752 192 /* Stop immediately if the parse has failed. */
80387638 193
60e1e752 194 if (MANDOCLEVEL_FATAL <= rc)
80387638 195 goto cleanup;
80387638
SW
196
197 /*
60e1e752
SW
198 * With -Wstop and warnings or errors of at least the requested
199 * level, do not produce output.
80387638
SW
200 */
201
60e1e752 202 if (MANDOCLEVEL_OK != rc && curp->wstop)
80387638
SW
203 goto cleanup;
204
205 /* If unset, allocate output dev now (if applicable). */
206
207 if ( ! (curp->outman && curp->outmdoc)) {
208 switch (curp->outtype) {
209 case (OUTT_XHTML):
210 curp->outdata = xhtml_alloc(curp->outopts);
a4c7eb57 211 curp->outfree = html_free;
80387638
SW
212 break;
213 case (OUTT_HTML):
214 curp->outdata = html_alloc(curp->outopts);
a4c7eb57
SW
215 curp->outfree = html_free;
216 break;
217 case (OUTT_UTF8):
218 curp->outdata = utf8_alloc(curp->outopts);
219 curp->outfree = ascii_free;
220 break;
221 case (OUTT_LOCALE):
222 curp->outdata = locale_alloc(curp->outopts);
223 curp->outfree = ascii_free;
80387638
SW
224 break;
225 case (OUTT_ASCII):
226 curp->outdata = ascii_alloc(curp->outopts);
227 curp->outfree = ascii_free;
228 break;
229 case (OUTT_PDF):
230 curp->outdata = pdf_alloc(curp->outopts);
231 curp->outfree = pspdf_free;
232 break;
233 case (OUTT_PS):
234 curp->outdata = ps_alloc(curp->outopts);
235 curp->outfree = pspdf_free;
236 break;
237 default:
238 break;
239 }
240
241 switch (curp->outtype) {
242 case (OUTT_HTML):
243 /* FALLTHROUGH */
244 case (OUTT_XHTML):
245 curp->outman = html_man;
246 curp->outmdoc = html_mdoc;
80387638
SW
247 break;
248 case (OUTT_TREE):
249 curp->outman = tree_man;
250 curp->outmdoc = tree_mdoc;
251 break;
252 case (OUTT_PDF):
253 /* FALLTHROUGH */
254 case (OUTT_ASCII):
255 /* FALLTHROUGH */
a4c7eb57
SW
256 case (OUTT_UTF8):
257 /* FALLTHROUGH */
258 case (OUTT_LOCALE):
259 /* FALLTHROUGH */
80387638
SW
260 case (OUTT_PS):
261 curp->outman = terminal_man;
262 curp->outmdoc = terminal_mdoc;
263 break;
264 default:
265 break;
266 }
267 }
268
60e1e752
SW
269 mparse_result(curp->mp, &mdoc, &man);
270
80387638
SW
271 /* Execute the out device, if it exists. */
272
60e1e752
SW
273 if (man && curp->outman)
274 (*curp->outman)(curp->outdata, man);
275 if (mdoc && curp->outmdoc)
276 (*curp->outmdoc)(curp->outdata, mdoc);
80387638
SW
277
278 cleanup:
279
60e1e752 280 mparse_reset(curp->mp);
80387638 281
60e1e752
SW
282 if (*level < rc)
283 *level = rc;
80387638
SW
284}
285
286static int
60e1e752 287moptions(enum mparset *tflags, char *arg)
80387638
SW
288{
289
290 if (0 == strcmp(arg, "doc"))
60e1e752 291 *tflags = MPARSE_MDOC;
80387638 292 else if (0 == strcmp(arg, "andoc"))
60e1e752 293 *tflags = MPARSE_AUTO;
80387638 294 else if (0 == strcmp(arg, "an"))
60e1e752 295 *tflags = MPARSE_MAN;
80387638
SW
296 else {
297 fprintf(stderr, "%s: Bad argument\n", arg);
298 return(0);
299 }
300
301 return(1);
302}
303
304static int
305toptions(struct curparse *curp, char *arg)
306{
307
308 if (0 == strcmp(arg, "ascii"))
309 curp->outtype = OUTT_ASCII;
310 else if (0 == strcmp(arg, "lint")) {
311 curp->outtype = OUTT_LINT;
312 curp->wlevel = MANDOCLEVEL_WARNING;
60e1e752 313 } else if (0 == strcmp(arg, "tree"))
80387638
SW
314 curp->outtype = OUTT_TREE;
315 else if (0 == strcmp(arg, "html"))
316 curp->outtype = OUTT_HTML;
a4c7eb57
SW
317 else if (0 == strcmp(arg, "utf8"))
318 curp->outtype = OUTT_UTF8;
319 else if (0 == strcmp(arg, "locale"))
320 curp->outtype = OUTT_LOCALE;
80387638
SW
321 else if (0 == strcmp(arg, "xhtml"))
322 curp->outtype = OUTT_XHTML;
323 else if (0 == strcmp(arg, "ps"))
324 curp->outtype = OUTT_PS;
325 else if (0 == strcmp(arg, "pdf"))
326 curp->outtype = OUTT_PDF;
327 else {
328 fprintf(stderr, "%s: Bad argument\n", arg);
329 return(0);
330 }
331
332 return(1);
333}
334
335static int
336woptions(struct curparse *curp, char *arg)
337{
338 char *v, *o;
339 const char *toks[6];
340
341 toks[0] = "stop";
342 toks[1] = "all";
343 toks[2] = "warning";
344 toks[3] = "error";
345 toks[4] = "fatal";
346 toks[5] = NULL;
347
348 while (*arg) {
349 o = arg;
350 switch (getsubopt(&arg, UNCONST(toks), &v)) {
351 case (0):
352 curp->wstop = 1;
353 break;
354 case (1):
355 /* FALLTHROUGH */
356 case (2):
357 curp->wlevel = MANDOCLEVEL_WARNING;
358 break;
359 case (3):
360 curp->wlevel = MANDOCLEVEL_ERROR;
361 break;
362 case (4):
363 curp->wlevel = MANDOCLEVEL_FATAL;
364 break;
365 default:
366 fprintf(stderr, "-W%s: Bad argument\n", o);
367 return(0);
368 }
369 }
370
371 return(1);
372}
373
60e1e752
SW
374static void
375mmsg(enum mandocerr t, enum mandoclevel lvl,
376 const char *file, int line, int col, const char *msg)
80387638 377{
80387638 378
60e1e752
SW
379 fprintf(stderr, "%s:%d:%d: %s: %s",
380 file, line, col + 1,
381 mparse_strlevel(lvl),
382 mparse_strerror(t));
80387638 383
80387638
SW
384 if (msg)
385 fprintf(stderr, ": %s", msg);
80387638 386
60e1e752 387 fputc('\n', stderr);
80387638 388}