1*544c191cSchristos /* Id: demandoc.c,v 1.33 2019/03/03 11:01:15 schwarze Exp */
2c5f73b34Sjoerg /*
3c5f73b34Sjoerg * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
4c5f73b34Sjoerg *
5c5f73b34Sjoerg * Permission to use, copy, modify, and distribute this software for any
6c5f73b34Sjoerg * purpose with or without fee is hereby granted, provided that the above
7c5f73b34Sjoerg * copyright notice and this permission notice appear in all copies.
8c5f73b34Sjoerg *
9c5f73b34Sjoerg * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10c5f73b34Sjoerg * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11c5f73b34Sjoerg * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12c5f73b34Sjoerg * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13c5f73b34Sjoerg * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14c5f73b34Sjoerg * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15c5f73b34Sjoerg * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16c5f73b34Sjoerg */
17c5f73b34Sjoerg #include "config.h"
18fec65c98Schristos
19fec65c98Schristos #include <sys/types.h>
20c5f73b34Sjoerg
21c5f73b34Sjoerg #include <assert.h>
22c5f73b34Sjoerg #include <ctype.h>
23c5f73b34Sjoerg #include <stdio.h>
24c5f73b34Sjoerg #include <stdlib.h>
25c5f73b34Sjoerg #include <string.h>
26c5f73b34Sjoerg #include <unistd.h>
27c5f73b34Sjoerg
28c9bcef03Schristos #include "mandoc.h"
299ff1f2acSchristos #include "roff.h"
30c5f73b34Sjoerg #include "man.h"
31c5f73b34Sjoerg #include "mdoc.h"
32*544c191cSchristos #include "mandoc_parse.h"
33c5f73b34Sjoerg
34c5f73b34Sjoerg static void pline(int, int *, int *, int);
359ff1f2acSchristos static void pman(const struct roff_node *, int *, int *, int);
36c5f73b34Sjoerg static void pmandoc(struct mparse *, int, const char *, int);
379ff1f2acSchristos static void pmdoc(const struct roff_node *, int *, int *, int);
38c5f73b34Sjoerg static void pstring(const char *, int, int *, int);
39c5f73b34Sjoerg static void usage(void);
40c5f73b34Sjoerg
41c5f73b34Sjoerg static const char *progname;
42c5f73b34Sjoerg
43c5f73b34Sjoerg int
main(int argc,char * argv[])44c5f73b34Sjoerg main(int argc, char *argv[])
45c5f73b34Sjoerg {
46c5f73b34Sjoerg struct mparse *mp;
47fec65c98Schristos int ch, fd, i, list;
48c5f73b34Sjoerg extern int optind;
49c5f73b34Sjoerg
50fec65c98Schristos if (argc < 1)
51fec65c98Schristos progname = "demandoc";
52fec65c98Schristos else if ((progname = strrchr(argv[0], '/')) == NULL)
53c5f73b34Sjoerg progname = argv[0];
54c5f73b34Sjoerg else
55c5f73b34Sjoerg ++progname;
56c5f73b34Sjoerg
57c5f73b34Sjoerg mp = NULL;
58c5f73b34Sjoerg list = 0;
59c5f73b34Sjoerg
60c5f73b34Sjoerg while (-1 != (ch = getopt(argc, argv, "ikm:pw")))
61c5f73b34Sjoerg switch (ch) {
62c5f73b34Sjoerg case ('i'):
63c5f73b34Sjoerg /* FALLTHROUGH */
64c5f73b34Sjoerg case ('k'):
65c5f73b34Sjoerg /* FALLTHROUGH */
66c5f73b34Sjoerg case ('m'):
67c5f73b34Sjoerg /* FALLTHROUGH */
68c5f73b34Sjoerg case ('p'):
69c5f73b34Sjoerg break;
70c5f73b34Sjoerg case ('w'):
71c5f73b34Sjoerg list = 1;
72c5f73b34Sjoerg break;
73c5f73b34Sjoerg default:
74c5f73b34Sjoerg usage();
759ff1f2acSchristos return (int)MANDOCLEVEL_BADARG;
76c5f73b34Sjoerg }
77c5f73b34Sjoerg
78c5f73b34Sjoerg argc -= optind;
79c5f73b34Sjoerg argv += optind;
80c5f73b34Sjoerg
819ff1f2acSchristos mchars_alloc();
82*544c191cSchristos mp = mparse_alloc(MPARSE_SO | MPARSE_UTF8 | MPARSE_LATIN1 |
83*544c191cSchristos MPARSE_VALIDATE, MANDOC_OS_OTHER, NULL);
84c5f73b34Sjoerg assert(mp);
85c5f73b34Sjoerg
86fec65c98Schristos if (argc < 1)
87c5f73b34Sjoerg pmandoc(mp, STDIN_FILENO, "<stdin>", list);
88c5f73b34Sjoerg
89c5f73b34Sjoerg for (i = 0; i < argc; i++) {
90c5f73b34Sjoerg mparse_reset(mp);
919ff1f2acSchristos if ((fd = mparse_open(mp, argv[i])) == -1) {
92fec65c98Schristos perror(argv[i]);
93fec65c98Schristos continue;
94fec65c98Schristos }
95fec65c98Schristos pmandoc(mp, fd, argv[i], list);
96c5f73b34Sjoerg }
97c5f73b34Sjoerg
98c5f73b34Sjoerg mparse_free(mp);
999ff1f2acSchristos mchars_free();
1009ff1f2acSchristos return (int)MANDOCLEVEL_OK;
101c5f73b34Sjoerg }
102c5f73b34Sjoerg
103c5f73b34Sjoerg static void
usage(void)104c5f73b34Sjoerg usage(void)
105c5f73b34Sjoerg {
106c5f73b34Sjoerg
107c5f73b34Sjoerg fprintf(stderr, "usage: %s [-w] [files...]\n", progname);
108c5f73b34Sjoerg }
109c5f73b34Sjoerg
110c5f73b34Sjoerg static void
pmandoc(struct mparse * mp,int fd,const char * fn,int list)111c5f73b34Sjoerg pmandoc(struct mparse *mp, int fd, const char *fn, int list)
112c5f73b34Sjoerg {
113*544c191cSchristos struct roff_meta *meta;
114c5f73b34Sjoerg int line, col;
115c5f73b34Sjoerg
116fec65c98Schristos mparse_readfd(mp, fd, fn);
1179ff1f2acSchristos close(fd);
118*544c191cSchristos meta = mparse_result(mp);
119c5f73b34Sjoerg line = 1;
120c5f73b34Sjoerg col = 0;
121c5f73b34Sjoerg
122*544c191cSchristos if (meta->macroset == MACROSET_MDOC)
123*544c191cSchristos pmdoc(meta->first->child, &line, &col, list);
124*544c191cSchristos else
125*544c191cSchristos pman(meta->first->child, &line, &col, list);
126c5f73b34Sjoerg
127c5f73b34Sjoerg if ( ! list)
128c5f73b34Sjoerg putchar('\n');
129c5f73b34Sjoerg }
130c5f73b34Sjoerg
131c5f73b34Sjoerg /*
132c5f73b34Sjoerg * Strip the escapes out of a string, emitting the results.
133c5f73b34Sjoerg */
134c5f73b34Sjoerg static void
pstring(const char * p,int col,int * colp,int list)135c5f73b34Sjoerg pstring(const char *p, int col, int *colp, int list)
136c5f73b34Sjoerg {
137c5f73b34Sjoerg enum mandoc_esc esc;
138c5f73b34Sjoerg const char *start, *end;
139c5f73b34Sjoerg int emit;
140c5f73b34Sjoerg
141c5f73b34Sjoerg /*
142c5f73b34Sjoerg * Print as many column spaces til we achieve parity with the
143c5f73b34Sjoerg * input document.
144c5f73b34Sjoerg */
145c5f73b34Sjoerg
146c5f73b34Sjoerg again:
147c5f73b34Sjoerg if (list && '\0' != *p) {
148c5f73b34Sjoerg while (isspace((unsigned char)*p))
149c5f73b34Sjoerg p++;
150c5f73b34Sjoerg
151c5f73b34Sjoerg while ('\'' == *p || '(' == *p || '"' == *p)
152c5f73b34Sjoerg p++;
153c5f73b34Sjoerg
154c5f73b34Sjoerg emit = isalpha((unsigned char)p[0]) &&
155c5f73b34Sjoerg isalpha((unsigned char)p[1]);
156c5f73b34Sjoerg
157c5f73b34Sjoerg for (start = p; '\0' != *p; p++)
158c5f73b34Sjoerg if ('\\' == *p) {
159c5f73b34Sjoerg p++;
160c5f73b34Sjoerg esc = mandoc_escape(&p, NULL, NULL);
161c5f73b34Sjoerg if (ESCAPE_ERROR == esc)
162c5f73b34Sjoerg return;
163c5f73b34Sjoerg emit = 0;
164c5f73b34Sjoerg } else if (isspace((unsigned char)*p))
165c5f73b34Sjoerg break;
166c5f73b34Sjoerg
167c5f73b34Sjoerg end = p - 1;
168c5f73b34Sjoerg
169c5f73b34Sjoerg while (end > start)
170c5f73b34Sjoerg if ('.' == *end || ',' == *end ||
171c5f73b34Sjoerg '\'' == *end || '"' == *end ||
172c5f73b34Sjoerg ')' == *end || '!' == *end ||
173c5f73b34Sjoerg '?' == *end || ':' == *end ||
174c5f73b34Sjoerg ';' == *end)
175c5f73b34Sjoerg end--;
176c5f73b34Sjoerg else
177c5f73b34Sjoerg break;
178c5f73b34Sjoerg
179c5f73b34Sjoerg if (emit && end - start >= 1) {
180c5f73b34Sjoerg for ( ; start <= end; start++)
181c5f73b34Sjoerg if (ASCII_HYPH == *start)
182c5f73b34Sjoerg putchar('-');
183c5f73b34Sjoerg else
184c5f73b34Sjoerg putchar((unsigned char)*start);
185c5f73b34Sjoerg putchar('\n');
186c5f73b34Sjoerg }
187c5f73b34Sjoerg
188c5f73b34Sjoerg if (isspace((unsigned char)*p))
189c5f73b34Sjoerg goto again;
190c5f73b34Sjoerg
191c5f73b34Sjoerg return;
192c5f73b34Sjoerg }
193c5f73b34Sjoerg
194c5f73b34Sjoerg while (*colp < col) {
195c5f73b34Sjoerg putchar(' ');
196c5f73b34Sjoerg (*colp)++;
197c5f73b34Sjoerg }
198c5f73b34Sjoerg
199c5f73b34Sjoerg /*
200c5f73b34Sjoerg * Print the input word, skipping any special characters.
201c5f73b34Sjoerg */
202c5f73b34Sjoerg while ('\0' != *p)
203c5f73b34Sjoerg if ('\\' == *p) {
204c5f73b34Sjoerg p++;
205c5f73b34Sjoerg esc = mandoc_escape(&p, NULL, NULL);
206c5f73b34Sjoerg if (ESCAPE_ERROR == esc)
207c5f73b34Sjoerg break;
208c5f73b34Sjoerg } else {
209c5f73b34Sjoerg putchar((unsigned char )*p++);
210c5f73b34Sjoerg (*colp)++;
211c5f73b34Sjoerg }
212c5f73b34Sjoerg }
213c5f73b34Sjoerg
214c5f73b34Sjoerg static void
pline(int line,int * linep,int * col,int list)215c5f73b34Sjoerg pline(int line, int *linep, int *col, int list)
216c5f73b34Sjoerg {
217c5f73b34Sjoerg
218c5f73b34Sjoerg if (list)
219c5f73b34Sjoerg return;
220c5f73b34Sjoerg
221c5f73b34Sjoerg /*
222c5f73b34Sjoerg * Print out as many lines as needed to reach parity with the
223c5f73b34Sjoerg * original input.
224c5f73b34Sjoerg */
225c5f73b34Sjoerg
226c5f73b34Sjoerg while (*linep < line) {
227c5f73b34Sjoerg putchar('\n');
228c5f73b34Sjoerg (*linep)++;
229c5f73b34Sjoerg }
230c5f73b34Sjoerg
231c5f73b34Sjoerg *col = 0;
232c5f73b34Sjoerg }
233c5f73b34Sjoerg
234c5f73b34Sjoerg static void
pmdoc(const struct roff_node * p,int * line,int * col,int list)2359ff1f2acSchristos pmdoc(const struct roff_node *p, int *line, int *col, int list)
236c5f73b34Sjoerg {
237c5f73b34Sjoerg
238c5f73b34Sjoerg for ( ; p; p = p->next) {
2399508192eSchristos if (NODE_LINE & p->flags)
240c5f73b34Sjoerg pline(p->line, line, col, list);
2419ff1f2acSchristos if (ROFFT_TEXT == p->type)
242c5f73b34Sjoerg pstring(p->string, p->pos, col, list);
243c5f73b34Sjoerg if (p->child)
244c5f73b34Sjoerg pmdoc(p->child, line, col, list);
245c5f73b34Sjoerg }
246c5f73b34Sjoerg }
247c5f73b34Sjoerg
248c5f73b34Sjoerg static void
pman(const struct roff_node * p,int * line,int * col,int list)2499ff1f2acSchristos pman(const struct roff_node *p, int *line, int *col, int list)
250c5f73b34Sjoerg {
251c5f73b34Sjoerg
252c5f73b34Sjoerg for ( ; p; p = p->next) {
2539508192eSchristos if (NODE_LINE & p->flags)
254c5f73b34Sjoerg pline(p->line, line, col, list);
2559ff1f2acSchristos if (ROFFT_TEXT == p->type)
256c5f73b34Sjoerg pstring(p->string, p->pos, col, list);
257c5f73b34Sjoerg if (p->child)
258c5f73b34Sjoerg pman(p->child, line, col, list);
259c5f73b34Sjoerg }
260c5f73b34Sjoerg }
261