1*0a6a1f1dSLionel Sambuc /* Id: main.c,v 1.167 2012/11/19 17:22:26 schwarze Exp */
2d65f6f70SBen Gras /*
3d65f6f70SBen Gras * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
4*0a6a1f1dSLionel Sambuc * Copyright (c) 2010, 2011, 2012 Ingo Schwarze <schwarze@openbsd.org>
5d65f6f70SBen Gras *
6d65f6f70SBen Gras * Permission to use, copy, modify, and distribute this software for any
7d65f6f70SBen Gras * purpose with or without fee is hereby granted, provided that the above
8d65f6f70SBen Gras * copyright notice and this permission notice appear in all copies.
9d65f6f70SBen Gras *
10d65f6f70SBen Gras * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11d65f6f70SBen Gras * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12d65f6f70SBen Gras * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13d65f6f70SBen Gras * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14d65f6f70SBen Gras * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15d65f6f70SBen Gras * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16d65f6f70SBen Gras * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17d65f6f70SBen Gras */
18d65f6f70SBen Gras #ifdef HAVE_CONFIG_H
19d65f6f70SBen Gras #include "config.h"
20d65f6f70SBen Gras #endif
21d65f6f70SBen Gras
22d65f6f70SBen Gras #include <assert.h>
23d65f6f70SBen Gras #include <stdio.h>
24d65f6f70SBen Gras #include <stdint.h>
25d65f6f70SBen Gras #include <stdlib.h>
26d65f6f70SBen Gras #include <string.h>
27d65f6f70SBen Gras #include <unistd.h>
28d65f6f70SBen Gras
29d65f6f70SBen Gras #include "mandoc.h"
30d65f6f70SBen Gras #include "main.h"
31d65f6f70SBen Gras #include "mdoc.h"
32d65f6f70SBen Gras #include "man.h"
33d65f6f70SBen Gras
34d65f6f70SBen Gras #if !defined(__GNUC__) || (__GNUC__ < 2)
35d65f6f70SBen Gras # if !defined(lint)
36d65f6f70SBen Gras # define __attribute__(x)
37d65f6f70SBen Gras # endif
38d65f6f70SBen Gras #endif /* !defined(__GNUC__) || (__GNUC__ < 2) */
39d65f6f70SBen Gras
40d65f6f70SBen Gras typedef void (*out_mdoc)(void *, const struct mdoc *);
41d65f6f70SBen Gras typedef void (*out_man)(void *, const struct man *);
42d65f6f70SBen Gras typedef void (*out_free)(void *);
43d65f6f70SBen Gras
44d65f6f70SBen Gras enum outt {
4592395e9cSLionel Sambuc OUTT_ASCII = 0, /* -Tascii */
4692395e9cSLionel Sambuc OUTT_LOCALE, /* -Tlocale */
4792395e9cSLionel Sambuc OUTT_UTF8, /* -Tutf8 */
4892395e9cSLionel Sambuc OUTT_TREE, /* -Ttree */
4992395e9cSLionel Sambuc OUTT_MAN, /* -Tman */
5092395e9cSLionel Sambuc OUTT_HTML, /* -Thtml */
5192395e9cSLionel Sambuc OUTT_XHTML, /* -Txhtml */
5292395e9cSLionel Sambuc OUTT_LINT, /* -Tlint */
5392395e9cSLionel Sambuc OUTT_PS, /* -Tps */
5492395e9cSLionel Sambuc OUTT_PDF /* -Tpdf */
55d65f6f70SBen Gras };
56d65f6f70SBen Gras
57d65f6f70SBen Gras struct curparse {
5892395e9cSLionel Sambuc struct mparse *mp;
5992395e9cSLionel Sambuc enum mandoclevel wlevel; /* ignore messages below this */
6092395e9cSLionel Sambuc int wstop; /* stop after a file with a warning */
61d65f6f70SBen Gras enum outt outtype; /* which output to use */
62d65f6f70SBen Gras out_mdoc outmdoc; /* mdoc output ptr */
63d65f6f70SBen Gras out_man outman; /* man output ptr */
64d65f6f70SBen Gras out_free outfree; /* free output ptr */
65d65f6f70SBen Gras void *outdata; /* data for output */
66d65f6f70SBen Gras char outopts[BUFSIZ]; /* buf of output opts */
67d65f6f70SBen Gras };
68d65f6f70SBen Gras
6992395e9cSLionel Sambuc static int moptions(enum mparset *, char *);
7092395e9cSLionel Sambuc static void mmsg(enum mandocerr, enum mandoclevel,
7192395e9cSLionel Sambuc const char *, int, int, const char *);
7292395e9cSLionel Sambuc static void parse(struct curparse *, int,
7392395e9cSLionel Sambuc const char *, enum mandoclevel *);
74d65f6f70SBen Gras static int toptions(struct curparse *, char *);
75d65f6f70SBen Gras static void usage(void) __attribute__((noreturn));
76d65f6f70SBen Gras static void version(void) __attribute__((noreturn));
77d65f6f70SBen Gras static int woptions(struct curparse *, char *);
78d65f6f70SBen Gras
79d65f6f70SBen Gras static const char *progname;
80d65f6f70SBen Gras
81d65f6f70SBen Gras int
main(int argc,char * argv[])82d65f6f70SBen Gras main(int argc, char *argv[])
83d65f6f70SBen Gras {
84d65f6f70SBen Gras int c;
85d65f6f70SBen Gras struct curparse curp;
8692395e9cSLionel Sambuc enum mparset type;
8792395e9cSLionel Sambuc enum mandoclevel rc;
88*0a6a1f1dSLionel Sambuc char *defos;
89d65f6f70SBen Gras
90d65f6f70SBen Gras progname = strrchr(argv[0], '/');
91d65f6f70SBen Gras if (progname == NULL)
92d65f6f70SBen Gras progname = argv[0];
93d65f6f70SBen Gras else
94d65f6f70SBen Gras ++progname;
95d65f6f70SBen Gras
96d65f6f70SBen Gras memset(&curp, 0, sizeof(struct curparse));
97d65f6f70SBen Gras
9892395e9cSLionel Sambuc type = MPARSE_AUTO;
99d65f6f70SBen Gras curp.outtype = OUTT_ASCII;
100d65f6f70SBen Gras curp.wlevel = MANDOCLEVEL_FATAL;
101*0a6a1f1dSLionel Sambuc defos = NULL;
102d65f6f70SBen Gras
103d65f6f70SBen Gras /* LINTED */
104*0a6a1f1dSLionel Sambuc while (-1 != (c = getopt(argc, argv, "I:m:O:T:VW:")))
105d65f6f70SBen Gras switch (c) {
106*0a6a1f1dSLionel Sambuc case ('I'):
107*0a6a1f1dSLionel Sambuc if (strncmp(optarg, "os=", 3)) {
108*0a6a1f1dSLionel Sambuc fprintf(stderr, "-I%s: Bad argument\n",
109*0a6a1f1dSLionel Sambuc optarg);
110*0a6a1f1dSLionel Sambuc return((int)MANDOCLEVEL_BADARG);
111*0a6a1f1dSLionel Sambuc }
112*0a6a1f1dSLionel Sambuc if (defos) {
113*0a6a1f1dSLionel Sambuc fprintf(stderr, "-I%s: Duplicate argument\n",
114*0a6a1f1dSLionel Sambuc optarg);
115*0a6a1f1dSLionel Sambuc return((int)MANDOCLEVEL_BADARG);
116*0a6a1f1dSLionel Sambuc }
117*0a6a1f1dSLionel Sambuc defos = mandoc_strdup(optarg + 3);
118*0a6a1f1dSLionel Sambuc break;
119d65f6f70SBen Gras case ('m'):
12092395e9cSLionel Sambuc if ( ! moptions(&type, optarg))
121d65f6f70SBen Gras return((int)MANDOCLEVEL_BADARG);
122d65f6f70SBen Gras break;
123d65f6f70SBen Gras case ('O'):
124d65f6f70SBen Gras (void)strlcat(curp.outopts, optarg, BUFSIZ);
125d65f6f70SBen Gras (void)strlcat(curp.outopts, ",", BUFSIZ);
126d65f6f70SBen Gras break;
127d65f6f70SBen Gras case ('T'):
128d65f6f70SBen Gras if ( ! toptions(&curp, optarg))
129d65f6f70SBen Gras return((int)MANDOCLEVEL_BADARG);
130d65f6f70SBen Gras break;
131d65f6f70SBen Gras case ('W'):
132d65f6f70SBen Gras if ( ! woptions(&curp, optarg))
133d65f6f70SBen Gras return((int)MANDOCLEVEL_BADARG);
134d65f6f70SBen Gras break;
135d65f6f70SBen Gras case ('V'):
136d65f6f70SBen Gras version();
137d65f6f70SBen Gras /* NOTREACHED */
138d65f6f70SBen Gras default:
139d65f6f70SBen Gras usage();
140d65f6f70SBen Gras /* NOTREACHED */
141d65f6f70SBen Gras }
142d65f6f70SBen Gras
143*0a6a1f1dSLionel Sambuc curp.mp = mparse_alloc(type, curp.wlevel, mmsg, &curp, defos);
14492395e9cSLionel Sambuc
14592395e9cSLionel Sambuc /*
14692395e9cSLionel Sambuc * Conditionally start up the lookaside buffer before parsing.
14792395e9cSLionel Sambuc */
14892395e9cSLionel Sambuc if (OUTT_MAN == curp.outtype)
14992395e9cSLionel Sambuc mparse_keep(curp.mp);
15092395e9cSLionel Sambuc
151d65f6f70SBen Gras argc -= optind;
152d65f6f70SBen Gras argv += optind;
153d65f6f70SBen Gras
15492395e9cSLionel Sambuc rc = MANDOCLEVEL_OK;
155d65f6f70SBen Gras
15692395e9cSLionel Sambuc if (NULL == *argv)
15792395e9cSLionel Sambuc parse(&curp, STDIN_FILENO, "<stdin>", &rc);
158d65f6f70SBen Gras
159d65f6f70SBen Gras while (*argv) {
16092395e9cSLionel Sambuc parse(&curp, -1, *argv, &rc);
16192395e9cSLionel Sambuc if (MANDOCLEVEL_OK != rc && curp.wstop)
162d65f6f70SBen Gras break;
163d65f6f70SBen Gras ++argv;
164d65f6f70SBen Gras }
165d65f6f70SBen Gras
166d65f6f70SBen Gras if (curp.outfree)
167d65f6f70SBen Gras (*curp.outfree)(curp.outdata);
16892395e9cSLionel Sambuc if (curp.mp)
16992395e9cSLionel Sambuc mparse_free(curp.mp);
170*0a6a1f1dSLionel Sambuc free(defos);
171d65f6f70SBen Gras
17292395e9cSLionel Sambuc return((int)rc);
173d65f6f70SBen Gras }
174d65f6f70SBen Gras
175d65f6f70SBen Gras static void
version(void)176d65f6f70SBen Gras version(void)
177d65f6f70SBen Gras {
178d65f6f70SBen Gras
17992395e9cSLionel Sambuc printf("%s %s\n", progname, VERSION);
180d65f6f70SBen Gras exit((int)MANDOCLEVEL_OK);
181d65f6f70SBen Gras }
182d65f6f70SBen Gras
183d65f6f70SBen Gras static void
usage(void)184d65f6f70SBen Gras usage(void)
185d65f6f70SBen Gras {
186d65f6f70SBen Gras
18792395e9cSLionel Sambuc fprintf(stderr, "usage: %s "
188d65f6f70SBen Gras "[-V] "
189*0a6a1f1dSLionel Sambuc "[-Ios=name] "
190d65f6f70SBen Gras "[-mformat] "
191d65f6f70SBen Gras "[-Ooption] "
192d65f6f70SBen Gras "[-Toutput] "
193*0a6a1f1dSLionel Sambuc "[-Wlevel]\n"
194*0a6a1f1dSLionel Sambuc "\t [file ...]\n",
195d65f6f70SBen Gras progname);
196d65f6f70SBen Gras
197d65f6f70SBen Gras exit((int)MANDOCLEVEL_BADARG);
198d65f6f70SBen Gras }
199d65f6f70SBen Gras
200d65f6f70SBen Gras static void
parse(struct curparse * curp,int fd,const char * file,enum mandoclevel * level)20192395e9cSLionel Sambuc parse(struct curparse *curp, int fd,
20292395e9cSLionel Sambuc const char *file, enum mandoclevel *level)
203d65f6f70SBen Gras {
20492395e9cSLionel Sambuc enum mandoclevel rc;
20592395e9cSLionel Sambuc struct mdoc *mdoc;
20692395e9cSLionel Sambuc struct man *man;
207d65f6f70SBen Gras
20892395e9cSLionel Sambuc /* Begin by parsing the file itself. */
209d65f6f70SBen Gras
21092395e9cSLionel Sambuc assert(file);
21192395e9cSLionel Sambuc assert(fd >= -1);
212d65f6f70SBen Gras
21392395e9cSLionel Sambuc rc = mparse_readfd(curp->mp, fd, file);
214d65f6f70SBen Gras
21592395e9cSLionel Sambuc /* Stop immediately if the parse has failed. */
216d65f6f70SBen Gras
21792395e9cSLionel Sambuc if (MANDOCLEVEL_FATAL <= rc)
218d65f6f70SBen Gras goto cleanup;
219d65f6f70SBen Gras
220d65f6f70SBen Gras /*
22192395e9cSLionel Sambuc * With -Wstop and warnings or errors of at least the requested
22292395e9cSLionel Sambuc * level, do not produce output.
223d65f6f70SBen Gras */
224d65f6f70SBen Gras
22592395e9cSLionel Sambuc if (MANDOCLEVEL_OK != rc && curp->wstop)
226d65f6f70SBen Gras goto cleanup;
227d65f6f70SBen Gras
228d65f6f70SBen Gras /* If unset, allocate output dev now (if applicable). */
229d65f6f70SBen Gras
230d65f6f70SBen Gras if ( ! (curp->outman && curp->outmdoc)) {
231d65f6f70SBen Gras switch (curp->outtype) {
232d65f6f70SBen Gras case (OUTT_XHTML):
233d65f6f70SBen Gras curp->outdata = xhtml_alloc(curp->outopts);
23492395e9cSLionel Sambuc curp->outfree = html_free;
235d65f6f70SBen Gras break;
236d65f6f70SBen Gras case (OUTT_HTML):
237d65f6f70SBen Gras curp->outdata = html_alloc(curp->outopts);
23892395e9cSLionel Sambuc curp->outfree = html_free;
23992395e9cSLionel Sambuc break;
24092395e9cSLionel Sambuc case (OUTT_UTF8):
24192395e9cSLionel Sambuc curp->outdata = utf8_alloc(curp->outopts);
24292395e9cSLionel Sambuc curp->outfree = ascii_free;
24392395e9cSLionel Sambuc break;
24492395e9cSLionel Sambuc case (OUTT_LOCALE):
24592395e9cSLionel Sambuc curp->outdata = locale_alloc(curp->outopts);
24692395e9cSLionel Sambuc curp->outfree = ascii_free;
247d65f6f70SBen Gras break;
248d65f6f70SBen Gras case (OUTT_ASCII):
249d65f6f70SBen Gras curp->outdata = ascii_alloc(curp->outopts);
250d65f6f70SBen Gras curp->outfree = ascii_free;
251d65f6f70SBen Gras break;
252d65f6f70SBen Gras case (OUTT_PDF):
253d65f6f70SBen Gras curp->outdata = pdf_alloc(curp->outopts);
254d65f6f70SBen Gras curp->outfree = pspdf_free;
255d65f6f70SBen Gras break;
256d65f6f70SBen Gras case (OUTT_PS):
257d65f6f70SBen Gras curp->outdata = ps_alloc(curp->outopts);
258d65f6f70SBen Gras curp->outfree = pspdf_free;
259d65f6f70SBen Gras break;
260d65f6f70SBen Gras default:
261d65f6f70SBen Gras break;
262d65f6f70SBen Gras }
263d65f6f70SBen Gras
264d65f6f70SBen Gras switch (curp->outtype) {
265d65f6f70SBen Gras case (OUTT_HTML):
266d65f6f70SBen Gras /* FALLTHROUGH */
267d65f6f70SBen Gras case (OUTT_XHTML):
268d65f6f70SBen Gras curp->outman = html_man;
269d65f6f70SBen Gras curp->outmdoc = html_mdoc;
270d65f6f70SBen Gras break;
271d65f6f70SBen Gras case (OUTT_TREE):
272d65f6f70SBen Gras curp->outman = tree_man;
273d65f6f70SBen Gras curp->outmdoc = tree_mdoc;
274d65f6f70SBen Gras break;
27592395e9cSLionel Sambuc case (OUTT_MAN):
27692395e9cSLionel Sambuc curp->outmdoc = man_mdoc;
27792395e9cSLionel Sambuc curp->outman = man_man;
27892395e9cSLionel Sambuc break;
279d65f6f70SBen Gras case (OUTT_PDF):
280d65f6f70SBen Gras /* FALLTHROUGH */
281d65f6f70SBen Gras case (OUTT_ASCII):
282d65f6f70SBen Gras /* FALLTHROUGH */
28392395e9cSLionel Sambuc case (OUTT_UTF8):
28492395e9cSLionel Sambuc /* FALLTHROUGH */
28592395e9cSLionel Sambuc case (OUTT_LOCALE):
28692395e9cSLionel Sambuc /* FALLTHROUGH */
287d65f6f70SBen Gras case (OUTT_PS):
288d65f6f70SBen Gras curp->outman = terminal_man;
289d65f6f70SBen Gras curp->outmdoc = terminal_mdoc;
290d65f6f70SBen Gras break;
291d65f6f70SBen Gras default:
292d65f6f70SBen Gras break;
293d65f6f70SBen Gras }
294d65f6f70SBen Gras }
295d65f6f70SBen Gras
29692395e9cSLionel Sambuc mparse_result(curp->mp, &mdoc, &man);
29792395e9cSLionel Sambuc
298d65f6f70SBen Gras /* Execute the out device, if it exists. */
299d65f6f70SBen Gras
30092395e9cSLionel Sambuc if (man && curp->outman)
30192395e9cSLionel Sambuc (*curp->outman)(curp->outdata, man);
30292395e9cSLionel Sambuc if (mdoc && curp->outmdoc)
30392395e9cSLionel Sambuc (*curp->outmdoc)(curp->outdata, mdoc);
304d65f6f70SBen Gras
305d65f6f70SBen Gras cleanup:
306d65f6f70SBen Gras
30792395e9cSLionel Sambuc mparse_reset(curp->mp);
308d65f6f70SBen Gras
30992395e9cSLionel Sambuc if (*level < rc)
31092395e9cSLionel Sambuc *level = rc;
311d65f6f70SBen Gras }
312d65f6f70SBen Gras
313d65f6f70SBen Gras static int
moptions(enum mparset * tflags,char * arg)31492395e9cSLionel Sambuc moptions(enum mparset *tflags, char *arg)
315d65f6f70SBen Gras {
316d65f6f70SBen Gras
317d65f6f70SBen Gras if (0 == strcmp(arg, "doc"))
31892395e9cSLionel Sambuc *tflags = MPARSE_MDOC;
319d65f6f70SBen Gras else if (0 == strcmp(arg, "andoc"))
32092395e9cSLionel Sambuc *tflags = MPARSE_AUTO;
321d65f6f70SBen Gras else if (0 == strcmp(arg, "an"))
32292395e9cSLionel Sambuc *tflags = MPARSE_MAN;
323d65f6f70SBen Gras else {
324d65f6f70SBen Gras fprintf(stderr, "%s: Bad argument\n", arg);
325d65f6f70SBen Gras return(0);
326d65f6f70SBen Gras }
327d65f6f70SBen Gras
328d65f6f70SBen Gras return(1);
329d65f6f70SBen Gras }
330d65f6f70SBen Gras
331d65f6f70SBen Gras static int
toptions(struct curparse * curp,char * arg)332d65f6f70SBen Gras toptions(struct curparse *curp, char *arg)
333d65f6f70SBen Gras {
334d65f6f70SBen Gras
335d65f6f70SBen Gras if (0 == strcmp(arg, "ascii"))
336d65f6f70SBen Gras curp->outtype = OUTT_ASCII;
337d65f6f70SBen Gras else if (0 == strcmp(arg, "lint")) {
338d65f6f70SBen Gras curp->outtype = OUTT_LINT;
339d65f6f70SBen Gras curp->wlevel = MANDOCLEVEL_WARNING;
34092395e9cSLionel Sambuc } else if (0 == strcmp(arg, "tree"))
341d65f6f70SBen Gras curp->outtype = OUTT_TREE;
34292395e9cSLionel Sambuc else if (0 == strcmp(arg, "man"))
34392395e9cSLionel Sambuc curp->outtype = OUTT_MAN;
344d65f6f70SBen Gras else if (0 == strcmp(arg, "html"))
345d65f6f70SBen Gras curp->outtype = OUTT_HTML;
34692395e9cSLionel Sambuc else if (0 == strcmp(arg, "utf8"))
34792395e9cSLionel Sambuc curp->outtype = OUTT_UTF8;
34892395e9cSLionel Sambuc else if (0 == strcmp(arg, "locale"))
34992395e9cSLionel Sambuc curp->outtype = OUTT_LOCALE;
350d65f6f70SBen Gras else if (0 == strcmp(arg, "xhtml"))
351d65f6f70SBen Gras curp->outtype = OUTT_XHTML;
352d65f6f70SBen Gras else if (0 == strcmp(arg, "ps"))
353d65f6f70SBen Gras curp->outtype = OUTT_PS;
354d65f6f70SBen Gras else if (0 == strcmp(arg, "pdf"))
355d65f6f70SBen Gras curp->outtype = OUTT_PDF;
356d65f6f70SBen Gras else {
357d65f6f70SBen Gras fprintf(stderr, "%s: Bad argument\n", arg);
358d65f6f70SBen Gras return(0);
359d65f6f70SBen Gras }
360d65f6f70SBen Gras
361d65f6f70SBen Gras return(1);
362d65f6f70SBen Gras }
363d65f6f70SBen Gras
364d65f6f70SBen Gras static int
woptions(struct curparse * curp,char * arg)365d65f6f70SBen Gras woptions(struct curparse *curp, char *arg)
366d65f6f70SBen Gras {
367d65f6f70SBen Gras char *v, *o;
368d65f6f70SBen Gras const char *toks[6];
369d65f6f70SBen Gras
370d65f6f70SBen Gras toks[0] = "stop";
371d65f6f70SBen Gras toks[1] = "all";
372d65f6f70SBen Gras toks[2] = "warning";
373d65f6f70SBen Gras toks[3] = "error";
374d65f6f70SBen Gras toks[4] = "fatal";
375d65f6f70SBen Gras toks[5] = NULL;
376d65f6f70SBen Gras
377d65f6f70SBen Gras while (*arg) {
378d65f6f70SBen Gras o = arg;
379d65f6f70SBen Gras switch (getsubopt(&arg, UNCONST(toks), &v)) {
380d65f6f70SBen Gras case (0):
381d65f6f70SBen Gras curp->wstop = 1;
382d65f6f70SBen Gras break;
383d65f6f70SBen Gras case (1):
384d65f6f70SBen Gras /* FALLTHROUGH */
385d65f6f70SBen Gras case (2):
386d65f6f70SBen Gras curp->wlevel = MANDOCLEVEL_WARNING;
387d65f6f70SBen Gras break;
388d65f6f70SBen Gras case (3):
389d65f6f70SBen Gras curp->wlevel = MANDOCLEVEL_ERROR;
390d65f6f70SBen Gras break;
391d65f6f70SBen Gras case (4):
392d65f6f70SBen Gras curp->wlevel = MANDOCLEVEL_FATAL;
393d65f6f70SBen Gras break;
394d65f6f70SBen Gras default:
395d65f6f70SBen Gras fprintf(stderr, "-W%s: Bad argument\n", o);
396d65f6f70SBen Gras return(0);
397d65f6f70SBen Gras }
398d65f6f70SBen Gras }
399d65f6f70SBen Gras
400d65f6f70SBen Gras return(1);
401d65f6f70SBen Gras }
402d65f6f70SBen Gras
40392395e9cSLionel Sambuc static void
mmsg(enum mandocerr t,enum mandoclevel lvl,const char * file,int line,int col,const char * msg)40492395e9cSLionel Sambuc mmsg(enum mandocerr t, enum mandoclevel lvl,
40592395e9cSLionel Sambuc const char *file, int line, int col, const char *msg)
406d65f6f70SBen Gras {
407d65f6f70SBen Gras
408d65f6f70SBen Gras fprintf(stderr, "%s:%d:%d: %s: %s",
40992395e9cSLionel Sambuc file, line, col + 1,
41092395e9cSLionel Sambuc mparse_strlevel(lvl),
41192395e9cSLionel Sambuc mparse_strerror(t));
41292395e9cSLionel Sambuc
413d65f6f70SBen Gras if (msg)
414d65f6f70SBen Gras fprintf(stderr, ": %s", msg);
41592395e9cSLionel Sambuc
416d65f6f70SBen Gras fputc('\n', stderr);
417d65f6f70SBen Gras }
418