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