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