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