xref: /freebsd/contrib/mandoc/demandoc.c (revision 7295610f5da64ab1818458ce007d9eb924496330)
1*7295610fSBaptiste Daroussin /*	$Id: demandoc.c,v 1.33 2019/03/03 11:01:15 schwarze Exp $ */
261d06d6bSBaptiste Daroussin /*
361d06d6bSBaptiste Daroussin  * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
461d06d6bSBaptiste Daroussin  *
561d06d6bSBaptiste Daroussin  * Permission to use, copy, modify, and distribute this software for any
661d06d6bSBaptiste Daroussin  * purpose with or without fee is hereby granted, provided that the above
761d06d6bSBaptiste Daroussin  * copyright notice and this permission notice appear in all copies.
861d06d6bSBaptiste Daroussin  *
961d06d6bSBaptiste Daroussin  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1061d06d6bSBaptiste Daroussin  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1161d06d6bSBaptiste Daroussin  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1261d06d6bSBaptiste Daroussin  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1361d06d6bSBaptiste Daroussin  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1461d06d6bSBaptiste Daroussin  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1561d06d6bSBaptiste Daroussin  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1661d06d6bSBaptiste Daroussin  */
1761d06d6bSBaptiste Daroussin #include "config.h"
1861d06d6bSBaptiste Daroussin 
1961d06d6bSBaptiste Daroussin #include <sys/types.h>
2061d06d6bSBaptiste Daroussin 
2161d06d6bSBaptiste Daroussin #include <assert.h>
2261d06d6bSBaptiste Daroussin #include <ctype.h>
2361d06d6bSBaptiste Daroussin #include <stdio.h>
2461d06d6bSBaptiste Daroussin #include <stdlib.h>
2561d06d6bSBaptiste Daroussin #include <string.h>
2661d06d6bSBaptiste Daroussin #include <unistd.h>
2761d06d6bSBaptiste Daroussin 
2861d06d6bSBaptiste Daroussin #include "mandoc.h"
2961d06d6bSBaptiste Daroussin #include "roff.h"
3061d06d6bSBaptiste Daroussin #include "man.h"
3161d06d6bSBaptiste Daroussin #include "mdoc.h"
32*7295610fSBaptiste Daroussin #include "mandoc_parse.h"
3361d06d6bSBaptiste Daroussin 
3461d06d6bSBaptiste Daroussin static	void	 pline(int, int *, int *, int);
3561d06d6bSBaptiste Daroussin static	void	 pman(const struct roff_node *, int *, int *, int);
3661d06d6bSBaptiste Daroussin static	void	 pmandoc(struct mparse *, int, const char *, int);
3761d06d6bSBaptiste Daroussin static	void	 pmdoc(const struct roff_node *, int *, int *, int);
3861d06d6bSBaptiste Daroussin static	void	 pstring(const char *, int, int *, int);
3961d06d6bSBaptiste Daroussin static	void	 usage(void);
4061d06d6bSBaptiste Daroussin 
4161d06d6bSBaptiste Daroussin static	const char	 *progname;
4261d06d6bSBaptiste Daroussin 
4361d06d6bSBaptiste Daroussin int
4461d06d6bSBaptiste Daroussin main(int argc, char *argv[])
4561d06d6bSBaptiste Daroussin {
4661d06d6bSBaptiste Daroussin 	struct mparse	*mp;
4761d06d6bSBaptiste Daroussin 	int		 ch, fd, i, list;
4861d06d6bSBaptiste Daroussin 	extern int	 optind;
4961d06d6bSBaptiste Daroussin 
5061d06d6bSBaptiste Daroussin 	if (argc < 1)
5161d06d6bSBaptiste Daroussin 		progname = "demandoc";
5261d06d6bSBaptiste Daroussin 	else if ((progname = strrchr(argv[0], '/')) == NULL)
5361d06d6bSBaptiste Daroussin 		progname = argv[0];
5461d06d6bSBaptiste Daroussin 	else
5561d06d6bSBaptiste Daroussin 		++progname;
5661d06d6bSBaptiste Daroussin 
5761d06d6bSBaptiste Daroussin 	mp = NULL;
5861d06d6bSBaptiste Daroussin 	list = 0;
5961d06d6bSBaptiste Daroussin 
6061d06d6bSBaptiste Daroussin 	while (-1 != (ch = getopt(argc, argv, "ikm:pw")))
6161d06d6bSBaptiste Daroussin 		switch (ch) {
6261d06d6bSBaptiste Daroussin 		case ('i'):
6361d06d6bSBaptiste Daroussin 			/* FALLTHROUGH */
6461d06d6bSBaptiste Daroussin 		case ('k'):
6561d06d6bSBaptiste Daroussin 			/* FALLTHROUGH */
6661d06d6bSBaptiste Daroussin 		case ('m'):
6761d06d6bSBaptiste Daroussin 			/* FALLTHROUGH */
6861d06d6bSBaptiste Daroussin 		case ('p'):
6961d06d6bSBaptiste Daroussin 			break;
7061d06d6bSBaptiste Daroussin 		case ('w'):
7161d06d6bSBaptiste Daroussin 			list = 1;
7261d06d6bSBaptiste Daroussin 			break;
7361d06d6bSBaptiste Daroussin 		default:
7461d06d6bSBaptiste Daroussin 			usage();
7561d06d6bSBaptiste Daroussin 			return (int)MANDOCLEVEL_BADARG;
7661d06d6bSBaptiste Daroussin 		}
7761d06d6bSBaptiste Daroussin 
7861d06d6bSBaptiste Daroussin 	argc -= optind;
7961d06d6bSBaptiste Daroussin 	argv += optind;
8061d06d6bSBaptiste Daroussin 
8161d06d6bSBaptiste Daroussin 	mchars_alloc();
82*7295610fSBaptiste Daroussin 	mp = mparse_alloc(MPARSE_SO | MPARSE_UTF8 | MPARSE_LATIN1 |
83*7295610fSBaptiste Daroussin 	    MPARSE_VALIDATE, MANDOC_OS_OTHER, NULL);
8461d06d6bSBaptiste Daroussin 	assert(mp);
8561d06d6bSBaptiste Daroussin 
8661d06d6bSBaptiste Daroussin 	if (argc < 1)
8761d06d6bSBaptiste Daroussin 		pmandoc(mp, STDIN_FILENO, "<stdin>", list);
8861d06d6bSBaptiste Daroussin 
8961d06d6bSBaptiste Daroussin 	for (i = 0; i < argc; i++) {
9061d06d6bSBaptiste Daroussin 		mparse_reset(mp);
9161d06d6bSBaptiste Daroussin 		if ((fd = mparse_open(mp, argv[i])) == -1) {
9261d06d6bSBaptiste Daroussin 			perror(argv[i]);
9361d06d6bSBaptiste Daroussin 			continue;
9461d06d6bSBaptiste Daroussin 		}
9561d06d6bSBaptiste Daroussin 		pmandoc(mp, fd, argv[i], list);
9661d06d6bSBaptiste Daroussin 	}
9761d06d6bSBaptiste Daroussin 
9861d06d6bSBaptiste Daroussin 	mparse_free(mp);
9961d06d6bSBaptiste Daroussin 	mchars_free();
10061d06d6bSBaptiste Daroussin 	return (int)MANDOCLEVEL_OK;
10161d06d6bSBaptiste Daroussin }
10261d06d6bSBaptiste Daroussin 
10361d06d6bSBaptiste Daroussin static void
10461d06d6bSBaptiste Daroussin usage(void)
10561d06d6bSBaptiste Daroussin {
10661d06d6bSBaptiste Daroussin 
10761d06d6bSBaptiste Daroussin 	fprintf(stderr, "usage: %s [-w] [files...]\n", progname);
10861d06d6bSBaptiste Daroussin }
10961d06d6bSBaptiste Daroussin 
11061d06d6bSBaptiste Daroussin static void
11161d06d6bSBaptiste Daroussin pmandoc(struct mparse *mp, int fd, const char *fn, int list)
11261d06d6bSBaptiste Daroussin {
113*7295610fSBaptiste Daroussin 	struct roff_meta	*meta;
11461d06d6bSBaptiste Daroussin 	int		 line, col;
11561d06d6bSBaptiste Daroussin 
11661d06d6bSBaptiste Daroussin 	mparse_readfd(mp, fd, fn);
11761d06d6bSBaptiste Daroussin 	close(fd);
118*7295610fSBaptiste Daroussin 	meta = mparse_result(mp);
11961d06d6bSBaptiste Daroussin 	line = 1;
12061d06d6bSBaptiste Daroussin 	col = 0;
12161d06d6bSBaptiste Daroussin 
122*7295610fSBaptiste Daroussin 	if (meta->macroset == MACROSET_MDOC)
123*7295610fSBaptiste Daroussin 		pmdoc(meta->first->child, &line, &col, list);
124*7295610fSBaptiste Daroussin 	else
125*7295610fSBaptiste Daroussin 		pman(meta->first->child, &line, &col, list);
12661d06d6bSBaptiste Daroussin 
12761d06d6bSBaptiste Daroussin 	if ( ! list)
12861d06d6bSBaptiste Daroussin 		putchar('\n');
12961d06d6bSBaptiste Daroussin }
13061d06d6bSBaptiste Daroussin 
13161d06d6bSBaptiste Daroussin /*
13261d06d6bSBaptiste Daroussin  * Strip the escapes out of a string, emitting the results.
13361d06d6bSBaptiste Daroussin  */
13461d06d6bSBaptiste Daroussin static void
13561d06d6bSBaptiste Daroussin pstring(const char *p, int col, int *colp, int list)
13661d06d6bSBaptiste Daroussin {
13761d06d6bSBaptiste Daroussin 	enum mandoc_esc	 esc;
13861d06d6bSBaptiste Daroussin 	const char	*start, *end;
13961d06d6bSBaptiste Daroussin 	int		 emit;
14061d06d6bSBaptiste Daroussin 
14161d06d6bSBaptiste Daroussin 	/*
14261d06d6bSBaptiste Daroussin 	 * Print as many column spaces til we achieve parity with the
14361d06d6bSBaptiste Daroussin 	 * input document.
14461d06d6bSBaptiste Daroussin 	 */
14561d06d6bSBaptiste Daroussin 
14661d06d6bSBaptiste Daroussin again:
14761d06d6bSBaptiste Daroussin 	if (list && '\0' != *p) {
14861d06d6bSBaptiste Daroussin 		while (isspace((unsigned char)*p))
14961d06d6bSBaptiste Daroussin 			p++;
15061d06d6bSBaptiste Daroussin 
15161d06d6bSBaptiste Daroussin 		while ('\'' == *p || '(' == *p || '"' == *p)
15261d06d6bSBaptiste Daroussin 			p++;
15361d06d6bSBaptiste Daroussin 
15461d06d6bSBaptiste Daroussin 		emit = isalpha((unsigned char)p[0]) &&
15561d06d6bSBaptiste Daroussin 			isalpha((unsigned char)p[1]);
15661d06d6bSBaptiste Daroussin 
15761d06d6bSBaptiste Daroussin 		for (start = p; '\0' != *p; p++)
15861d06d6bSBaptiste Daroussin 			if ('\\' == *p) {
15961d06d6bSBaptiste Daroussin 				p++;
16061d06d6bSBaptiste Daroussin 				esc = mandoc_escape(&p, NULL, NULL);
16161d06d6bSBaptiste Daroussin 				if (ESCAPE_ERROR == esc)
16261d06d6bSBaptiste Daroussin 					return;
16361d06d6bSBaptiste Daroussin 				emit = 0;
16461d06d6bSBaptiste Daroussin 			} else if (isspace((unsigned char)*p))
16561d06d6bSBaptiste Daroussin 				break;
16661d06d6bSBaptiste Daroussin 
16761d06d6bSBaptiste Daroussin 		end = p - 1;
16861d06d6bSBaptiste Daroussin 
16961d06d6bSBaptiste Daroussin 		while (end > start)
17061d06d6bSBaptiste Daroussin 			if ('.' == *end || ',' == *end ||
17161d06d6bSBaptiste Daroussin 					'\'' == *end || '"' == *end ||
17261d06d6bSBaptiste Daroussin 					')' == *end || '!' == *end ||
17361d06d6bSBaptiste Daroussin 					'?' == *end || ':' == *end ||
17461d06d6bSBaptiste Daroussin 					';' == *end)
17561d06d6bSBaptiste Daroussin 				end--;
17661d06d6bSBaptiste Daroussin 			else
17761d06d6bSBaptiste Daroussin 				break;
17861d06d6bSBaptiste Daroussin 
17961d06d6bSBaptiste Daroussin 		if (emit && end - start >= 1) {
18061d06d6bSBaptiste Daroussin 			for ( ; start <= end; start++)
18161d06d6bSBaptiste Daroussin 				if (ASCII_HYPH == *start)
18261d06d6bSBaptiste Daroussin 					putchar('-');
18361d06d6bSBaptiste Daroussin 				else
18461d06d6bSBaptiste Daroussin 					putchar((unsigned char)*start);
18561d06d6bSBaptiste Daroussin 			putchar('\n');
18661d06d6bSBaptiste Daroussin 		}
18761d06d6bSBaptiste Daroussin 
18861d06d6bSBaptiste Daroussin 		if (isspace((unsigned char)*p))
18961d06d6bSBaptiste Daroussin 			goto again;
19061d06d6bSBaptiste Daroussin 
19161d06d6bSBaptiste Daroussin 		return;
19261d06d6bSBaptiste Daroussin 	}
19361d06d6bSBaptiste Daroussin 
19461d06d6bSBaptiste Daroussin 	while (*colp < col) {
19561d06d6bSBaptiste Daroussin 		putchar(' ');
19661d06d6bSBaptiste Daroussin 		(*colp)++;
19761d06d6bSBaptiste Daroussin 	}
19861d06d6bSBaptiste Daroussin 
19961d06d6bSBaptiste Daroussin 	/*
20061d06d6bSBaptiste Daroussin 	 * Print the input word, skipping any special characters.
20161d06d6bSBaptiste Daroussin 	 */
20261d06d6bSBaptiste Daroussin 	while ('\0' != *p)
20361d06d6bSBaptiste Daroussin 		if ('\\' == *p) {
20461d06d6bSBaptiste Daroussin 			p++;
20561d06d6bSBaptiste Daroussin 			esc = mandoc_escape(&p, NULL, NULL);
20661d06d6bSBaptiste Daroussin 			if (ESCAPE_ERROR == esc)
20761d06d6bSBaptiste Daroussin 				break;
20861d06d6bSBaptiste Daroussin 		} else {
20961d06d6bSBaptiste Daroussin 			putchar((unsigned char )*p++);
21061d06d6bSBaptiste Daroussin 			(*colp)++;
21161d06d6bSBaptiste Daroussin 		}
21261d06d6bSBaptiste Daroussin }
21361d06d6bSBaptiste Daroussin 
21461d06d6bSBaptiste Daroussin static void
21561d06d6bSBaptiste Daroussin pline(int line, int *linep, int *col, int list)
21661d06d6bSBaptiste Daroussin {
21761d06d6bSBaptiste Daroussin 
21861d06d6bSBaptiste Daroussin 	if (list)
21961d06d6bSBaptiste Daroussin 		return;
22061d06d6bSBaptiste Daroussin 
22161d06d6bSBaptiste Daroussin 	/*
22261d06d6bSBaptiste Daroussin 	 * Print out as many lines as needed to reach parity with the
22361d06d6bSBaptiste Daroussin 	 * original input.
22461d06d6bSBaptiste Daroussin 	 */
22561d06d6bSBaptiste Daroussin 
22661d06d6bSBaptiste Daroussin 	while (*linep < line) {
22761d06d6bSBaptiste Daroussin 		putchar('\n');
22861d06d6bSBaptiste Daroussin 		(*linep)++;
22961d06d6bSBaptiste Daroussin 	}
23061d06d6bSBaptiste Daroussin 
23161d06d6bSBaptiste Daroussin 	*col = 0;
23261d06d6bSBaptiste Daroussin }
23361d06d6bSBaptiste Daroussin 
23461d06d6bSBaptiste Daroussin static void
23561d06d6bSBaptiste Daroussin pmdoc(const struct roff_node *p, int *line, int *col, int list)
23661d06d6bSBaptiste Daroussin {
23761d06d6bSBaptiste Daroussin 
23861d06d6bSBaptiste Daroussin 	for ( ; p; p = p->next) {
23961d06d6bSBaptiste Daroussin 		if (NODE_LINE & p->flags)
24061d06d6bSBaptiste Daroussin 			pline(p->line, line, col, list);
24161d06d6bSBaptiste Daroussin 		if (ROFFT_TEXT == p->type)
24261d06d6bSBaptiste Daroussin 			pstring(p->string, p->pos, col, list);
24361d06d6bSBaptiste Daroussin 		if (p->child)
24461d06d6bSBaptiste Daroussin 			pmdoc(p->child, line, col, list);
24561d06d6bSBaptiste Daroussin 	}
24661d06d6bSBaptiste Daroussin }
24761d06d6bSBaptiste Daroussin 
24861d06d6bSBaptiste Daroussin static void
24961d06d6bSBaptiste Daroussin pman(const struct roff_node *p, int *line, int *col, int list)
25061d06d6bSBaptiste Daroussin {
25161d06d6bSBaptiste Daroussin 
25261d06d6bSBaptiste Daroussin 	for ( ; p; p = p->next) {
25361d06d6bSBaptiste Daroussin 		if (NODE_LINE & p->flags)
25461d06d6bSBaptiste Daroussin 			pline(p->line, line, col, list);
25561d06d6bSBaptiste Daroussin 		if (ROFFT_TEXT == p->type)
25661d06d6bSBaptiste Daroussin 			pstring(p->string, p->pos, col, list);
25761d06d6bSBaptiste Daroussin 		if (p->child)
25861d06d6bSBaptiste Daroussin 			pman(p->child, line, col, list);
25961d06d6bSBaptiste Daroussin 	}
26061d06d6bSBaptiste Daroussin }
261