1 /* $Id: mdoc_state.c,v 1.15 2019/01/01 07:42:04 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 <stdio.h> 21 #include <stdlib.h> 22 #include <string.h> 23 24 #include "mandoc.h" 25 #include "roff.h" 26 #include "mdoc.h" 27 #include "libmandoc.h" 28 #include "roff_int.h" 29 #include "libmdoc.h" 30 31 #define STATE_ARGS struct roff_man *mdoc, struct roff_node *n 32 33 typedef void (*state_handler)(STATE_ARGS); 34 35 static void state_bl(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 NULL, /* Dl */ 48 NULL, /* 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 162 163 void 164 mdoc_state(struct roff_man *mdoc, struct roff_node *n) 165 { 166 state_handler handler; 167 168 if (n->tok == TOKEN_NONE || n->tok < ROFF_MAX) 169 return; 170 171 assert(n->tok >= MDOC_Dd && n->tok < MDOC_MAX); 172 if ((mdoc_macro(n->tok)->flags & MDOC_PROLOGUE) == 0) 173 mdoc->flags |= MDOC_PBODY; 174 175 handler = state_handlers[n->tok - MDOC_Dd]; 176 if (*handler) 177 (*handler)(mdoc, n); 178 } 179 180 static void 181 state_bl(STATE_ARGS) 182 { 183 struct mdoc_arg *args; 184 size_t i; 185 186 if (n->type != ROFFT_HEAD || n->parent->args == NULL) 187 return; 188 189 args = n->parent->args; 190 for (i = 0; i < args->argc; i++) { 191 switch(args->argv[i].arg) { 192 case MDOC_Diag: 193 n->norm->Bl.type = LIST_diag; 194 return; 195 case MDOC_Column: 196 n->norm->Bl.type = LIST_column; 197 return; 198 default: 199 break; 200 } 201 } 202 } 203 204 static void 205 state_sh(STATE_ARGS) 206 { 207 struct roff_node *nch; 208 char *secname; 209 210 if (n->type != ROFFT_HEAD) 211 return; 212 213 if ( ! (n->flags & NODE_VALID)) { 214 secname = NULL; 215 deroff(&secname, n); 216 217 /* 218 * Set the section attribute for the BLOCK, HEAD, 219 * and HEAD children; the latter can only be TEXT 220 * nodes, so no recursion is needed. For other 221 * nodes, including the .Sh BODY, this is done 222 * when allocating the node data structures, but 223 * for .Sh BLOCK and HEAD, the section is still 224 * unknown at that time. 225 */ 226 227 n->sec = n->parent->sec = secname == NULL ? 228 SEC_CUSTOM : mdoc_a2sec(secname); 229 for (nch = n->child; nch != NULL; nch = nch->next) 230 nch->sec = n->sec; 231 free(secname); 232 } 233 234 if ((mdoc->lastsec = n->sec) == SEC_SYNOPSIS) { 235 roff_setreg(mdoc->roff, "nS", 1, '='); 236 mdoc->flags |= MDOC_SYNOPSIS; 237 } else { 238 roff_setreg(mdoc->roff, "nS", 0, '='); 239 mdoc->flags &= ~MDOC_SYNOPSIS; 240 } 241 } 242 243 static void 244 state_sm(STATE_ARGS) 245 { 246 247 if (n->child == NULL) 248 mdoc->flags ^= MDOC_SMOFF; 249 else if ( ! strcmp(n->child->string, "on")) 250 mdoc->flags &= ~MDOC_SMOFF; 251 else if ( ! strcmp(n->child->string, "off")) 252 mdoc->flags |= MDOC_SMOFF; 253 } 254