xref: /dflybsd-src/contrib/mdocml/demandoc.c (revision 54ba96075f5891e4574304da6ba88f1a1afe520b)
1*54ba9607SSascha Wildner /*	$Id: demandoc.c,v 1.33 2019/03/03 11:01:15 schwarze Exp $ */
236342e81SSascha Wildner /*
336342e81SSascha Wildner  * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
436342e81SSascha Wildner  *
536342e81SSascha Wildner  * Permission to use, copy, modify, and distribute this software for any
636342e81SSascha Wildner  * purpose with or without fee is hereby granted, provided that the above
736342e81SSascha Wildner  * copyright notice and this permission notice appear in all copies.
836342e81SSascha Wildner  *
936342e81SSascha Wildner  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1036342e81SSascha Wildner  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1136342e81SSascha Wildner  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1236342e81SSascha Wildner  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1336342e81SSascha Wildner  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1436342e81SSascha Wildner  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1536342e81SSascha Wildner  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1636342e81SSascha Wildner  */
1736342e81SSascha Wildner #include "config.h"
18*54ba9607SSascha Wildner 
19*54ba9607SSascha Wildner #include <sys/types.h>
2036342e81SSascha Wildner 
2136342e81SSascha Wildner #include <assert.h>
2236342e81SSascha Wildner #include <ctype.h>
2336342e81SSascha Wildner #include <stdio.h>
2436342e81SSascha Wildner #include <stdlib.h>
2536342e81SSascha Wildner #include <string.h>
2636342e81SSascha Wildner #include <unistd.h>
2736342e81SSascha Wildner 
28*54ba9607SSascha Wildner #include "mandoc.h"
29*54ba9607SSascha Wildner #include "roff.h"
3036342e81SSascha Wildner #include "man.h"
3136342e81SSascha Wildner #include "mdoc.h"
32*54ba9607SSascha Wildner #include "mandoc_parse.h"
3336342e81SSascha Wildner 
3436342e81SSascha Wildner static	void	 pline(int, int *, int *, int);
35*54ba9607SSascha Wildner static	void	 pman(const struct roff_node *, int *, int *, int);
3636342e81SSascha Wildner static	void	 pmandoc(struct mparse *, int, const char *, int);
37*54ba9607SSascha Wildner static	void	 pmdoc(const struct roff_node *, int *, int *, int);
3836342e81SSascha Wildner static	void	 pstring(const char *, int, int *, int);
3936342e81SSascha Wildner static	void	 usage(void);
4036342e81SSascha Wildner 
4136342e81SSascha Wildner static	const char	 *progname;
4236342e81SSascha Wildner 
4336342e81SSascha Wildner int
main(int argc,char * argv[])4436342e81SSascha Wildner main(int argc, char *argv[])
4536342e81SSascha Wildner {
4636342e81SSascha Wildner 	struct mparse	*mp;
47*54ba9607SSascha Wildner 	int		 ch, fd, i, list;
4836342e81SSascha Wildner 	extern int	 optind;
4936342e81SSascha Wildner 
50*54ba9607SSascha Wildner 	if (argc < 1)
51*54ba9607SSascha Wildner 		progname = "demandoc";
52*54ba9607SSascha Wildner 	else if ((progname = strrchr(argv[0], '/')) == NULL)
5336342e81SSascha Wildner 		progname = argv[0];
5436342e81SSascha Wildner 	else
5536342e81SSascha Wildner 		++progname;
5636342e81SSascha Wildner 
5736342e81SSascha Wildner 	mp = NULL;
5836342e81SSascha Wildner 	list = 0;
5936342e81SSascha Wildner 
6036342e81SSascha Wildner 	while (-1 != (ch = getopt(argc, argv, "ikm:pw")))
6136342e81SSascha Wildner 		switch (ch) {
6236342e81SSascha Wildner 		case ('i'):
6336342e81SSascha Wildner 			/* FALLTHROUGH */
6436342e81SSascha Wildner 		case ('k'):
6536342e81SSascha Wildner 			/* FALLTHROUGH */
6636342e81SSascha Wildner 		case ('m'):
6736342e81SSascha Wildner 			/* FALLTHROUGH */
6836342e81SSascha Wildner 		case ('p'):
6936342e81SSascha Wildner 			break;
7036342e81SSascha Wildner 		case ('w'):
7136342e81SSascha Wildner 			list = 1;
7236342e81SSascha Wildner 			break;
7336342e81SSascha Wildner 		default:
7436342e81SSascha Wildner 			usage();
75*54ba9607SSascha Wildner 			return (int)MANDOCLEVEL_BADARG;
7636342e81SSascha Wildner 		}
7736342e81SSascha Wildner 
7836342e81SSascha Wildner 	argc -= optind;
7936342e81SSascha Wildner 	argv += optind;
8036342e81SSascha Wildner 
81*54ba9607SSascha Wildner 	mchars_alloc();
82*54ba9607SSascha Wildner 	mp = mparse_alloc(MPARSE_SO | MPARSE_UTF8 | MPARSE_LATIN1 |
83*54ba9607SSascha Wildner 	    MPARSE_VALIDATE, MANDOC_OS_OTHER, NULL);
8436342e81SSascha Wildner 	assert(mp);
8536342e81SSascha Wildner 
86*54ba9607SSascha Wildner 	if (argc < 1)
8736342e81SSascha Wildner 		pmandoc(mp, STDIN_FILENO, "<stdin>", list);
8836342e81SSascha Wildner 
8936342e81SSascha Wildner 	for (i = 0; i < argc; i++) {
9036342e81SSascha Wildner 		mparse_reset(mp);
91*54ba9607SSascha Wildner 		if ((fd = mparse_open(mp, argv[i])) == -1) {
92*54ba9607SSascha Wildner 			perror(argv[i]);
93*54ba9607SSascha Wildner 			continue;
94*54ba9607SSascha Wildner 		}
95*54ba9607SSascha Wildner 		pmandoc(mp, fd, argv[i], list);
9636342e81SSascha Wildner 	}
9736342e81SSascha Wildner 
9836342e81SSascha Wildner 	mparse_free(mp);
99*54ba9607SSascha Wildner 	mchars_free();
100*54ba9607SSascha Wildner 	return (int)MANDOCLEVEL_OK;
10136342e81SSascha Wildner }
10236342e81SSascha Wildner 
10336342e81SSascha Wildner static void
usage(void)10436342e81SSascha Wildner usage(void)
10536342e81SSascha Wildner {
10636342e81SSascha Wildner 
10736342e81SSascha Wildner 	fprintf(stderr, "usage: %s [-w] [files...]\n", progname);
10836342e81SSascha Wildner }
10936342e81SSascha Wildner 
11036342e81SSascha Wildner static void
pmandoc(struct mparse * mp,int fd,const char * fn,int list)11136342e81SSascha Wildner pmandoc(struct mparse *mp, int fd, const char *fn, int list)
11236342e81SSascha Wildner {
113*54ba9607SSascha Wildner 	struct roff_meta	*meta;
11436342e81SSascha Wildner 	int		 line, col;
11536342e81SSascha Wildner 
116*54ba9607SSascha Wildner 	mparse_readfd(mp, fd, fn);
117*54ba9607SSascha Wildner 	close(fd);
118*54ba9607SSascha Wildner 	meta = mparse_result(mp);
11936342e81SSascha Wildner 	line = 1;
12036342e81SSascha Wildner 	col = 0;
12136342e81SSascha Wildner 
122*54ba9607SSascha Wildner 	if (meta->macroset == MACROSET_MDOC)
123*54ba9607SSascha Wildner 		pmdoc(meta->first->child, &line, &col, list);
12436342e81SSascha Wildner 	else
125*54ba9607SSascha Wildner 		pman(meta->first->child, &line, &col, list);
12636342e81SSascha Wildner 
12736342e81SSascha Wildner 	if ( ! list)
12836342e81SSascha Wildner 		putchar('\n');
12936342e81SSascha Wildner }
13036342e81SSascha Wildner 
13136342e81SSascha Wildner /*
13236342e81SSascha Wildner  * Strip the escapes out of a string, emitting the results.
13336342e81SSascha Wildner  */
13436342e81SSascha Wildner static void
pstring(const char * p,int col,int * colp,int list)13536342e81SSascha Wildner pstring(const char *p, int col, int *colp, int list)
13636342e81SSascha Wildner {
13736342e81SSascha Wildner 	enum mandoc_esc	 esc;
13836342e81SSascha Wildner 	const char	*start, *end;
13936342e81SSascha Wildner 	int		 emit;
14036342e81SSascha Wildner 
14136342e81SSascha Wildner 	/*
14236342e81SSascha Wildner 	 * Print as many column spaces til we achieve parity with the
14336342e81SSascha Wildner 	 * input document.
14436342e81SSascha Wildner 	 */
14536342e81SSascha Wildner 
14636342e81SSascha Wildner again:
14736342e81SSascha Wildner 	if (list && '\0' != *p) {
14836342e81SSascha Wildner 		while (isspace((unsigned char)*p))
14936342e81SSascha Wildner 			p++;
15036342e81SSascha Wildner 
15136342e81SSascha Wildner 		while ('\'' == *p || '(' == *p || '"' == *p)
15236342e81SSascha Wildner 			p++;
15336342e81SSascha Wildner 
15436342e81SSascha Wildner 		emit = isalpha((unsigned char)p[0]) &&
15536342e81SSascha Wildner 			isalpha((unsigned char)p[1]);
15636342e81SSascha Wildner 
15736342e81SSascha Wildner 		for (start = p; '\0' != *p; p++)
15836342e81SSascha Wildner 			if ('\\' == *p) {
15936342e81SSascha Wildner 				p++;
16036342e81SSascha Wildner 				esc = mandoc_escape(&p, NULL, NULL);
16136342e81SSascha Wildner 				if (ESCAPE_ERROR == esc)
16236342e81SSascha Wildner 					return;
16336342e81SSascha Wildner 				emit = 0;
16436342e81SSascha Wildner 			} else if (isspace((unsigned char)*p))
16536342e81SSascha Wildner 				break;
16636342e81SSascha Wildner 
16736342e81SSascha Wildner 		end = p - 1;
16836342e81SSascha Wildner 
16936342e81SSascha Wildner 		while (end > start)
17036342e81SSascha Wildner 			if ('.' == *end || ',' == *end ||
17136342e81SSascha Wildner 					'\'' == *end || '"' == *end ||
17236342e81SSascha Wildner 					')' == *end || '!' == *end ||
17336342e81SSascha Wildner 					'?' == *end || ':' == *end ||
17436342e81SSascha Wildner 					';' == *end)
17536342e81SSascha Wildner 				end--;
17636342e81SSascha Wildner 			else
17736342e81SSascha Wildner 				break;
17836342e81SSascha Wildner 
17936342e81SSascha Wildner 		if (emit && end - start >= 1) {
18036342e81SSascha Wildner 			for ( ; start <= end; start++)
18136342e81SSascha Wildner 				if (ASCII_HYPH == *start)
18236342e81SSascha Wildner 					putchar('-');
18336342e81SSascha Wildner 				else
18436342e81SSascha Wildner 					putchar((unsigned char)*start);
18536342e81SSascha Wildner 			putchar('\n');
18636342e81SSascha Wildner 		}
18736342e81SSascha Wildner 
18836342e81SSascha Wildner 		if (isspace((unsigned char)*p))
18936342e81SSascha Wildner 			goto again;
19036342e81SSascha Wildner 
19136342e81SSascha Wildner 		return;
19236342e81SSascha Wildner 	}
19336342e81SSascha Wildner 
19436342e81SSascha Wildner 	while (*colp < col) {
19536342e81SSascha Wildner 		putchar(' ');
19636342e81SSascha Wildner 		(*colp)++;
19736342e81SSascha Wildner 	}
19836342e81SSascha Wildner 
19936342e81SSascha Wildner 	/*
20036342e81SSascha Wildner 	 * Print the input word, skipping any special characters.
20136342e81SSascha Wildner 	 */
20236342e81SSascha Wildner 	while ('\0' != *p)
20336342e81SSascha Wildner 		if ('\\' == *p) {
20436342e81SSascha Wildner 			p++;
20536342e81SSascha Wildner 			esc = mandoc_escape(&p, NULL, NULL);
20636342e81SSascha Wildner 			if (ESCAPE_ERROR == esc)
20736342e81SSascha Wildner 				break;
20836342e81SSascha Wildner 		} else {
20936342e81SSascha Wildner 			putchar((unsigned char )*p++);
21036342e81SSascha Wildner 			(*colp)++;
21136342e81SSascha Wildner 		}
21236342e81SSascha Wildner }
21336342e81SSascha Wildner 
21436342e81SSascha Wildner static void
pline(int line,int * linep,int * col,int list)21536342e81SSascha Wildner pline(int line, int *linep, int *col, int list)
21636342e81SSascha Wildner {
21736342e81SSascha Wildner 
21836342e81SSascha Wildner 	if (list)
21936342e81SSascha Wildner 		return;
22036342e81SSascha Wildner 
22136342e81SSascha Wildner 	/*
22236342e81SSascha Wildner 	 * Print out as many lines as needed to reach parity with the
22336342e81SSascha Wildner 	 * original input.
22436342e81SSascha Wildner 	 */
22536342e81SSascha Wildner 
22636342e81SSascha Wildner 	while (*linep < line) {
22736342e81SSascha Wildner 		putchar('\n');
22836342e81SSascha Wildner 		(*linep)++;
22936342e81SSascha Wildner 	}
23036342e81SSascha Wildner 
23136342e81SSascha Wildner 	*col = 0;
23236342e81SSascha Wildner }
23336342e81SSascha Wildner 
23436342e81SSascha Wildner static void
pmdoc(const struct roff_node * p,int * line,int * col,int list)235*54ba9607SSascha Wildner pmdoc(const struct roff_node *p, int *line, int *col, int list)
23636342e81SSascha Wildner {
23736342e81SSascha Wildner 
23836342e81SSascha Wildner 	for ( ; p; p = p->next) {
239*54ba9607SSascha Wildner 		if (NODE_LINE & p->flags)
24036342e81SSascha Wildner 			pline(p->line, line, col, list);
241*54ba9607SSascha Wildner 		if (ROFFT_TEXT == p->type)
24236342e81SSascha Wildner 			pstring(p->string, p->pos, col, list);
24336342e81SSascha Wildner 		if (p->child)
24436342e81SSascha Wildner 			pmdoc(p->child, line, col, list);
24536342e81SSascha Wildner 	}
24636342e81SSascha Wildner }
24736342e81SSascha Wildner 
24836342e81SSascha Wildner static void
pman(const struct roff_node * p,int * line,int * col,int list)249*54ba9607SSascha Wildner pman(const struct roff_node *p, int *line, int *col, int list)
25036342e81SSascha Wildner {
25136342e81SSascha Wildner 
25236342e81SSascha Wildner 	for ( ; p; p = p->next) {
253*54ba9607SSascha Wildner 		if (NODE_LINE & p->flags)
25436342e81SSascha Wildner 			pline(p->line, line, col, list);
255*54ba9607SSascha Wildner 		if (ROFFT_TEXT == p->type)
25636342e81SSascha Wildner 			pstring(p->string, p->pos, col, list);
25736342e81SSascha Wildner 		if (p->child)
25836342e81SSascha Wildner 			pman(p->child, line, col, list);
25936342e81SSascha Wildner 	}
26036342e81SSascha Wildner }
261