1 /*      $Id: mdoc_state.c,v 1.9 2017/11/29 20:05:33 schwarze Exp $ */
   2 /*
   3  * Copyright (c) 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
   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  */
  17 #include <sys/types.h>
  18 
  19 #include <assert.h>
  20 #include <stdlib.h>
  21 #include <string.h>
  22 
  23 #include "mandoc.h"
  24 #include "roff.h"
  25 #include "mdoc.h"
  26 #include "libmandoc.h"
  27 #include "libmdoc.h"
  28 
  29 #define STATE_ARGS  struct roff_man *mdoc, struct roff_node *n
  30 
  31 typedef void    (*state_handler)(STATE_ARGS);
  32 
  33 static  void     state_bd(STATE_ARGS);
  34 static  void     state_bl(STATE_ARGS);
  35 static  void     state_dl(STATE_ARGS);
  36 static  void     state_sh(STATE_ARGS);
  37 static  void     state_sm(STATE_ARGS);
  38 
  39 static  const state_handler __state_handlers[MDOC_MAX - MDOC_Dd] = {
  40         NULL,           /* Dd */
  41         NULL,           /* Dt */
  42         NULL,           /* Os */
  43         state_sh,       /* Sh */
  44         NULL,           /* Ss */
  45         NULL,           /* Pp */
  46         NULL,           /* D1 */
  47         state_dl,       /* Dl */
  48         state_bd,       /* Bd */
  49         NULL,           /* Ed */
  50         state_bl,       /* Bl */
  51         NULL,           /* El */
  52         NULL,           /* It */
  53         NULL,           /* Ad */
  54         NULL,           /* An */
  55         NULL,           /* Ap */
  56         NULL,           /* Ar */
  57         NULL,           /* Cd */
  58         NULL,           /* Cm */
  59         NULL,           /* Dv */
  60         NULL,           /* Er */
  61         NULL,           /* Ev */
  62         NULL,           /* Ex */
  63         NULL,           /* Fa */
  64         NULL,           /* Fd */
  65         NULL,           /* Fl */
  66         NULL,           /* Fn */
  67         NULL,           /* Ft */
  68         NULL,           /* Ic */
  69         NULL,           /* In */
  70         NULL,           /* Li */
  71         NULL,           /* Nd */
  72         NULL,           /* Nm */
  73         NULL,           /* Op */
  74         NULL,           /* Ot */
  75         NULL,           /* Pa */
  76         NULL,           /* Rv */
  77         NULL,           /* St */
  78         NULL,           /* Va */
  79         NULL,           /* Vt */
  80         NULL,           /* Xr */
  81         NULL,           /* %A */
  82         NULL,           /* %B */
  83         NULL,           /* %D */
  84         NULL,           /* %I */
  85         NULL,           /* %J */
  86         NULL,           /* %N */
  87         NULL,           /* %O */
  88         NULL,           /* %P */
  89         NULL,           /* %R */
  90         NULL,           /* %T */
  91         NULL,           /* %V */
  92         NULL,           /* Ac */
  93         NULL,           /* Ao */
  94         NULL,           /* Aq */
  95         NULL,           /* At */
  96         NULL,           /* Bc */
  97         NULL,           /* Bf */
  98         NULL,           /* Bo */
  99         NULL,           /* Bq */
 100         NULL,           /* Bsx */
 101         NULL,           /* Bx */
 102         NULL,           /* Db */
 103         NULL,           /* Dc */
 104         NULL,           /* Do */
 105         NULL,           /* Dq */
 106         NULL,           /* Ec */
 107         NULL,           /* Ef */
 108         NULL,           /* Em */
 109         NULL,           /* Eo */
 110         NULL,           /* Fx */
 111         NULL,           /* Ms */
 112         NULL,           /* No */
 113         NULL,           /* Ns */
 114         NULL,           /* Nx */
 115         NULL,           /* Ox */
 116         NULL,           /* Pc */
 117         NULL,           /* Pf */
 118         NULL,           /* Po */
 119         NULL,           /* Pq */
 120         NULL,           /* Qc */
 121         NULL,           /* Ql */
 122         NULL,           /* Qo */
 123         NULL,           /* Qq */
 124         NULL,           /* Re */
 125         NULL,           /* Rs */
 126         NULL,           /* Sc */
 127         NULL,           /* So */
 128         NULL,           /* Sq */
 129         state_sm,       /* Sm */
 130         NULL,           /* Sx */
 131         NULL,           /* Sy */
 132         NULL,           /* Tn */
 133         NULL,           /* Ux */
 134         NULL,           /* Xc */
 135         NULL,           /* Xo */
 136         NULL,           /* Fo */
 137         NULL,           /* Fc */
 138         NULL,           /* Oo */
 139         NULL,           /* Oc */
 140         NULL,           /* Bk */
 141         NULL,           /* Ek */
 142         NULL,           /* Bt */
 143         NULL,           /* Hf */
 144         NULL,           /* Fr */
 145         NULL,           /* Ud */
 146         NULL,           /* Lb */
 147         NULL,           /* Lp */
 148         NULL,           /* Lk */
 149         NULL,           /* Mt */
 150         NULL,           /* Brq */
 151         NULL,           /* Bro */
 152         NULL,           /* Brc */
 153         NULL,           /* %C */
 154         NULL,           /* Es */
 155         NULL,           /* En */
 156         NULL,           /* Dx */
 157         NULL,           /* %Q */
 158         NULL,           /* %U */
 159         NULL,           /* Ta */
 160 };
 161 static const state_handler *const state_handlers = __state_handlers - MDOC_Dd;
 162 
 163 
 164 void
 165 mdoc_state(struct roff_man *mdoc, struct roff_node *n)
 166 {
 167         state_handler handler;
 168 
 169         if (n->tok == TOKEN_NONE || n->tok < ROFF_MAX)
 170                 return;
 171 
 172         assert(n->tok >= MDOC_Dd && n->tok < MDOC_MAX);
 173         if ( ! (mdoc_macros[n->tok].flags & MDOC_PROLOGUE))
 174                 mdoc->flags |= MDOC_PBODY;
 175 
 176         handler = state_handlers[n->tok];
 177         if (*handler)
 178                 (*handler)(mdoc, n);
 179 }
 180 
 181 void
 182 mdoc_state_reset(struct roff_man *mdoc)
 183 {
 184 
 185         roff_setreg(mdoc->roff, "nS", 0, '=');
 186         mdoc->flags = 0;
 187 }
 188 
 189 static void
 190 state_bd(STATE_ARGS)
 191 {
 192         enum mdocargt arg;
 193 
 194         if (n->type != ROFFT_HEAD &&
 195             (n->type != ROFFT_BODY || n->end != ENDBODY_NOT))
 196                 return;
 197 
 198         if (n->parent->args == NULL)
 199                 return;
 200 
 201         arg = n->parent->args->argv[0].arg;
 202         if (arg != MDOC_Literal && arg != MDOC_Unfilled)
 203                 return;
 204 
 205         state_dl(mdoc, n);
 206 }
 207 
 208 static void
 209 state_bl(STATE_ARGS)
 210 {
 211         struct mdoc_arg *args;
 212         size_t           i;
 213 
 214         if (n->type != ROFFT_HEAD || n->parent->args == NULL)
 215                 return;
 216 
 217         args = n->parent->args;
 218         for (i = 0; i < args->argc; i++) {
 219                 switch(args->argv[i].arg) {
 220                 case MDOC_Diag:
 221                         n->norm->Bl.type = LIST_diag;
 222                         return;
 223                 case MDOC_Column:
 224                         n->norm->Bl.type = LIST_column;
 225                         return;
 226                 default:
 227                         break;
 228                 }
 229         }
 230 }
 231 
 232 static void
 233 state_dl(STATE_ARGS)
 234 {
 235 
 236         switch (n->type) {
 237         case ROFFT_HEAD:
 238                 mdoc->flags |= MDOC_LITERAL;
 239                 break;
 240         case ROFFT_BODY:
 241                 mdoc->flags &= ~MDOC_LITERAL;
 242                 break;
 243         default:
 244                 break;
 245         }
 246 }
 247 
 248 static void
 249 state_sh(STATE_ARGS)
 250 {
 251         struct roff_node *nch;
 252         char             *secname;
 253 
 254         if (n->type != ROFFT_HEAD)
 255                 return;
 256 
 257         if ( ! (n->flags & NODE_VALID)) {
 258                 secname = NULL;
 259                 deroff(&secname, n);
 260 
 261                 /*
 262                  * Set the section attribute for the BLOCK, HEAD,
 263                  * and HEAD children; the latter can only be TEXT
 264                  * nodes, so no recursion is needed.  For other
 265                  * nodes, including the .Sh BODY, this is done
 266                  * when allocating the node data structures, but
 267                  * for .Sh BLOCK and HEAD, the section is still
 268                  * unknown at that time.
 269                  */
 270 
 271                 n->sec = n->parent->sec = secname == NULL ?
 272                     SEC_CUSTOM : mdoc_a2sec(secname);
 273                 for (nch = n->child; nch != NULL; nch = nch->next)
 274                         nch->sec = n->sec;
 275                 free(secname);
 276         }
 277 
 278         if ((mdoc->lastsec = n->sec) == SEC_SYNOPSIS) {
 279                 roff_setreg(mdoc->roff, "nS", 1, '=');
 280                 mdoc->flags |= MDOC_SYNOPSIS;
 281         } else {
 282                 roff_setreg(mdoc->roff, "nS", 0, '=');
 283                 mdoc->flags &= ~MDOC_SYNOPSIS;
 284         }
 285 }
 286 
 287 static void
 288 state_sm(STATE_ARGS)
 289 {
 290 
 291         if (n->child == NULL)
 292                 mdoc->flags ^= MDOC_SMOFF;
 293         else if ( ! strcmp(n->child->string, "on"))
 294                 mdoc->flags &= ~MDOC_SMOFF;
 295         else if ( ! strcmp(n->child->string, "off"))
 296                 mdoc->flags |= MDOC_SMOFF;
 297 }