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 } 298