xref: /dragonfly/contrib/mdocml/tree.c (revision 1e4d43f9c96723e4e55543d240f182e1aac9a4c2)
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
tree_mdoc(void * arg,const struct roff_meta * mdoc)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
tree_man(void * arg,const struct roff_meta * man)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
print_meta(const struct roff_meta * meta)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
print_mdoc(const struct roff_node * n,int indent)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
print_man(const struct roff_node * n,int indent)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
print_attr(const struct roff_node * n)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
print_box(const struct eqn_box * ep,int indent)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
print_cellt(enum tbl_cellt pos)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
print_span(const struct tbl_span * sp,int indent)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 }
537