Import mandoc-1.14.6.
[dragonfly.git] / contrib / mdocml / tree.c
1 /* $Id: tree.c,v 1.91 2021/09/07 10:59:18 schwarze Exp $ */
2 /*
3  * Copyright (c) 2008, 2009, 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
4  * Copyright (c) 2013-2015, 2017-2021 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  * Formatting module to let mandoc(1) show
19  * a human readable representation of the syntax tree.
20  */
21 #include "config.h"
22
23 #include <sys/types.h>
24
25 #include <assert.h>
26 #include <limits.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <time.h>
30
31 #include "mandoc.h"
32 #include "roff.h"
33 #include "mdoc.h"
34 #include "man.h"
35 #include "tbl.h"
36 #include "eqn.h"
37 #include "main.h"
38
39 static  void    print_attr(const struct roff_node *);
40 static  void    print_box(const struct eqn_box *, int);
41 static  void    print_cellt(enum tbl_cellt);
42 static  void    print_man(const struct roff_node *, int);
43 static  void    print_meta(const struct roff_meta *);
44 static  void    print_mdoc(const struct roff_node *, int);
45 static  void    print_span(const struct tbl_span *, int);
46
47
48 void
49 tree_mdoc(void *arg, const struct roff_meta *mdoc)
50 {
51         print_meta(mdoc);
52         putchar('\n');
53         print_mdoc(mdoc->first->child, 0);
54 }
55
56 void
57 tree_man(void *arg, const struct roff_meta *man)
58 {
59         print_meta(man);
60         if (man->hasbody == 0)
61                 puts("body  = empty");
62         putchar('\n');
63         print_man(man->first->child, 0);
64 }
65
66 static void
67 print_meta(const struct roff_meta *meta)
68 {
69         if (meta->title != NULL)
70                 printf("title = \"%s\"\n", meta->title);
71         if (meta->name != NULL)
72                 printf("name  = \"%s\"\n", meta->name);
73         if (meta->msec != NULL)
74                 printf("sec   = \"%s\"\n", meta->msec);
75         if (meta->vol != NULL)
76                 printf("vol   = \"%s\"\n", meta->vol);
77         if (meta->arch != NULL)
78                 printf("arch  = \"%s\"\n", meta->arch);
79         if (meta->os != NULL)
80                 printf("os    = \"%s\"\n", meta->os);
81         if (meta->date != NULL)
82                 printf("date  = \"%s\"\n", meta->date);
83 }
84
85 static void
86 print_mdoc(const struct roff_node *n, int indent)
87 {
88         const char       *p, *t;
89         int               i, j;
90         size_t            argc;
91         struct mdoc_argv *argv;
92
93         if (n == NULL)
94                 return;
95
96         argv = NULL;
97         argc = 0;
98         t = p = NULL;
99
100         switch (n->type) {
101         case ROFFT_ROOT:
102                 t = "root";
103                 break;
104         case ROFFT_BLOCK:
105                 t = "block";
106                 break;
107         case ROFFT_HEAD:
108                 t = "head";
109                 break;
110         case ROFFT_BODY:
111                 if (n->end)
112                         t = "body-end";
113                 else
114                         t = "body";
115                 break;
116         case ROFFT_TAIL:
117                 t = "tail";
118                 break;
119         case ROFFT_ELEM:
120                 t = "elem";
121                 break;
122         case ROFFT_TEXT:
123                 t = "text";
124                 break;
125         case ROFFT_COMMENT:
126                 t = "comment";
127                 break;
128         case ROFFT_TBL:
129                 break;
130         case ROFFT_EQN:
131                 t = "eqn";
132                 break;
133         default:
134                 abort();
135         }
136
137         switch (n->type) {
138         case ROFFT_TEXT:
139         case ROFFT_COMMENT:
140                 p = n->string;
141                 break;
142         case ROFFT_BODY:
143                 p = roff_name[n->tok];
144                 break;
145         case ROFFT_HEAD:
146                 p = roff_name[n->tok];
147                 break;
148         case ROFFT_TAIL:
149                 p = roff_name[n->tok];
150                 break;
151         case ROFFT_ELEM:
152                 p = roff_name[n->tok];
153                 if (n->args) {
154                         argv = n->args->argv;
155                         argc = n->args->argc;
156                 }
157                 break;
158         case ROFFT_BLOCK:
159                 p = roff_name[n->tok];
160                 if (n->args) {
161                         argv = n->args->argv;
162                         argc = n->args->argc;
163                 }
164                 break;
165         case ROFFT_TBL:
166                 break;
167         case ROFFT_EQN:
168                 p = "EQ";
169                 break;
170         case ROFFT_ROOT:
171                 p = "root";
172                 break;
173         default:
174                 abort();
175         }
176
177         if (n->span) {
178                 assert(NULL == p && NULL == t);
179                 print_span(n->span, indent);
180         } else {
181                 for (i = 0; i < indent; i++)
182                         putchar(' ');
183
184                 printf("%s (%s)", p, t);
185
186                 for (i = 0; i < (int)argc; i++) {
187                         printf(" -%s", mdoc_argnames[argv[i].arg]);
188                         if (argv[i].sz > 0)
189                                 printf(" [");
190                         for (j = 0; j < (int)argv[i].sz; j++)
191                                 printf(" [%s]", argv[i].value[j]);
192                         if (argv[i].sz > 0)
193                                 printf(" ]");
194                 }
195                 print_attr(n);
196         }
197         if (n->eqn)
198                 print_box(n->eqn->first, indent + 4);
199         if (n->child)
200                 print_mdoc(n->child, indent +
201                     (n->type == ROFFT_BLOCK ? 2 : 4));
202         if (n->next)
203                 print_mdoc(n->next, indent);
204 }
205
206 static void
207 print_man(const struct roff_node *n, int indent)
208 {
209         const char       *p, *t;
210         int               i;
211
212         if (n == NULL)
213                 return;
214
215         t = p = NULL;
216
217         switch (n->type) {
218         case ROFFT_ROOT:
219                 t = "root";
220                 break;
221         case ROFFT_ELEM:
222                 t = "elem";
223                 break;
224         case ROFFT_TEXT:
225                 t = "text";
226                 break;
227         case ROFFT_COMMENT:
228                 t = "comment";
229                 break;
230         case ROFFT_BLOCK:
231                 t = "block";
232                 break;
233         case ROFFT_HEAD:
234                 t = "head";
235                 break;
236         case ROFFT_BODY:
237                 t = "body";
238                 break;
239         case ROFFT_TBL:
240                 break;
241         case ROFFT_EQN:
242                 t = "eqn";
243                 break;
244         default:
245                 abort();
246         }
247
248         switch (n->type) {
249         case ROFFT_TEXT:
250         case ROFFT_COMMENT:
251                 p = n->string;
252                 break;
253         case ROFFT_ELEM:
254         case ROFFT_BLOCK:
255         case ROFFT_HEAD:
256         case ROFFT_BODY:
257                 p = roff_name[n->tok];
258                 break;
259         case ROFFT_ROOT:
260                 p = "root";
261                 break;
262         case ROFFT_TBL:
263                 break;
264         case ROFFT_EQN:
265                 p = "EQ";
266                 break;
267         default:
268                 abort();
269         }
270
271         if (n->span) {
272                 assert(NULL == p && NULL == t);
273                 print_span(n->span, indent);
274         } else {
275                 for (i = 0; i < indent; i++)
276                         putchar(' ');
277                 printf("%s (%s)", p, t);
278                 print_attr(n);
279         }
280         if (n->eqn)
281                 print_box(n->eqn->first, indent + 4);
282         if (n->child)
283                 print_man(n->child, indent +
284                     (n->type == ROFFT_BLOCK ? 2 : 4));
285         if (n->next)
286                 print_man(n->next, indent);
287 }
288
289 static void
290 print_attr(const struct roff_node *n)
291 {
292         putchar(' ');
293         if (n->flags & NODE_DELIMO)
294                 putchar('(');
295         if (n->flags & NODE_LINE)
296                 putchar('*');
297         printf("%d:%d", n->line, n->pos + 1);
298         if (n->flags & NODE_DELIMC)
299                 putchar(')');
300         if (n->flags & NODE_EOS)
301                 putchar('.');
302         if (n->flags & NODE_ID) {
303                 printf(" ID");
304                 if (n->flags & NODE_HREF)
305                         printf("=HREF");
306         } else if (n->flags & NODE_HREF)
307                 printf(" HREF");
308         else if (n->tag != NULL)
309                 printf(" STRAYTAG");
310         if (n->tag != NULL)
311                 printf("=%s", n->tag);
312         if (n->flags & NODE_BROKEN)
313                 printf(" BROKEN");
314         if (n->flags & NODE_NOFILL)
315                 printf(" NOFILL");
316         if (n->flags & NODE_NOSRC)
317                 printf(" NOSRC");
318         if (n->flags & NODE_NOPRT)
319                 printf(" NOPRT");
320         putchar('\n');
321 }
322
323 static void
324 print_box(const struct eqn_box *ep, int indent)
325 {
326         int              i;
327         const char      *t;
328
329         static const char *posnames[] = {
330             NULL, "sup", "subsup", "sub",
331             "to", "from", "fromto",
332             "over", "sqrt", NULL };
333
334         if (NULL == ep)
335                 return;
336         for (i = 0; i < indent; i++)
337                 putchar(' ');
338
339         t = NULL;
340         switch (ep->type) {
341         case EQN_LIST:
342                 t = "eqn-list";
343                 break;
344         case EQN_SUBEXPR:
345                 t = "eqn-expr";
346                 break;
347         case EQN_TEXT:
348                 t = "eqn-text";
349                 break;
350         case EQN_PILE:
351                 t = "eqn-pile";
352                 break;
353         case EQN_MATRIX:
354                 t = "eqn-matrix";
355                 break;
356         }
357
358         fputs(t, stdout);
359         if (ep->pos)
360                 printf(" pos=%s", posnames[ep->pos]);
361         if (ep->left)
362                 printf(" left=\"%s\"", ep->left);
363         if (ep->right)
364                 printf(" right=\"%s\"", ep->right);
365         if (ep->top)
366                 printf(" top=\"%s\"", ep->top);
367         if (ep->bottom)
368                 printf(" bottom=\"%s\"", ep->bottom);
369         if (ep->text)
370                 printf(" text=\"%s\"", ep->text);
371         if (ep->font)
372                 printf(" font=%d", ep->font);
373         if (ep->size != EQN_DEFSIZE)
374                 printf(" size=%d", ep->size);
375         if (ep->expectargs != UINT_MAX && ep->expectargs != ep->args)
376                 printf(" badargs=%zu(%zu)", ep->args, ep->expectargs);
377         else if (ep->args)
378                 printf(" args=%zu", ep->args);
379         putchar('\n');
380
381         print_box(ep->first, indent + 4);
382         print_box(ep->next, indent);
383 }
384
385 static void
386 print_cellt(enum tbl_cellt pos)
387 {
388         switch(pos) {
389         case TBL_CELL_LEFT:
390                 putchar('L');
391                 break;
392         case TBL_CELL_LONG:
393                 putchar('a');
394                 break;
395         case TBL_CELL_CENTRE:
396                 putchar('c');
397                 break;
398         case TBL_CELL_RIGHT:
399                 putchar('r');
400                 break;
401         case TBL_CELL_NUMBER:
402                 putchar('n');
403                 break;
404         case TBL_CELL_SPAN:
405                 putchar('s');
406                 break;
407         case TBL_CELL_DOWN:
408                 putchar('^');
409                 break;
410         case TBL_CELL_HORIZ:
411                 putchar('-');
412                 break;
413         case TBL_CELL_DHORIZ:
414                 putchar('=');
415                 break;
416         case TBL_CELL_MAX:
417                 putchar('#');
418                 break;
419         }
420 }
421
422 static void
423 print_span(const struct tbl_span *sp, int indent)
424 {
425         const struct tbl_dat *dp;
426         const struct tbl_cell *cp;
427         int              i;
428
429         if (sp->prev == NULL) {
430                 for (i = 0; i < indent; i++)
431                         putchar(' ');
432                 printf("%d", sp->opts->cols);
433                 if (sp->opts->opts & TBL_OPT_CENTRE)
434                         fputs(" center", stdout);
435                 if (sp->opts->opts & TBL_OPT_EXPAND)
436                         fputs(" expand", stdout);
437                 if (sp->opts->opts & TBL_OPT_ALLBOX)
438                         fputs(" allbox", stdout);
439                 if (sp->opts->opts & TBL_OPT_BOX)
440                         fputs(" box", stdout);
441                 if (sp->opts->opts & TBL_OPT_DBOX)
442                         fputs(" doublebox", stdout);
443                 if (sp->opts->opts & TBL_OPT_NOKEEP)
444                         fputs(" nokeep", stdout);
445                 if (sp->opts->opts & TBL_OPT_NOSPACE)
446                         fputs(" nospaces", stdout);
447                 if (sp->opts->opts & TBL_OPT_NOWARN)
448                         fputs(" nowarn", stdout);
449                 printf(" (tbl options) %d:1\n", sp->line);
450         }
451
452         for (i = 0; i < indent; i++)
453                 putchar(' ');
454
455         switch (sp->pos) {
456         case TBL_SPAN_HORIZ:
457                 putchar('-');
458                 putchar(' ');
459                 break;
460         case TBL_SPAN_DHORIZ:
461                 putchar('=');
462                 putchar(' ');
463                 break;
464         default:
465                 for (cp = sp->layout->first; cp != NULL; cp = cp->next)
466                         print_cellt(cp->pos);
467                 putchar(' ');
468                 for (dp = sp->first; dp; dp = dp->next) {
469                         if ((cp = dp->layout) == NULL)
470                                 putchar('*');
471                         else {
472                                 printf("%d", cp->col);
473                                 print_cellt(dp->layout->pos);
474                                 switch (cp->font) {
475                                 case ESCAPE_FONTROMAN:
476                                         break;
477                                 case ESCAPE_FONTBOLD:
478                                         putchar('b');
479                                         break;
480                                 case ESCAPE_FONTITALIC:
481                                         putchar('i');
482                                         break;
483                                 case ESCAPE_FONTBI:
484                                         fputs("bi", stdout);
485                                         break;
486                                 case ESCAPE_FONTCR:
487                                         putchar('c');
488                                         break;
489                                 case ESCAPE_FONTCB:
490                                         fputs("cb", stdout);
491                                         break;
492                                 case ESCAPE_FONTCI:
493                                         fputs("ci", stdout);
494                                         break;
495                                 default:
496                                         abort();
497                                 }
498                                 if (cp->flags & TBL_CELL_TALIGN)
499                                         putchar('t');
500                                 if (cp->flags & TBL_CELL_UP)
501                                         putchar('u');
502                                 if (cp->flags & TBL_CELL_BALIGN)
503                                         putchar('d');
504                                 if (cp->flags & TBL_CELL_WIGN)
505                                         putchar('z');
506                                 if (cp->flags & TBL_CELL_EQUAL)
507                                         putchar('e');
508                                 if (cp->flags & TBL_CELL_WMAX)
509                                         putchar('x');
510                         }
511                         switch (dp->pos) {
512                         case TBL_DATA_HORIZ:
513                         case TBL_DATA_NHORIZ:
514                                 putchar('-');
515                                 break;
516                         case TBL_DATA_DHORIZ:
517                         case TBL_DATA_NDHORIZ:
518                                 putchar('=');
519                                 break;
520                         default:
521                                 putchar(dp->block ? '{' : '[');
522                                 if (dp->string != NULL)
523                                         fputs(dp->string, stdout);
524                                 putchar(dp->block ? '}' : ']');
525                                 break;
526                         }
527                         if (dp->hspans)
528                                 printf(">%d", dp->hspans);
529                         if (dp->vspans)
530                                 printf("v%d", dp->vspans);
531                         putchar(' ');
532                 }
533                 break;
534         }
535         printf("(tbl) %d:1\n", sp->line);
536 }