1 /*      $Id: tree.c,v 1.78 2018/04/11 17:11:13 schwarze Exp $ */
   2 /*
   3  * Copyright (c) 2008, 2009, 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
   4  * Copyright (c) 2013,2014,2015,2017,2018 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_meta(const struct roff_meta *);
  37 static  void    print_mdoc(const struct roff_node *, int);
  38 static  void    print_span(const struct tbl_span *, int);
  39 
  40 
  41 void
  42 tree_mdoc(void *arg, const struct roff_man *mdoc)
  43 {
  44         print_meta(&mdoc->meta);
  45         putchar('\n');
  46         print_mdoc(mdoc->first->child, 0);
  47 }
  48 
  49 void
  50 tree_man(void *arg, const struct roff_man *man)
  51 {
  52         print_meta(&man->meta);
  53         if (man->meta.hasbody == 0)
  54                 puts("body  = empty");
  55         putchar('\n');
  56         print_man(man->first->child, 0);
  57 }
  58 
  59 static void
  60 print_meta(const struct roff_meta *meta)
  61 {
  62         if (meta->title != NULL)
  63                 printf("title = \"%s\"\n", meta->title);
  64         if (meta->name != NULL)
  65                 printf("name  = \"%s\"\n", meta->name);
  66         if (meta->msec != NULL)
  67                 printf("sec   = \"%s\"\n", meta->msec);
  68         if (meta->vol != NULL)
  69                 printf("vol   = \"%s\"\n", meta->vol);
  70         if (meta->arch != NULL)
  71                 printf("arch  = \"%s\"\n", meta->arch);
  72         if (meta->os != NULL)
  73                 printf("os    = \"%s\"\n", meta->os);
  74         if (meta->date != NULL)
  75                 printf("date  = \"%s\"\n", meta->date);
  76 }
  77 
  78 static void
  79 print_mdoc(const struct roff_node *n, int indent)
  80 {
  81         const char       *p, *t;
  82         int               i, j;
  83         size_t            argc;
  84         struct mdoc_argv *argv;
  85 
  86         if (n == NULL)
  87                 return;
  88 
  89         argv = NULL;
  90         argc = 0;
  91         t = p = NULL;
  92 
  93         switch (n->type) {
  94         case ROFFT_ROOT:
  95                 t = "root";
  96                 break;
  97         case ROFFT_BLOCK:
  98                 t = "block";
  99                 break;
 100         case ROFFT_HEAD:
 101                 t = "head";
 102                 break;
 103         case ROFFT_BODY:
 104                 if (n->end)
 105                         t = "body-end";
 106                 else
 107                         t = "body";
 108                 break;
 109         case ROFFT_TAIL:
 110                 t = "tail";
 111                 break;
 112         case ROFFT_ELEM:
 113                 t = "elem";
 114                 break;
 115         case ROFFT_TEXT:
 116                 t = "text";
 117                 break;
 118         case ROFFT_COMMENT:
 119                 t = "comment";
 120                 break;
 121         case ROFFT_TBL:
 122                 break;
 123         case ROFFT_EQN:
 124                 t = "eqn";
 125                 break;
 126         default:
 127                 abort();
 128         }
 129 
 130         switch (n->type) {
 131         case ROFFT_TEXT:
 132         case ROFFT_COMMENT:
 133                 p = n->string;
 134                 break;
 135         case ROFFT_BODY:
 136                 p = roff_name[n->tok];
 137                 break;
 138         case ROFFT_HEAD:
 139                 p = roff_name[n->tok];
 140                 break;
 141         case ROFFT_TAIL:
 142                 p = roff_name[n->tok];
 143                 break;
 144         case ROFFT_ELEM:
 145                 p = roff_name[n->tok];
 146                 if (n->args) {
 147                         argv = n->args->argv;
 148                         argc = n->args->argc;
 149                 }
 150                 break;
 151         case ROFFT_BLOCK:
 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_TBL:
 159                 break;
 160         case ROFFT_EQN:
 161                 p = "EQ";
 162                 break;
 163         case ROFFT_ROOT:
 164                 p = "root";
 165                 break;
 166         default:
 167                 abort();
 168         }
 169 
 170         if (n->span) {
 171                 assert(NULL == p && NULL == t);
 172                 print_span(n->span, indent);
 173         } else {
 174                 for (i = 0; i < indent; i++)
 175                         putchar(' ');
 176 
 177                 printf("%s (%s)", p, t);
 178 
 179                 for (i = 0; i < (int)argc; i++) {
 180                         printf(" -%s", mdoc_argnames[argv[i].arg]);
 181                         if (argv[i].sz > 0)
 182                                 printf(" [");
 183                         for (j = 0; j < (int)argv[i].sz; j++)
 184                                 printf(" [%s]", argv[i].value[j]);
 185                         if (argv[i].sz > 0)
 186                                 printf(" ]");
 187                 }
 188 
 189                 putchar(' ');
 190                 if (NODE_DELIMO & n->flags)
 191                         putchar('(');
 192                 if (NODE_LINE & n->flags)
 193                         putchar('*');
 194                 printf("%d:%d", n->line, n->pos + 1);
 195                 if (NODE_DELIMC & n->flags)
 196                         putchar(')');
 197                 if (NODE_EOS & n->flags)
 198                         putchar('.');
 199                 if (NODE_BROKEN & n->flags)
 200                         printf(" BROKEN");
 201                 if (NODE_NOSRC & n->flags)
 202                         printf(" NOSRC");
 203                 if (NODE_NOPRT & n->flags)
 204                         printf(" NOPRT");
 205                 putchar('\n');
 206         }
 207 
 208         if (n->eqn)
 209                 print_box(n->eqn->first, indent + 4);
 210         if (n->child)
 211                 print_mdoc(n->child, indent +
 212                     (n->type == ROFFT_BLOCK ? 2 : 4));
 213         if (n->next)
 214                 print_mdoc(n->next, indent);
 215 }
 216 
 217 static void
 218 print_man(const struct roff_node *n, int indent)
 219 {
 220         const char       *p, *t;
 221         int               i;
 222 
 223         if (n == NULL)
 224                 return;
 225 
 226         t = p = NULL;
 227 
 228         switch (n->type) {
 229         case ROFFT_ROOT:
 230                 t = "root";
 231                 break;
 232         case ROFFT_ELEM:
 233                 t = "elem";
 234                 break;
 235         case ROFFT_TEXT:
 236                 t = "text";
 237                 break;
 238         case ROFFT_COMMENT:
 239                 t = "comment";
 240                 break;
 241         case ROFFT_BLOCK:
 242                 t = "block";
 243                 break;
 244         case ROFFT_HEAD:
 245                 t = "head";
 246                 break;
 247         case ROFFT_BODY:
 248                 t = "body";
 249                 break;
 250         case ROFFT_TBL:
 251                 break;
 252         case ROFFT_EQN:
 253                 t = "eqn";
 254                 break;
 255         default:
 256                 abort();
 257         }
 258 
 259         switch (n->type) {
 260         case ROFFT_TEXT:
 261         case ROFFT_COMMENT:
 262                 p = n->string;
 263                 break;
 264         case ROFFT_ELEM:
 265         case ROFFT_BLOCK:
 266         case ROFFT_HEAD:
 267         case ROFFT_BODY:
 268                 p = roff_name[n->tok];
 269                 break;
 270         case ROFFT_ROOT:
 271                 p = "root";
 272                 break;
 273         case ROFFT_TBL:
 274                 break;
 275         case ROFFT_EQN:
 276                 p = "EQ";
 277                 break;
 278         default:
 279                 abort();
 280         }
 281 
 282         if (n->span) {
 283                 assert(NULL == p && NULL == t);
 284                 print_span(n->span, indent);
 285         } else {
 286                 for (i = 0; i < indent; i++)
 287                         putchar(' ');
 288                 printf("%s (%s) ", p, t);
 289                 if (NODE_LINE & n->flags)
 290                         putchar('*');
 291                 printf("%d:%d", n->line, n->pos + 1);
 292                 if (NODE_EOS & n->flags)
 293                         putchar('.');
 294                 putchar('\n');
 295         }
 296 
 297         if (n->eqn)
 298                 print_box(n->eqn->first, indent + 4);
 299         if (n->child)
 300                 print_man(n->child, indent +
 301                     (n->type == ROFFT_BLOCK ? 2 : 4));
 302         if (n->next)
 303                 print_man(n->next, indent);
 304 }
 305 
 306 static void
 307 print_box(const struct eqn_box *ep, int indent)
 308 {
 309         int              i;
 310         const char      *t;
 311 
 312         static const char *posnames[] = {
 313             NULL, "sup", "subsup", "sub",
 314             "to", "from", "fromto",
 315             "over", "sqrt", NULL };
 316 
 317         if (NULL == ep)
 318                 return;
 319         for (i = 0; i < indent; i++)
 320                 putchar(' ');
 321 
 322         t = NULL;
 323         switch (ep->type) {
 324         case EQN_LIST:
 325                 t = "eqn-list";
 326                 break;
 327         case EQN_SUBEXPR:
 328                 t = "eqn-expr";
 329                 break;
 330         case EQN_TEXT:
 331                 t = "eqn-text";
 332                 break;
 333         case EQN_PILE:
 334                 t = "eqn-pile";
 335                 break;
 336         case EQN_MATRIX:
 337                 t = "eqn-matrix";
 338                 break;
 339         }
 340 
 341         fputs(t, stdout);
 342         if (ep->pos)
 343                 printf(" pos=%s", posnames[ep->pos]);
 344         if (ep->left)
 345                 printf(" left=\"%s\"", ep->left);
 346         if (ep->right)
 347                 printf(" right=\"%s\"", ep->right);
 348         if (ep->top)
 349                 printf(" top=\"%s\"", ep->top);
 350         if (ep->bottom)
 351                 printf(" bottom=\"%s\"", ep->bottom);
 352         if (ep->text)
 353                 printf(" text=\"%s\"", ep->text);
 354         if (ep->font)
 355                 printf(" font=%d", ep->font);
 356         if (ep->size != EQN_DEFSIZE)
 357                 printf(" size=%d", ep->size);
 358         if (ep->expectargs != UINT_MAX && ep->expectargs != ep->args)
 359                 printf(" badargs=%zu(%zu)", ep->args, ep->expectargs);
 360         else if (ep->args)
 361                 printf(" args=%zu", ep->args);
 362         putchar('\n');
 363 
 364         print_box(ep->first, indent + 4);
 365         print_box(ep->next, indent);
 366 }
 367 
 368 static void
 369 print_span(const struct tbl_span *sp, int indent)
 370 {
 371         const struct tbl_dat *dp;
 372         int              i;
 373 
 374         for (i = 0; i < indent; i++)
 375                 putchar(' ');
 376 
 377         switch (sp->pos) {
 378         case TBL_SPAN_HORIZ:
 379                 putchar('-');
 380                 return;
 381         case TBL_SPAN_DHORIZ:
 382                 putchar('=');
 383                 return;
 384         default:
 385                 break;
 386         }
 387 
 388         for (dp = sp->first; dp; dp = dp->next) {
 389                 switch (dp->pos) {
 390                 case TBL_DATA_HORIZ:
 391                 case TBL_DATA_NHORIZ:
 392                         putchar('-');
 393                         continue;
 394                 case TBL_DATA_DHORIZ:
 395                 case TBL_DATA_NDHORIZ:
 396                         putchar('=');
 397                         continue;
 398                 default:
 399                         break;
 400                 }
 401                 printf("[\"%s\"", dp->string ? dp->string : "");
 402                 if (dp->spans)
 403                         printf("(%d)", dp->spans);
 404                 if (NULL == dp->layout)
 405                         putchar('*');
 406                 putchar(']');
 407                 putchar(' ');
 408         }
 409 
 410         printf("(tbl) %d:1\n", sp->line);
 411 }