xref: /freebsd/contrib/mandoc/demandoc.c (revision 61d06d6bd19dafe8ea971dd43e8328fa1b473456)
1*61d06d6bSBaptiste Daroussin /*	$Id: demandoc.c,v 1.29 2017/06/24 14:38:32 schwarze Exp $ */
2*61d06d6bSBaptiste Daroussin /*
3*61d06d6bSBaptiste Daroussin  * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
4*61d06d6bSBaptiste Daroussin  *
5*61d06d6bSBaptiste Daroussin  * Permission to use, copy, modify, and distribute this software for any
6*61d06d6bSBaptiste Daroussin  * purpose with or without fee is hereby granted, provided that the above
7*61d06d6bSBaptiste Daroussin  * copyright notice and this permission notice appear in all copies.
8*61d06d6bSBaptiste Daroussin  *
9*61d06d6bSBaptiste Daroussin  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10*61d06d6bSBaptiste Daroussin  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11*61d06d6bSBaptiste Daroussin  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12*61d06d6bSBaptiste Daroussin  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13*61d06d6bSBaptiste Daroussin  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14*61d06d6bSBaptiste Daroussin  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15*61d06d6bSBaptiste Daroussin  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16*61d06d6bSBaptiste Daroussin  */
17*61d06d6bSBaptiste Daroussin #include "config.h"
18*61d06d6bSBaptiste Daroussin 
19*61d06d6bSBaptiste Daroussin #include <sys/types.h>
20*61d06d6bSBaptiste Daroussin 
21*61d06d6bSBaptiste Daroussin #include <assert.h>
22*61d06d6bSBaptiste Daroussin #include <ctype.h>
23*61d06d6bSBaptiste Daroussin #include <stdio.h>
24*61d06d6bSBaptiste Daroussin #include <stdlib.h>
25*61d06d6bSBaptiste Daroussin #include <string.h>
26*61d06d6bSBaptiste Daroussin #include <unistd.h>
27*61d06d6bSBaptiste Daroussin 
28*61d06d6bSBaptiste Daroussin #include "mandoc.h"
29*61d06d6bSBaptiste Daroussin #include "roff.h"
30*61d06d6bSBaptiste Daroussin #include "man.h"
31*61d06d6bSBaptiste Daroussin #include "mdoc.h"
32*61d06d6bSBaptiste Daroussin 
33*61d06d6bSBaptiste Daroussin static	void	 pline(int, int *, int *, int);
34*61d06d6bSBaptiste Daroussin static	void	 pman(const struct roff_node *, int *, int *, int);
35*61d06d6bSBaptiste Daroussin static	void	 pmandoc(struct mparse *, int, const char *, int);
36*61d06d6bSBaptiste Daroussin static	void	 pmdoc(const struct roff_node *, int *, int *, int);
37*61d06d6bSBaptiste Daroussin static	void	 pstring(const char *, int, int *, int);
38*61d06d6bSBaptiste Daroussin static	void	 usage(void);
39*61d06d6bSBaptiste Daroussin 
40*61d06d6bSBaptiste Daroussin static	const char	 *progname;
41*61d06d6bSBaptiste Daroussin 
42*61d06d6bSBaptiste Daroussin int
43*61d06d6bSBaptiste Daroussin main(int argc, char *argv[])
44*61d06d6bSBaptiste Daroussin {
45*61d06d6bSBaptiste Daroussin 	struct mparse	*mp;
46*61d06d6bSBaptiste Daroussin 	int		 ch, fd, i, list;
47*61d06d6bSBaptiste Daroussin 	extern int	 optind;
48*61d06d6bSBaptiste Daroussin 
49*61d06d6bSBaptiste Daroussin 	if (argc < 1)
50*61d06d6bSBaptiste Daroussin 		progname = "demandoc";
51*61d06d6bSBaptiste Daroussin 	else if ((progname = strrchr(argv[0], '/')) == NULL)
52*61d06d6bSBaptiste Daroussin 		progname = argv[0];
53*61d06d6bSBaptiste Daroussin 	else
54*61d06d6bSBaptiste Daroussin 		++progname;
55*61d06d6bSBaptiste Daroussin 
56*61d06d6bSBaptiste Daroussin 	mp = NULL;
57*61d06d6bSBaptiste Daroussin 	list = 0;
58*61d06d6bSBaptiste Daroussin 
59*61d06d6bSBaptiste Daroussin 	while (-1 != (ch = getopt(argc, argv, "ikm:pw")))
60*61d06d6bSBaptiste Daroussin 		switch (ch) {
61*61d06d6bSBaptiste Daroussin 		case ('i'):
62*61d06d6bSBaptiste Daroussin 			/* FALLTHROUGH */
63*61d06d6bSBaptiste Daroussin 		case ('k'):
64*61d06d6bSBaptiste Daroussin 			/* FALLTHROUGH */
65*61d06d6bSBaptiste Daroussin 		case ('m'):
66*61d06d6bSBaptiste Daroussin 			/* FALLTHROUGH */
67*61d06d6bSBaptiste Daroussin 		case ('p'):
68*61d06d6bSBaptiste Daroussin 			break;
69*61d06d6bSBaptiste Daroussin 		case ('w'):
70*61d06d6bSBaptiste Daroussin 			list = 1;
71*61d06d6bSBaptiste Daroussin 			break;
72*61d06d6bSBaptiste Daroussin 		default:
73*61d06d6bSBaptiste Daroussin 			usage();
74*61d06d6bSBaptiste Daroussin 			return (int)MANDOCLEVEL_BADARG;
75*61d06d6bSBaptiste Daroussin 		}
76*61d06d6bSBaptiste Daroussin 
77*61d06d6bSBaptiste Daroussin 	argc -= optind;
78*61d06d6bSBaptiste Daroussin 	argv += optind;
79*61d06d6bSBaptiste Daroussin 
80*61d06d6bSBaptiste Daroussin 	mchars_alloc();
81*61d06d6bSBaptiste Daroussin 	mp = mparse_alloc(MPARSE_SO, MANDOCERR_MAX, NULL,
82*61d06d6bSBaptiste Daroussin 	    MANDOC_OS_OTHER, NULL);
83*61d06d6bSBaptiste Daroussin 	assert(mp);
84*61d06d6bSBaptiste Daroussin 
85*61d06d6bSBaptiste Daroussin 	if (argc < 1)
86*61d06d6bSBaptiste Daroussin 		pmandoc(mp, STDIN_FILENO, "<stdin>", list);
87*61d06d6bSBaptiste Daroussin 
88*61d06d6bSBaptiste Daroussin 	for (i = 0; i < argc; i++) {
89*61d06d6bSBaptiste Daroussin 		mparse_reset(mp);
90*61d06d6bSBaptiste Daroussin 		if ((fd = mparse_open(mp, argv[i])) == -1) {
91*61d06d6bSBaptiste Daroussin 			perror(argv[i]);
92*61d06d6bSBaptiste Daroussin 			continue;
93*61d06d6bSBaptiste Daroussin 		}
94*61d06d6bSBaptiste Daroussin 		pmandoc(mp, fd, argv[i], list);
95*61d06d6bSBaptiste Daroussin 	}
96*61d06d6bSBaptiste Daroussin 
97*61d06d6bSBaptiste Daroussin 	mparse_free(mp);
98*61d06d6bSBaptiste Daroussin 	mchars_free();
99*61d06d6bSBaptiste Daroussin 	return (int)MANDOCLEVEL_OK;
100*61d06d6bSBaptiste Daroussin }
101*61d06d6bSBaptiste Daroussin 
102*61d06d6bSBaptiste Daroussin static void
103*61d06d6bSBaptiste Daroussin usage(void)
104*61d06d6bSBaptiste Daroussin {
105*61d06d6bSBaptiste Daroussin 
106*61d06d6bSBaptiste Daroussin 	fprintf(stderr, "usage: %s [-w] [files...]\n", progname);
107*61d06d6bSBaptiste Daroussin }
108*61d06d6bSBaptiste Daroussin 
109*61d06d6bSBaptiste Daroussin static void
110*61d06d6bSBaptiste Daroussin pmandoc(struct mparse *mp, int fd, const char *fn, int list)
111*61d06d6bSBaptiste Daroussin {
112*61d06d6bSBaptiste Daroussin 	struct roff_man	*man;
113*61d06d6bSBaptiste Daroussin 	int		 line, col;
114*61d06d6bSBaptiste Daroussin 
115*61d06d6bSBaptiste Daroussin 	mparse_readfd(mp, fd, fn);
116*61d06d6bSBaptiste Daroussin 	close(fd);
117*61d06d6bSBaptiste Daroussin 	mparse_result(mp, &man, NULL);
118*61d06d6bSBaptiste Daroussin 	line = 1;
119*61d06d6bSBaptiste Daroussin 	col = 0;
120*61d06d6bSBaptiste Daroussin 
121*61d06d6bSBaptiste Daroussin 	if (man == NULL)
122*61d06d6bSBaptiste Daroussin 		return;
123*61d06d6bSBaptiste Daroussin 	if (man->macroset == MACROSET_MDOC) {
124*61d06d6bSBaptiste Daroussin 		mdoc_validate(man);
125*61d06d6bSBaptiste Daroussin 		pmdoc(man->first->child, &line, &col, list);
126*61d06d6bSBaptiste Daroussin 	} else {
127*61d06d6bSBaptiste Daroussin 		man_validate(man);
128*61d06d6bSBaptiste Daroussin 		pman(man->first->child, &line, &col, list);
129*61d06d6bSBaptiste Daroussin 	}
130*61d06d6bSBaptiste Daroussin 
131*61d06d6bSBaptiste Daroussin 	if ( ! list)
132*61d06d6bSBaptiste Daroussin 		putchar('\n');
133*61d06d6bSBaptiste Daroussin }
134*61d06d6bSBaptiste Daroussin 
135*61d06d6bSBaptiste Daroussin /*
136*61d06d6bSBaptiste Daroussin  * Strip the escapes out of a string, emitting the results.
137*61d06d6bSBaptiste Daroussin  */
138*61d06d6bSBaptiste Daroussin static void
139*61d06d6bSBaptiste Daroussin pstring(const char *p, int col, int *colp, int list)
140*61d06d6bSBaptiste Daroussin {
141*61d06d6bSBaptiste Daroussin 	enum mandoc_esc	 esc;
142*61d06d6bSBaptiste Daroussin 	const char	*start, *end;
143*61d06d6bSBaptiste Daroussin 	int		 emit;
144*61d06d6bSBaptiste Daroussin 
145*61d06d6bSBaptiste Daroussin 	/*
146*61d06d6bSBaptiste Daroussin 	 * Print as many column spaces til we achieve parity with the
147*61d06d6bSBaptiste Daroussin 	 * input document.
148*61d06d6bSBaptiste Daroussin 	 */
149*61d06d6bSBaptiste Daroussin 
150*61d06d6bSBaptiste Daroussin again:
151*61d06d6bSBaptiste Daroussin 	if (list && '\0' != *p) {
152*61d06d6bSBaptiste Daroussin 		while (isspace((unsigned char)*p))
153*61d06d6bSBaptiste Daroussin 			p++;
154*61d06d6bSBaptiste Daroussin 
155*61d06d6bSBaptiste Daroussin 		while ('\'' == *p || '(' == *p || '"' == *p)
156*61d06d6bSBaptiste Daroussin 			p++;
157*61d06d6bSBaptiste Daroussin 
158*61d06d6bSBaptiste Daroussin 		emit = isalpha((unsigned char)p[0]) &&
159*61d06d6bSBaptiste Daroussin 			isalpha((unsigned char)p[1]);
160*61d06d6bSBaptiste Daroussin 
161*61d06d6bSBaptiste Daroussin 		for (start = p; '\0' != *p; p++)
162*61d06d6bSBaptiste Daroussin 			if ('\\' == *p) {
163*61d06d6bSBaptiste Daroussin 				p++;
164*61d06d6bSBaptiste Daroussin 				esc = mandoc_escape(&p, NULL, NULL);
165*61d06d6bSBaptiste Daroussin 				if (ESCAPE_ERROR == esc)
166*61d06d6bSBaptiste Daroussin 					return;
167*61d06d6bSBaptiste Daroussin 				emit = 0;
168*61d06d6bSBaptiste Daroussin 			} else if (isspace((unsigned char)*p))
169*61d06d6bSBaptiste Daroussin 				break;
170*61d06d6bSBaptiste Daroussin 
171*61d06d6bSBaptiste Daroussin 		end = p - 1;
172*61d06d6bSBaptiste Daroussin 
173*61d06d6bSBaptiste Daroussin 		while (end > start)
174*61d06d6bSBaptiste Daroussin 			if ('.' == *end || ',' == *end ||
175*61d06d6bSBaptiste Daroussin 					'\'' == *end || '"' == *end ||
176*61d06d6bSBaptiste Daroussin 					')' == *end || '!' == *end ||
177*61d06d6bSBaptiste Daroussin 					'?' == *end || ':' == *end ||
178*61d06d6bSBaptiste Daroussin 					';' == *end)
179*61d06d6bSBaptiste Daroussin 				end--;
180*61d06d6bSBaptiste Daroussin 			else
181*61d06d6bSBaptiste Daroussin 				break;
182*61d06d6bSBaptiste Daroussin 
183*61d06d6bSBaptiste Daroussin 		if (emit && end - start >= 1) {
184*61d06d6bSBaptiste Daroussin 			for ( ; start <= end; start++)
185*61d06d6bSBaptiste Daroussin 				if (ASCII_HYPH == *start)
186*61d06d6bSBaptiste Daroussin 					putchar('-');
187*61d06d6bSBaptiste Daroussin 				else
188*61d06d6bSBaptiste Daroussin 					putchar((unsigned char)*start);
189*61d06d6bSBaptiste Daroussin 			putchar('\n');
190*61d06d6bSBaptiste Daroussin 		}
191*61d06d6bSBaptiste Daroussin 
192*61d06d6bSBaptiste Daroussin 		if (isspace((unsigned char)*p))
193*61d06d6bSBaptiste Daroussin 			goto again;
194*61d06d6bSBaptiste Daroussin 
195*61d06d6bSBaptiste Daroussin 		return;
196*61d06d6bSBaptiste Daroussin 	}
197*61d06d6bSBaptiste Daroussin 
198*61d06d6bSBaptiste Daroussin 	while (*colp < col) {
199*61d06d6bSBaptiste Daroussin 		putchar(' ');
200*61d06d6bSBaptiste Daroussin 		(*colp)++;
201*61d06d6bSBaptiste Daroussin 	}
202*61d06d6bSBaptiste Daroussin 
203*61d06d6bSBaptiste Daroussin 	/*
204*61d06d6bSBaptiste Daroussin 	 * Print the input word, skipping any special characters.
205*61d06d6bSBaptiste Daroussin 	 */
206*61d06d6bSBaptiste Daroussin 	while ('\0' != *p)
207*61d06d6bSBaptiste Daroussin 		if ('\\' == *p) {
208*61d06d6bSBaptiste Daroussin 			p++;
209*61d06d6bSBaptiste Daroussin 			esc = mandoc_escape(&p, NULL, NULL);
210*61d06d6bSBaptiste Daroussin 			if (ESCAPE_ERROR == esc)
211*61d06d6bSBaptiste Daroussin 				break;
212*61d06d6bSBaptiste Daroussin 		} else {
213*61d06d6bSBaptiste Daroussin 			putchar((unsigned char )*p++);
214*61d06d6bSBaptiste Daroussin 			(*colp)++;
215*61d06d6bSBaptiste Daroussin 		}
216*61d06d6bSBaptiste Daroussin }
217*61d06d6bSBaptiste Daroussin 
218*61d06d6bSBaptiste Daroussin static void
219*61d06d6bSBaptiste Daroussin pline(int line, int *linep, int *col, int list)
220*61d06d6bSBaptiste Daroussin {
221*61d06d6bSBaptiste Daroussin 
222*61d06d6bSBaptiste Daroussin 	if (list)
223*61d06d6bSBaptiste Daroussin 		return;
224*61d06d6bSBaptiste Daroussin 
225*61d06d6bSBaptiste Daroussin 	/*
226*61d06d6bSBaptiste Daroussin 	 * Print out as many lines as needed to reach parity with the
227*61d06d6bSBaptiste Daroussin 	 * original input.
228*61d06d6bSBaptiste Daroussin 	 */
229*61d06d6bSBaptiste Daroussin 
230*61d06d6bSBaptiste Daroussin 	while (*linep < line) {
231*61d06d6bSBaptiste Daroussin 		putchar('\n');
232*61d06d6bSBaptiste Daroussin 		(*linep)++;
233*61d06d6bSBaptiste Daroussin 	}
234*61d06d6bSBaptiste Daroussin 
235*61d06d6bSBaptiste Daroussin 	*col = 0;
236*61d06d6bSBaptiste Daroussin }
237*61d06d6bSBaptiste Daroussin 
238*61d06d6bSBaptiste Daroussin static void
239*61d06d6bSBaptiste Daroussin pmdoc(const struct roff_node *p, int *line, int *col, int list)
240*61d06d6bSBaptiste Daroussin {
241*61d06d6bSBaptiste Daroussin 
242*61d06d6bSBaptiste Daroussin 	for ( ; p; p = p->next) {
243*61d06d6bSBaptiste Daroussin 		if (NODE_LINE & p->flags)
244*61d06d6bSBaptiste Daroussin 			pline(p->line, line, col, list);
245*61d06d6bSBaptiste Daroussin 		if (ROFFT_TEXT == p->type)
246*61d06d6bSBaptiste Daroussin 			pstring(p->string, p->pos, col, list);
247*61d06d6bSBaptiste Daroussin 		if (p->child)
248*61d06d6bSBaptiste Daroussin 			pmdoc(p->child, line, col, list);
249*61d06d6bSBaptiste Daroussin 	}
250*61d06d6bSBaptiste Daroussin }
251*61d06d6bSBaptiste Daroussin 
252*61d06d6bSBaptiste Daroussin static void
253*61d06d6bSBaptiste Daroussin pman(const struct roff_node *p, int *line, int *col, int list)
254*61d06d6bSBaptiste Daroussin {
255*61d06d6bSBaptiste Daroussin 
256*61d06d6bSBaptiste Daroussin 	for ( ; p; p = p->next) {
257*61d06d6bSBaptiste Daroussin 		if (NODE_LINE & p->flags)
258*61d06d6bSBaptiste Daroussin 			pline(p->line, line, col, list);
259*61d06d6bSBaptiste Daroussin 		if (ROFFT_TEXT == p->type)
260*61d06d6bSBaptiste Daroussin 			pstring(p->string, p->pos, col, list);
261*61d06d6bSBaptiste Daroussin 		if (p->child)
262*61d06d6bSBaptiste Daroussin 			pman(p->child, line, col, list);
263*61d06d6bSBaptiste Daroussin 	}
264*61d06d6bSBaptiste Daroussin }
265