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