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