1 /* $OpenBSD: man_macro.c,v 1.71 2015/04/23 15:35:39 schwarze Exp $ */ 2 /* 3 * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> 4 * Copyright (c) 2012, 2013, 2014, 2015 Ingo Schwarze <schwarze@openbsd.org> 5 * Copyright (c) 2013 Franco Fichtner <franco@lastsummer.de> 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 #include <sys/types.h> 20 21 #include <assert.h> 22 #include <ctype.h> 23 #include <stdlib.h> 24 #include <string.h> 25 26 #include "mandoc.h" 27 #include "roff.h" 28 #include "man.h" 29 #include "libmandoc.h" 30 #include "roff_int.h" 31 #include "libman.h" 32 33 static void blk_close(MACRO_PROT_ARGS); 34 static void blk_exp(MACRO_PROT_ARGS); 35 static void blk_imp(MACRO_PROT_ARGS); 36 static void in_line_eoln(MACRO_PROT_ARGS); 37 static int man_args(struct roff_man *, int, 38 int *, char *, char **); 39 static void rew_scope(struct roff_man *, int); 40 41 const struct man_macro __man_macros[MAN_MAX] = { 42 { in_line_eoln, MAN_NSCOPED }, /* br */ 43 { in_line_eoln, MAN_BSCOPE }, /* TH */ 44 { blk_imp, MAN_BSCOPE | MAN_SCOPED }, /* SH */ 45 { blk_imp, MAN_BSCOPE | MAN_SCOPED }, /* SS */ 46 { blk_imp, MAN_BSCOPE | MAN_SCOPED }, /* TP */ 47 { blk_imp, MAN_BSCOPE }, /* LP */ 48 { blk_imp, MAN_BSCOPE }, /* PP */ 49 { blk_imp, MAN_BSCOPE }, /* P */ 50 { blk_imp, MAN_BSCOPE }, /* IP */ 51 { blk_imp, MAN_BSCOPE }, /* HP */ 52 { in_line_eoln, MAN_SCOPED | MAN_JOIN }, /* SM */ 53 { in_line_eoln, MAN_SCOPED | MAN_JOIN }, /* SB */ 54 { in_line_eoln, 0 }, /* BI */ 55 { in_line_eoln, 0 }, /* IB */ 56 { in_line_eoln, 0 }, /* BR */ 57 { in_line_eoln, 0 }, /* RB */ 58 { in_line_eoln, MAN_SCOPED | MAN_JOIN }, /* R */ 59 { in_line_eoln, MAN_SCOPED | MAN_JOIN }, /* B */ 60 { in_line_eoln, MAN_SCOPED | MAN_JOIN }, /* I */ 61 { in_line_eoln, 0 }, /* IR */ 62 { in_line_eoln, 0 }, /* RI */ 63 { in_line_eoln, MAN_NSCOPED }, /* sp */ 64 { in_line_eoln, MAN_BSCOPE }, /* nf */ 65 { in_line_eoln, MAN_BSCOPE }, /* fi */ 66 { blk_close, MAN_BSCOPE }, /* RE */ 67 { blk_exp, MAN_BSCOPE }, /* RS */ 68 { in_line_eoln, 0 }, /* DT */ 69 { in_line_eoln, 0 }, /* UC */ 70 { in_line_eoln, MAN_NSCOPED }, /* PD */ 71 { in_line_eoln, 0 }, /* AT */ 72 { in_line_eoln, 0 }, /* in */ 73 { in_line_eoln, 0 }, /* ft */ 74 { in_line_eoln, 0 }, /* OP */ 75 { in_line_eoln, MAN_BSCOPE }, /* EX */ 76 { in_line_eoln, MAN_BSCOPE }, /* EE */ 77 { blk_exp, MAN_BSCOPE }, /* UR */ 78 { blk_close, MAN_BSCOPE }, /* UE */ 79 { in_line_eoln, 0 }, /* ll */ 80 }; 81 82 const struct man_macro * const man_macros = __man_macros; 83 84 85 void 86 man_unscope(struct roff_man *man, const struct roff_node *to) 87 { 88 struct roff_node *n; 89 90 to = to->parent; 91 n = man->last; 92 while (n != to) { 93 94 /* Reached the end of the document? */ 95 96 if (to == NULL && ! (n->flags & MAN_VALID)) { 97 if (man->flags & (MAN_BLINE | MAN_ELINE) && 98 man_macros[n->tok].flags & MAN_SCOPED) { 99 mandoc_vmsg(MANDOCERR_BLK_LINE, 100 man->parse, n->line, n->pos, 101 "EOF breaks %s", 102 man_macronames[n->tok]); 103 if (man->flags & MAN_ELINE) 104 man->flags &= ~MAN_ELINE; 105 else { 106 assert(n->type == ROFFT_HEAD); 107 n = n->parent; 108 man->flags &= ~MAN_BLINE; 109 } 110 man->last = n; 111 n = n->parent; 112 roff_node_delete(man, man->last); 113 continue; 114 } 115 if (n->type == ROFFT_BLOCK && 116 man_macros[n->tok].fp == blk_exp) 117 mandoc_msg(MANDOCERR_BLK_NOEND, 118 man->parse, n->line, n->pos, 119 man_macronames[n->tok]); 120 } 121 122 /* 123 * We might delete the man->last node 124 * in the post-validation phase. 125 * Save a pointer to the parent such that 126 * we know where to continue the iteration. 127 */ 128 129 man->last = n; 130 n = n->parent; 131 man_valid_post(man); 132 } 133 134 /* 135 * If we ended up at the parent of the node we were 136 * supposed to rewind to, that means the target node 137 * got deleted, so add the next node we parse as a child 138 * of the parent instead of as a sibling of the target. 139 */ 140 141 man->next = (man->last == to) ? 142 ROFF_NEXT_CHILD : ROFF_NEXT_SIBLING; 143 } 144 145 /* 146 * Rewinding entails ascending the parse tree until a coherent point, 147 * for example, the `SH' macro will close out any intervening `SS' 148 * scopes. When a scope is closed, it must be validated and actioned. 149 */ 150 static void 151 rew_scope(struct roff_man *man, int tok) 152 { 153 struct roff_node *n; 154 155 /* Preserve empty paragraphs before RS. */ 156 157 n = man->last; 158 if (tok == MAN_RS && n->nchild == 0 && 159 (n->tok == MAN_P || n->tok == MAN_PP || n->tok == MAN_LP)) 160 return; 161 162 for (;;) { 163 if (n->type == ROFFT_ROOT) 164 return; 165 if (n->flags & MAN_VALID) { 166 n = n->parent; 167 continue; 168 } 169 if (n->type != ROFFT_BLOCK) { 170 if (n->parent->type == ROFFT_ROOT) { 171 man_unscope(man, n); 172 return; 173 } else { 174 n = n->parent; 175 continue; 176 } 177 } 178 if (tok != MAN_SH && (n->tok == MAN_SH || 179 (tok != MAN_SS && (n->tok == MAN_SS || 180 man_macros[n->tok].fp == blk_exp)))) 181 return; 182 man_unscope(man, n); 183 n = man->last; 184 } 185 } 186 187 188 /* 189 * Close out a generic explicit macro. 190 */ 191 void 192 blk_close(MACRO_PROT_ARGS) 193 { 194 int ntok; 195 const struct roff_node *nn; 196 char *p; 197 int nrew, target; 198 199 nrew = 1; 200 switch (tok) { 201 case MAN_RE: 202 ntok = MAN_RS; 203 if ( ! man_args(man, line, pos, buf, &p)) 204 break; 205 for (nn = man->last->parent; nn; nn = nn->parent) 206 if (nn->tok == ntok && nn->type == ROFFT_BLOCK) 207 nrew++; 208 target = strtol(p, &p, 10); 209 if (*p != '\0') 210 mandoc_vmsg(MANDOCERR_ARG_EXCESS, man->parse, 211 line, p - buf, "RE ... %s", p); 212 if (target == 0) 213 target = 1; 214 nrew -= target; 215 if (nrew < 1) { 216 mandoc_vmsg(MANDOCERR_RE_NOTOPEN, man->parse, 217 line, ppos, "RE %d", target); 218 return; 219 } 220 break; 221 case MAN_UE: 222 ntok = MAN_UR; 223 break; 224 default: 225 abort(); 226 /* NOTREACHED */ 227 } 228 229 for (nn = man->last->parent; nn; nn = nn->parent) 230 if (nn->tok == ntok && nn->type == ROFFT_BLOCK && ! --nrew) 231 break; 232 233 if (nn == NULL) { 234 mandoc_msg(MANDOCERR_BLK_NOTOPEN, man->parse, 235 line, ppos, man_macronames[tok]); 236 rew_scope(man, MAN_PP); 237 } else { 238 line = man->last->line; 239 ppos = man->last->pos; 240 ntok = man->last->tok; 241 man_unscope(man, nn); 242 243 /* Move a trailing paragraph behind the block. */ 244 245 if (ntok == MAN_LP || ntok == MAN_PP || ntok == MAN_P) { 246 *pos = strlen(buf); 247 blk_imp(man, ntok, line, ppos, pos, buf); 248 } 249 } 250 } 251 252 void 253 blk_exp(MACRO_PROT_ARGS) 254 { 255 struct roff_node *head; 256 char *p; 257 int la; 258 259 rew_scope(man, tok); 260 roff_block_alloc(man, line, ppos, tok); 261 head = roff_head_alloc(man, line, ppos, tok); 262 263 la = *pos; 264 if (man_args(man, line, pos, buf, &p)) 265 roff_word_alloc(man, line, la, p); 266 267 if (buf[*pos] != '\0') 268 mandoc_vmsg(MANDOCERR_ARG_EXCESS, 269 man->parse, line, *pos, "%s ... %s", 270 man_macronames[tok], buf + *pos); 271 272 man_unscope(man, head); 273 roff_body_alloc(man, line, ppos, tok); 274 } 275 276 /* 277 * Parse an implicit-block macro. These contain a ROFFT_HEAD and a 278 * ROFFT_BODY contained within a ROFFT_BLOCK. Rules for closing out other 279 * scopes, such as `SH' closing out an `SS', are defined in the rew 280 * routines. 281 */ 282 void 283 blk_imp(MACRO_PROT_ARGS) 284 { 285 int la; 286 char *p; 287 struct roff_node *n; 288 289 rew_scope(man, tok); 290 n = roff_block_alloc(man, line, ppos, tok); 291 if (n->tok == MAN_SH || n->tok == MAN_SS) 292 man->flags &= ~MAN_LITERAL; 293 n = roff_head_alloc(man, line, ppos, tok); 294 295 /* Add line arguments. */ 296 297 for (;;) { 298 la = *pos; 299 if ( ! man_args(man, line, pos, buf, &p)) 300 break; 301 roff_word_alloc(man, line, la, p); 302 } 303 304 /* 305 * For macros having optional next-line scope, 306 * keep the head open if there were no arguments. 307 * For `TP', always keep the head open. 308 */ 309 310 if (man_macros[tok].flags & MAN_SCOPED && 311 (tok == MAN_TP || n == man->last)) { 312 man->flags |= MAN_BLINE; 313 return; 314 } 315 316 /* Close out the head and open the body. */ 317 318 man_unscope(man, n); 319 roff_body_alloc(man, line, ppos, tok); 320 } 321 322 void 323 in_line_eoln(MACRO_PROT_ARGS) 324 { 325 int la; 326 char *p; 327 struct roff_node *n; 328 329 roff_elem_alloc(man, line, ppos, tok); 330 n = man->last; 331 332 for (;;) { 333 if (buf[*pos] != '\0' && (tok == MAN_br || 334 tok == MAN_fi || tok == MAN_nf)) { 335 mandoc_vmsg(MANDOCERR_ARG_SKIP, 336 man->parse, line, *pos, "%s %s", 337 man_macronames[tok], buf + *pos); 338 break; 339 } 340 if (buf[*pos] != '\0' && man->last != n && 341 (tok == MAN_PD || tok == MAN_ft || tok == MAN_sp)) { 342 mandoc_vmsg(MANDOCERR_ARG_EXCESS, 343 man->parse, line, *pos, "%s ... %s", 344 man_macronames[tok], buf + *pos); 345 break; 346 } 347 la = *pos; 348 if ( ! man_args(man, line, pos, buf, &p)) 349 break; 350 if (man_macros[tok].flags & MAN_JOIN && 351 man->last->type == ROFFT_TEXT) 352 roff_word_append(man, p); 353 else 354 roff_word_alloc(man, line, la, p); 355 } 356 357 /* 358 * Append MAN_EOS in case the last snipped argument 359 * ends with a dot, e.g. `.IR syslog (3).' 360 */ 361 362 if (n != man->last && 363 mandoc_eos(man->last->string, strlen(man->last->string))) 364 man->last->flags |= MAN_EOS; 365 366 /* 367 * If no arguments are specified and this is MAN_SCOPED (i.e., 368 * next-line scoped), then set our mode to indicate that we're 369 * waiting for terms to load into our context. 370 */ 371 372 if (n == man->last && man_macros[tok].flags & MAN_SCOPED) { 373 assert( ! (man_macros[tok].flags & MAN_NSCOPED)); 374 man->flags |= MAN_ELINE; 375 return; 376 } 377 378 assert(man->last->type != ROFFT_ROOT); 379 man->next = ROFF_NEXT_SIBLING; 380 381 /* 382 * Rewind our element scope. Note that when TH is pruned, we'll 383 * be back at the root, so make sure that we don't clobber as 384 * its sibling. 385 */ 386 387 for ( ; man->last; man->last = man->last->parent) { 388 if (man->last == n) 389 break; 390 if (man->last->type == ROFFT_ROOT) 391 break; 392 man_valid_post(man); 393 } 394 395 assert(man->last); 396 397 /* 398 * Same here regarding whether we're back at the root. 399 */ 400 401 if (man->last->type != ROFFT_ROOT) 402 man_valid_post(man); 403 } 404 405 void 406 man_endparse(struct roff_man *man) 407 { 408 409 man_unscope(man, man->first); 410 } 411 412 static int 413 man_args(struct roff_man *man, int line, int *pos, char *buf, char **v) 414 { 415 char *start; 416 417 assert(*pos); 418 *v = start = buf + *pos; 419 assert(' ' != *start); 420 421 if ('\0' == *start) 422 return(0); 423 424 *v = mandoc_getarg(man->parse, v, line, pos); 425 return(1); 426 } 427