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