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