]> git.cameronkatri.com Git - mandoc.git/blob - tree.c
Do not mistreat empty arguments to font alternating macros
[mandoc.git] / tree.c
1 /* $Id: tree.c,v 1.64 2015/04/02 22:48:18 schwarze Exp $ */
2 /*
3 * Copyright (c) 2008, 2009, 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
4 * Copyright (c) 2013, 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18 #include "config.h"
19
20 #include <sys/types.h>
21
22 #include <assert.h>
23 #include <limits.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <time.h>
27
28 #include "mandoc.h"
29 #include "roff.h"
30 #include "mdoc.h"
31 #include "man.h"
32 #include "main.h"
33
34 static void print_box(const struct eqn_box *, int);
35 static void print_man(const struct roff_node *, int);
36 static void print_mdoc(const struct roff_node *, int);
37 static void print_span(const struct tbl_span *, int);
38
39
40 void
41 tree_mdoc(void *arg, const struct mdoc *mdoc)
42 {
43
44 print_mdoc(mdoc_node(mdoc)->child, 0);
45 }
46
47 void
48 tree_man(void *arg, const struct man *man)
49 {
50
51 print_man(man_node(man)->child, 0);
52 }
53
54 static void
55 print_mdoc(const struct roff_node *n, int indent)
56 {
57 const char *p, *t;
58 int i, j;
59 size_t argc;
60 struct mdoc_argv *argv;
61
62 if (n == NULL)
63 return;
64
65 argv = NULL;
66 argc = 0;
67 t = p = NULL;
68
69 switch (n->type) {
70 case ROFFT_ROOT:
71 t = "root";
72 break;
73 case ROFFT_BLOCK:
74 t = "block";
75 break;
76 case ROFFT_HEAD:
77 t = "block-head";
78 break;
79 case ROFFT_BODY:
80 if (n->end)
81 t = "body-end";
82 else
83 t = "block-body";
84 break;
85 case ROFFT_TAIL:
86 t = "block-tail";
87 break;
88 case ROFFT_ELEM:
89 t = "elem";
90 break;
91 case ROFFT_TEXT:
92 t = "text";
93 break;
94 case ROFFT_TBL:
95 break;
96 case ROFFT_EQN:
97 t = "eqn";
98 break;
99 default:
100 abort();
101 /* NOTREACHED */
102 }
103
104 switch (n->type) {
105 case ROFFT_TEXT:
106 p = n->string;
107 break;
108 case ROFFT_BODY:
109 p = mdoc_macronames[n->tok];
110 break;
111 case ROFFT_HEAD:
112 p = mdoc_macronames[n->tok];
113 break;
114 case ROFFT_TAIL:
115 p = mdoc_macronames[n->tok];
116 break;
117 case ROFFT_ELEM:
118 p = mdoc_macronames[n->tok];
119 if (n->args) {
120 argv = n->args->argv;
121 argc = n->args->argc;
122 }
123 break;
124 case ROFFT_BLOCK:
125 p = mdoc_macronames[n->tok];
126 if (n->args) {
127 argv = n->args->argv;
128 argc = n->args->argc;
129 }
130 break;
131 case ROFFT_TBL:
132 break;
133 case ROFFT_EQN:
134 p = "EQ";
135 break;
136 case ROFFT_ROOT:
137 p = "root";
138 break;
139 default:
140 abort();
141 /* NOTREACHED */
142 }
143
144 if (n->span) {
145 assert(NULL == p && NULL == t);
146 print_span(n->span, indent);
147 } else {
148 for (i = 0; i < indent; i++)
149 putchar(' ');
150
151 printf("%s (%s)", p, t);
152
153 for (i = 0; i < (int)argc; i++) {
154 printf(" -%s", mdoc_argnames[argv[i].arg]);
155 if (argv[i].sz > 0)
156 printf(" [");
157 for (j = 0; j < (int)argv[i].sz; j++)
158 printf(" [%s]", argv[i].value[j]);
159 if (argv[i].sz > 0)
160 printf(" ]");
161 }
162
163 putchar(' ');
164 if (MDOC_LINE & n->flags)
165 putchar('*');
166 printf("%d:%d\n", n->line, n->pos + 1);
167 }
168
169 if (n->eqn)
170 print_box(n->eqn->root->first, indent + 4);
171 if (n->child)
172 print_mdoc(n->child, indent +
173 (n->type == ROFFT_BLOCK ? 2 : 4));
174 if (n->next)
175 print_mdoc(n->next, indent);
176 }
177
178 static void
179 print_man(const struct roff_node *n, int indent)
180 {
181 const char *p, *t;
182 int i;
183
184 if (n == NULL)
185 return;
186
187 t = p = NULL;
188
189 switch (n->type) {
190 case ROFFT_ROOT:
191 t = "root";
192 break;
193 case ROFFT_ELEM:
194 t = "elem";
195 break;
196 case ROFFT_TEXT:
197 t = "text";
198 break;
199 case ROFFT_BLOCK:
200 t = "block";
201 break;
202 case ROFFT_HEAD:
203 t = "block-head";
204 break;
205 case ROFFT_BODY:
206 t = "block-body";
207 break;
208 case ROFFT_TBL:
209 break;
210 case ROFFT_EQN:
211 t = "eqn";
212 break;
213 default:
214 abort();
215 /* NOTREACHED */
216 }
217
218 switch (n->type) {
219 case ROFFT_TEXT:
220 p = n->string;
221 break;
222 case ROFFT_ELEM:
223 /* FALLTHROUGH */
224 case ROFFT_BLOCK:
225 /* FALLTHROUGH */
226 case ROFFT_HEAD:
227 /* FALLTHROUGH */
228 case ROFFT_BODY:
229 p = man_macronames[n->tok];
230 break;
231 case ROFFT_ROOT:
232 p = "root";
233 break;
234 case ROFFT_TBL:
235 break;
236 case ROFFT_EQN:
237 p = "EQ";
238 break;
239 default:
240 abort();
241 /* NOTREACHED */
242 }
243
244 if (n->span) {
245 assert(NULL == p && NULL == t);
246 print_span(n->span, indent);
247 } else {
248 for (i = 0; i < indent; i++)
249 putchar(' ');
250 printf("%s (%s) ", p, t);
251 if (MAN_LINE & n->flags)
252 putchar('*');
253 printf("%d:%d\n", n->line, n->pos + 1);
254 }
255
256 if (n->eqn)
257 print_box(n->eqn->root->first, indent + 4);
258 if (n->child)
259 print_man(n->child, indent +
260 (n->type == ROFFT_BLOCK ? 2 : 4));
261 if (n->next)
262 print_man(n->next, indent);
263 }
264
265 static void
266 print_box(const struct eqn_box *ep, int indent)
267 {
268 int i;
269 const char *t;
270
271 static const char *posnames[] = {
272 NULL, "sup", "subsup", "sub",
273 "to", "from", "fromto",
274 "over", "sqrt", NULL };
275
276 if (NULL == ep)
277 return;
278 for (i = 0; i < indent; i++)
279 putchar(' ');
280
281 t = NULL;
282 switch (ep->type) {
283 case EQN_ROOT:
284 t = "eqn-root";
285 break;
286 case EQN_LISTONE:
287 case EQN_LIST:
288 t = "eqn-list";
289 break;
290 case EQN_SUBEXPR:
291 t = "eqn-expr";
292 break;
293 case EQN_TEXT:
294 t = "eqn-text";
295 break;
296 case EQN_PILE:
297 t = "eqn-pile";
298 break;
299 case EQN_MATRIX:
300 t = "eqn-matrix";
301 break;
302 }
303
304 fputs(t, stdout);
305 if (ep->pos)
306 printf(" pos=%s", posnames[ep->pos]);
307 if (ep->left)
308 printf(" left=\"%s\"", ep->left);
309 if (ep->right)
310 printf(" right=\"%s\"", ep->right);
311 if (ep->top)
312 printf(" top=\"%s\"", ep->top);
313 if (ep->bottom)
314 printf(" bottom=\"%s\"", ep->bottom);
315 if (ep->text)
316 printf(" text=\"%s\"", ep->text);
317 if (ep->font)
318 printf(" font=%d", ep->font);
319 if (ep->size != EQN_DEFSIZE)
320 printf(" size=%d", ep->size);
321 if (ep->expectargs != UINT_MAX && ep->expectargs != ep->args)
322 printf(" badargs=%zu(%zu)", ep->args, ep->expectargs);
323 else if (ep->args)
324 printf(" args=%zu", ep->args);
325 putchar('\n');
326
327 print_box(ep->first, indent + 4);
328 print_box(ep->next, indent);
329 }
330
331 static void
332 print_span(const struct tbl_span *sp, int indent)
333 {
334 const struct tbl_dat *dp;
335 int i;
336
337 for (i = 0; i < indent; i++)
338 putchar(' ');
339
340 switch (sp->pos) {
341 case TBL_SPAN_HORIZ:
342 putchar('-');
343 return;
344 case TBL_SPAN_DHORIZ:
345 putchar('=');
346 return;
347 default:
348 break;
349 }
350
351 for (dp = sp->first; dp; dp = dp->next) {
352 switch (dp->pos) {
353 case TBL_DATA_HORIZ:
354 /* FALLTHROUGH */
355 case TBL_DATA_NHORIZ:
356 putchar('-');
357 continue;
358 case TBL_DATA_DHORIZ:
359 /* FALLTHROUGH */
360 case TBL_DATA_NDHORIZ:
361 putchar('=');
362 continue;
363 default:
364 break;
365 }
366 printf("[\"%s\"", dp->string ? dp->string : "");
367 if (dp->spans)
368 printf("(%d)", dp->spans);
369 if (NULL == dp->layout)
370 putchar('*');
371 putchar(']');
372 putchar(' ');
373 }
374
375 printf("(tbl) %d:1\n", sp->line);
376 }