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