xref: /freebsd/contrib/mandoc/demandoc.c (revision c1c95add8c80843ba15d784f95c361d795b1f593)
1*c1c95addSBrooks Davis /* $Id: demandoc.c,v 1.34 2022/04/14 16:43:43 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"
29*c1c95addSBrooks Davis #if DEBUG_MEMORY
30*c1c95addSBrooks Davis #define DEBUG_NODEF
31*c1c95addSBrooks Davis #include "mandoc_dbg.h"
32*c1c95addSBrooks Davis #endif
3361d06d6bSBaptiste Daroussin #include "roff.h"
3461d06d6bSBaptiste Daroussin #include "man.h"
3561d06d6bSBaptiste Daroussin #include "mdoc.h"
367295610fSBaptiste Daroussin #include "mandoc_parse.h"
3761d06d6bSBaptiste Daroussin 
3861d06d6bSBaptiste Daroussin static	void	 pline(int, int *, int *, int);
3961d06d6bSBaptiste Daroussin static	void	 pman(const struct roff_node *, int *, int *, int);
4061d06d6bSBaptiste Daroussin static	void	 pmandoc(struct mparse *, int, const char *, int);
4161d06d6bSBaptiste Daroussin static	void	 pmdoc(const struct roff_node *, int *, int *, int);
4261d06d6bSBaptiste Daroussin static	void	 pstring(const char *, int, int *, int);
4361d06d6bSBaptiste Daroussin static	void	 usage(void);
4461d06d6bSBaptiste Daroussin 
4561d06d6bSBaptiste Daroussin static	const char	 *progname;
4661d06d6bSBaptiste Daroussin 
4761d06d6bSBaptiste Daroussin int
main(int argc,char * argv[])4861d06d6bSBaptiste Daroussin main(int argc, char *argv[])
4961d06d6bSBaptiste Daroussin {
5061d06d6bSBaptiste Daroussin 	struct mparse	*mp;
5161d06d6bSBaptiste Daroussin 	int		 ch, fd, i, list;
5261d06d6bSBaptiste Daroussin 	extern int	 optind;
5361d06d6bSBaptiste Daroussin 
54*c1c95addSBrooks Davis #if DEBUG_MEMORY
55*c1c95addSBrooks Davis 	mandoc_dbg_init(argc, argv);
56*c1c95addSBrooks Davis #endif
57*c1c95addSBrooks Davis 
5861d06d6bSBaptiste Daroussin 	if (argc < 1)
5961d06d6bSBaptiste Daroussin 		progname = "demandoc";
6061d06d6bSBaptiste Daroussin 	else if ((progname = strrchr(argv[0], '/')) == NULL)
6161d06d6bSBaptiste Daroussin 		progname = argv[0];
6261d06d6bSBaptiste Daroussin 	else
6361d06d6bSBaptiste Daroussin 		++progname;
6461d06d6bSBaptiste Daroussin 
6561d06d6bSBaptiste Daroussin 	mp = NULL;
6661d06d6bSBaptiste Daroussin 	list = 0;
6761d06d6bSBaptiste Daroussin 
6861d06d6bSBaptiste Daroussin 	while (-1 != (ch = getopt(argc, argv, "ikm:pw")))
6961d06d6bSBaptiste Daroussin 		switch (ch) {
7061d06d6bSBaptiste Daroussin 		case ('i'):
7161d06d6bSBaptiste Daroussin 			/* FALLTHROUGH */
7261d06d6bSBaptiste Daroussin 		case ('k'):
7361d06d6bSBaptiste Daroussin 			/* FALLTHROUGH */
7461d06d6bSBaptiste Daroussin 		case ('m'):
7561d06d6bSBaptiste Daroussin 			/* FALLTHROUGH */
7661d06d6bSBaptiste Daroussin 		case ('p'):
7761d06d6bSBaptiste Daroussin 			break;
7861d06d6bSBaptiste Daroussin 		case ('w'):
7961d06d6bSBaptiste Daroussin 			list = 1;
8061d06d6bSBaptiste Daroussin 			break;
8161d06d6bSBaptiste Daroussin 		default:
8261d06d6bSBaptiste Daroussin 			usage();
8361d06d6bSBaptiste Daroussin 			return (int)MANDOCLEVEL_BADARG;
8461d06d6bSBaptiste Daroussin 		}
8561d06d6bSBaptiste Daroussin 
8661d06d6bSBaptiste Daroussin 	argc -= optind;
8761d06d6bSBaptiste Daroussin 	argv += optind;
8861d06d6bSBaptiste Daroussin 
8961d06d6bSBaptiste Daroussin 	mchars_alloc();
907295610fSBaptiste Daroussin 	mp = mparse_alloc(MPARSE_SO | MPARSE_UTF8 | MPARSE_LATIN1 |
917295610fSBaptiste Daroussin 	    MPARSE_VALIDATE, MANDOC_OS_OTHER, NULL);
9261d06d6bSBaptiste Daroussin 	assert(mp);
9361d06d6bSBaptiste Daroussin 
9461d06d6bSBaptiste Daroussin 	if (argc < 1)
9561d06d6bSBaptiste Daroussin 		pmandoc(mp, STDIN_FILENO, "<stdin>", list);
9661d06d6bSBaptiste Daroussin 
9761d06d6bSBaptiste Daroussin 	for (i = 0; i < argc; i++) {
9861d06d6bSBaptiste Daroussin 		mparse_reset(mp);
9961d06d6bSBaptiste Daroussin 		if ((fd = mparse_open(mp, argv[i])) == -1) {
10061d06d6bSBaptiste Daroussin 			perror(argv[i]);
10161d06d6bSBaptiste Daroussin 			continue;
10261d06d6bSBaptiste Daroussin 		}
10361d06d6bSBaptiste Daroussin 		pmandoc(mp, fd, argv[i], list);
10461d06d6bSBaptiste Daroussin 	}
10561d06d6bSBaptiste Daroussin 
10661d06d6bSBaptiste Daroussin 	mparse_free(mp);
10761d06d6bSBaptiste Daroussin 	mchars_free();
108*c1c95addSBrooks Davis #if DEBUG_MEMORY
109*c1c95addSBrooks Davis 	mandoc_dbg_finish();
110*c1c95addSBrooks Davis #endif
11161d06d6bSBaptiste Daroussin 	return (int)MANDOCLEVEL_OK;
11261d06d6bSBaptiste Daroussin }
11361d06d6bSBaptiste Daroussin 
11461d06d6bSBaptiste Daroussin static void
usage(void)11561d06d6bSBaptiste Daroussin usage(void)
11661d06d6bSBaptiste Daroussin {
11761d06d6bSBaptiste Daroussin 
11861d06d6bSBaptiste Daroussin 	fprintf(stderr, "usage: %s [-w] [files...]\n", progname);
11961d06d6bSBaptiste Daroussin }
12061d06d6bSBaptiste Daroussin 
12161d06d6bSBaptiste Daroussin static void
pmandoc(struct mparse * mp,int fd,const char * fn,int list)12261d06d6bSBaptiste Daroussin pmandoc(struct mparse *mp, int fd, const char *fn, int list)
12361d06d6bSBaptiste Daroussin {
1247295610fSBaptiste Daroussin 	struct roff_meta	*meta;
12561d06d6bSBaptiste Daroussin 	int		 line, col;
12661d06d6bSBaptiste Daroussin 
12761d06d6bSBaptiste Daroussin 	mparse_readfd(mp, fd, fn);
12861d06d6bSBaptiste Daroussin 	close(fd);
1297295610fSBaptiste Daroussin 	meta = mparse_result(mp);
13061d06d6bSBaptiste Daroussin 	line = 1;
13161d06d6bSBaptiste Daroussin 	col = 0;
13261d06d6bSBaptiste Daroussin 
1337295610fSBaptiste Daroussin 	if (meta->macroset == MACROSET_MDOC)
1347295610fSBaptiste Daroussin 		pmdoc(meta->first->child, &line, &col, list);
1357295610fSBaptiste Daroussin 	else
1367295610fSBaptiste Daroussin 		pman(meta->first->child, &line, &col, list);
13761d06d6bSBaptiste Daroussin 
13861d06d6bSBaptiste Daroussin 	if ( ! list)
13961d06d6bSBaptiste Daroussin 		putchar('\n');
14061d06d6bSBaptiste Daroussin }
14161d06d6bSBaptiste Daroussin 
14261d06d6bSBaptiste Daroussin /*
14361d06d6bSBaptiste Daroussin  * Strip the escapes out of a string, emitting the results.
14461d06d6bSBaptiste Daroussin  */
14561d06d6bSBaptiste Daroussin static void
pstring(const char * p,int col,int * colp,int list)14661d06d6bSBaptiste Daroussin pstring(const char *p, int col, int *colp, int list)
14761d06d6bSBaptiste Daroussin {
14861d06d6bSBaptiste Daroussin 	enum mandoc_esc	 esc;
14961d06d6bSBaptiste Daroussin 	const char	*start, *end;
15061d06d6bSBaptiste Daroussin 	int		 emit;
15161d06d6bSBaptiste Daroussin 
15261d06d6bSBaptiste Daroussin 	/*
15361d06d6bSBaptiste Daroussin 	 * Print as many column spaces til we achieve parity with the
15461d06d6bSBaptiste Daroussin 	 * input document.
15561d06d6bSBaptiste Daroussin 	 */
15661d06d6bSBaptiste Daroussin 
15761d06d6bSBaptiste Daroussin again:
15861d06d6bSBaptiste Daroussin 	if (list && '\0' != *p) {
15961d06d6bSBaptiste Daroussin 		while (isspace((unsigned char)*p))
16061d06d6bSBaptiste Daroussin 			p++;
16161d06d6bSBaptiste Daroussin 
16261d06d6bSBaptiste Daroussin 		while ('\'' == *p || '(' == *p || '"' == *p)
16361d06d6bSBaptiste Daroussin 			p++;
16461d06d6bSBaptiste Daroussin 
16561d06d6bSBaptiste Daroussin 		emit = isalpha((unsigned char)p[0]) &&
16661d06d6bSBaptiste Daroussin 			isalpha((unsigned char)p[1]);
16761d06d6bSBaptiste Daroussin 
16861d06d6bSBaptiste Daroussin 		for (start = p; '\0' != *p; p++)
16961d06d6bSBaptiste Daroussin 			if ('\\' == *p) {
17061d06d6bSBaptiste Daroussin 				p++;
17161d06d6bSBaptiste Daroussin 				esc = mandoc_escape(&p, NULL, NULL);
17261d06d6bSBaptiste Daroussin 				if (ESCAPE_ERROR == esc)
17361d06d6bSBaptiste Daroussin 					return;
17461d06d6bSBaptiste Daroussin 				emit = 0;
17561d06d6bSBaptiste Daroussin 			} else if (isspace((unsigned char)*p))
17661d06d6bSBaptiste Daroussin 				break;
17761d06d6bSBaptiste Daroussin 
17861d06d6bSBaptiste Daroussin 		end = p - 1;
17961d06d6bSBaptiste Daroussin 
18061d06d6bSBaptiste Daroussin 		while (end > start)
18161d06d6bSBaptiste Daroussin 			if ('.' == *end || ',' == *end ||
18261d06d6bSBaptiste Daroussin 					'\'' == *end || '"' == *end ||
18361d06d6bSBaptiste Daroussin 					')' == *end || '!' == *end ||
18461d06d6bSBaptiste Daroussin 					'?' == *end || ':' == *end ||
18561d06d6bSBaptiste Daroussin 					';' == *end)
18661d06d6bSBaptiste Daroussin 				end--;
18761d06d6bSBaptiste Daroussin 			else
18861d06d6bSBaptiste Daroussin 				break;
18961d06d6bSBaptiste Daroussin 
19061d06d6bSBaptiste Daroussin 		if (emit && end - start >= 1) {
19161d06d6bSBaptiste Daroussin 			for ( ; start <= end; start++)
19261d06d6bSBaptiste Daroussin 				if (ASCII_HYPH == *start)
19361d06d6bSBaptiste Daroussin 					putchar('-');
19461d06d6bSBaptiste Daroussin 				else
19561d06d6bSBaptiste Daroussin 					putchar((unsigned char)*start);
19661d06d6bSBaptiste Daroussin 			putchar('\n');
19761d06d6bSBaptiste Daroussin 		}
19861d06d6bSBaptiste Daroussin 
19961d06d6bSBaptiste Daroussin 		if (isspace((unsigned char)*p))
20061d06d6bSBaptiste Daroussin 			goto again;
20161d06d6bSBaptiste Daroussin 
20261d06d6bSBaptiste Daroussin 		return;
20361d06d6bSBaptiste Daroussin 	}
20461d06d6bSBaptiste Daroussin 
20561d06d6bSBaptiste Daroussin 	while (*colp < col) {
20661d06d6bSBaptiste Daroussin 		putchar(' ');
20761d06d6bSBaptiste Daroussin 		(*colp)++;
20861d06d6bSBaptiste Daroussin 	}
20961d06d6bSBaptiste Daroussin 
21061d06d6bSBaptiste Daroussin 	/*
21161d06d6bSBaptiste Daroussin 	 * Print the input word, skipping any special characters.
21261d06d6bSBaptiste Daroussin 	 */
21361d06d6bSBaptiste Daroussin 	while ('\0' != *p)
21461d06d6bSBaptiste Daroussin 		if ('\\' == *p) {
21561d06d6bSBaptiste Daroussin 			p++;
21661d06d6bSBaptiste Daroussin 			esc = mandoc_escape(&p, NULL, NULL);
21761d06d6bSBaptiste Daroussin 			if (ESCAPE_ERROR == esc)
21861d06d6bSBaptiste Daroussin 				break;
21961d06d6bSBaptiste Daroussin 		} else {
22061d06d6bSBaptiste Daroussin 			putchar((unsigned char )*p++);
22161d06d6bSBaptiste Daroussin 			(*colp)++;
22261d06d6bSBaptiste Daroussin 		}
22361d06d6bSBaptiste Daroussin }
22461d06d6bSBaptiste Daroussin 
22561d06d6bSBaptiste Daroussin static void
pline(int line,int * linep,int * col,int list)22661d06d6bSBaptiste Daroussin pline(int line, int *linep, int *col, int list)
22761d06d6bSBaptiste Daroussin {
22861d06d6bSBaptiste Daroussin 
22961d06d6bSBaptiste Daroussin 	if (list)
23061d06d6bSBaptiste Daroussin 		return;
23161d06d6bSBaptiste Daroussin 
23261d06d6bSBaptiste Daroussin 	/*
23361d06d6bSBaptiste Daroussin 	 * Print out as many lines as needed to reach parity with the
23461d06d6bSBaptiste Daroussin 	 * original input.
23561d06d6bSBaptiste Daroussin 	 */
23661d06d6bSBaptiste Daroussin 
23761d06d6bSBaptiste Daroussin 	while (*linep < line) {
23861d06d6bSBaptiste Daroussin 		putchar('\n');
23961d06d6bSBaptiste Daroussin 		(*linep)++;
24061d06d6bSBaptiste Daroussin 	}
24161d06d6bSBaptiste Daroussin 
24261d06d6bSBaptiste Daroussin 	*col = 0;
24361d06d6bSBaptiste Daroussin }
24461d06d6bSBaptiste Daroussin 
24561d06d6bSBaptiste Daroussin static void
pmdoc(const struct roff_node * p,int * line,int * col,int list)24661d06d6bSBaptiste Daroussin pmdoc(const struct roff_node *p, int *line, int *col, int list)
24761d06d6bSBaptiste Daroussin {
24861d06d6bSBaptiste Daroussin 
24961d06d6bSBaptiste Daroussin 	for ( ; p; p = p->next) {
25061d06d6bSBaptiste Daroussin 		if (NODE_LINE & p->flags)
25161d06d6bSBaptiste Daroussin 			pline(p->line, line, col, list);
25261d06d6bSBaptiste Daroussin 		if (ROFFT_TEXT == p->type)
25361d06d6bSBaptiste Daroussin 			pstring(p->string, p->pos, col, list);
25461d06d6bSBaptiste Daroussin 		if (p->child)
25561d06d6bSBaptiste Daroussin 			pmdoc(p->child, line, col, list);
25661d06d6bSBaptiste Daroussin 	}
25761d06d6bSBaptiste Daroussin }
25861d06d6bSBaptiste Daroussin 
25961d06d6bSBaptiste Daroussin static void
pman(const struct roff_node * p,int * line,int * col,int list)26061d06d6bSBaptiste Daroussin pman(const struct roff_node *p, int *line, int *col, int list)
26161d06d6bSBaptiste Daroussin {
26261d06d6bSBaptiste Daroussin 
26361d06d6bSBaptiste Daroussin 	for ( ; p; p = p->next) {
26461d06d6bSBaptiste Daroussin 		if (NODE_LINE & p->flags)
26561d06d6bSBaptiste Daroussin 			pline(p->line, line, col, list);
26661d06d6bSBaptiste Daroussin 		if (ROFFT_TEXT == p->type)
26761d06d6bSBaptiste Daroussin 			pstring(p->string, p->pos, col, list);
26861d06d6bSBaptiste Daroussin 		if (p->child)
26961d06d6bSBaptiste Daroussin 			pman(p->child, line, col, list);
27061d06d6bSBaptiste Daroussin 	}
27161d06d6bSBaptiste Daroussin }
272