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