1 /* $Vendor-Id: man_macro.c,v 1.42 2010/03/29 10:10:35 kristaps Exp $ */ 2 /* 3 * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se> 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 #ifdef HAVE_CONFIG_H 18 #include "config.h" 19 #endif 20 21 #include <assert.h> 22 #include <ctype.h> 23 #include <stdlib.h> 24 #include <string.h> 25 26 #include "libman.h" 27 28 enum rew { 29 REW_REWIND, 30 REW_NOHALT, 31 REW_HALT 32 }; 33 34 static int blk_close(MACRO_PROT_ARGS); 35 static int blk_dotted(MACRO_PROT_ARGS); 36 static int blk_exp(MACRO_PROT_ARGS); 37 static int blk_imp(MACRO_PROT_ARGS); 38 static int in_line_eoln(MACRO_PROT_ARGS); 39 40 static int rew_scope(enum man_type, 41 struct man *, enum mant); 42 static enum rew rew_dohalt(enum mant, enum man_type, 43 const struct man_node *); 44 static enum rew rew_block(enum mant, enum man_type, 45 const struct man_node *); 46 static int rew_warn(struct man *, 47 struct man_node *, enum merr); 48 49 const struct man_macro __man_macros[MAN_MAX] = { 50 { in_line_eoln, MAN_NSCOPED }, /* br */ 51 { in_line_eoln, 0 }, /* TH */ 52 { blk_imp, MAN_SCOPED }, /* SH */ 53 { blk_imp, MAN_SCOPED }, /* SS */ 54 { blk_imp, MAN_SCOPED | MAN_FSCOPED }, /* TP */ 55 { blk_imp, 0 }, /* LP */ 56 { blk_imp, 0 }, /* PP */ 57 { blk_imp, 0 }, /* P */ 58 { blk_imp, 0 }, /* IP */ 59 { blk_imp, 0 }, /* HP */ 60 { in_line_eoln, MAN_SCOPED }, /* SM */ 61 { in_line_eoln, MAN_SCOPED }, /* SB */ 62 { in_line_eoln, 0 }, /* BI */ 63 { in_line_eoln, 0 }, /* IB */ 64 { in_line_eoln, 0 }, /* BR */ 65 { in_line_eoln, 0 }, /* RB */ 66 { in_line_eoln, MAN_SCOPED }, /* R */ 67 { in_line_eoln, MAN_SCOPED }, /* B */ 68 { in_line_eoln, MAN_SCOPED }, /* I */ 69 { in_line_eoln, 0 }, /* IR */ 70 { in_line_eoln, 0 }, /* RI */ 71 { in_line_eoln, MAN_NSCOPED }, /* na */ 72 { in_line_eoln, 0 }, /* i */ 73 { in_line_eoln, MAN_NSCOPED }, /* sp */ 74 { in_line_eoln, 0 }, /* nf */ 75 { in_line_eoln, 0 }, /* fi */ 76 { in_line_eoln, 0 }, /* r */ 77 { blk_close, 0 }, /* RE */ 78 { blk_exp, MAN_EXPLICIT }, /* RS */ 79 { in_line_eoln, 0 }, /* DT */ 80 { in_line_eoln, 0 }, /* UC */ 81 { in_line_eoln, 0 }, /* PD */ 82 { in_line_eoln, MAN_NSCOPED }, /* Sp */ 83 { in_line_eoln, 0 }, /* Vb */ 84 { in_line_eoln, 0 }, /* Ve */ 85 { blk_exp, MAN_EXPLICIT | MAN_NOCLOSE}, /* de */ 86 { blk_exp, MAN_EXPLICIT | MAN_NOCLOSE}, /* dei */ 87 { blk_exp, MAN_EXPLICIT | MAN_NOCLOSE}, /* am */ 88 { blk_exp, MAN_EXPLICIT | MAN_NOCLOSE}, /* ami */ 89 { blk_exp, MAN_EXPLICIT | MAN_NOCLOSE}, /* ig */ 90 { blk_dotted, 0 }, /* . */ 91 }; 92 93 const struct man_macro * const man_macros = __man_macros; 94 95 96 /* 97 * Warn when "n" is an explicit non-roff macro. 98 */ 99 static int 100 rew_warn(struct man *m, struct man_node *n, enum merr er) 101 { 102 103 if (er == WERRMAX || MAN_BLOCK != n->type) 104 return(1); 105 if (MAN_VALID & n->flags) 106 return(1); 107 if ( ! (MAN_EXPLICIT & man_macros[n->tok].flags)) 108 return(1); 109 if (MAN_NOCLOSE & man_macros[n->tok].flags) 110 return(1); 111 return(man_nwarn(m, n, er)); 112 } 113 114 115 /* 116 * Rewind scope. If a code "er" != WERRMAX has been provided, it will 117 * be used if an explicit block scope is being closed out. 118 */ 119 int 120 man_unscope(struct man *m, const struct man_node *n, enum merr er) 121 { 122 123 assert(n); 124 125 /* LINTED */ 126 while (m->last != n) { 127 if ( ! rew_warn(m, m->last, er)) 128 return(0); 129 if ( ! man_valid_post(m)) 130 return(0); 131 if ( ! man_action_post(m)) 132 return(0); 133 m->last = m->last->parent; 134 assert(m->last); 135 } 136 137 if ( ! rew_warn(m, m->last, er)) 138 return(0); 139 if ( ! man_valid_post(m)) 140 return(0); 141 if ( ! man_action_post(m)) 142 return(0); 143 144 m->next = MAN_ROOT == m->last->type ? 145 MAN_NEXT_CHILD : MAN_NEXT_SIBLING; 146 147 return(1); 148 } 149 150 151 static enum rew 152 rew_block(enum mant ntok, enum man_type type, const struct man_node *n) 153 { 154 155 if (MAN_BLOCK == type && ntok == n->parent->tok && 156 MAN_BODY == n->parent->type) 157 return(REW_REWIND); 158 return(ntok == n->tok ? REW_HALT : REW_NOHALT); 159 } 160 161 162 /* 163 * There are three scope levels: scoped to the root (all), scoped to the 164 * section (all less sections), and scoped to subsections (all less 165 * sections and subsections). 166 */ 167 static enum rew 168 rew_dohalt(enum mant tok, enum man_type type, const struct man_node *n) 169 { 170 enum rew c; 171 172 /* We cannot progress beyond the root ever. */ 173 if (MAN_ROOT == n->type) 174 return(REW_HALT); 175 176 assert(n->parent); 177 178 /* Normal nodes shouldn't go to the level of the root. */ 179 if (MAN_ROOT == n->parent->type) 180 return(REW_REWIND); 181 182 /* Already-validated nodes should be closed out. */ 183 if (MAN_VALID & n->flags) 184 return(REW_NOHALT); 185 186 /* First: rewind to ourselves. */ 187 if (type == n->type && tok == n->tok) 188 return(REW_REWIND); 189 190 /* 191 * If we're a roff macro, then we can close out anything that 192 * stands between us and our parent context. 193 */ 194 if (MAN_NOCLOSE & man_macros[tok].flags) 195 return(REW_NOHALT); 196 197 /* 198 * Don't clobber roff macros: this is a bit complicated. If the 199 * current macro is a roff macro, halt immediately and don't 200 * rewind. If it's not, and the parent is, then close out the 201 * current scope and halt at the parent. 202 */ 203 if (MAN_NOCLOSE & man_macros[n->tok].flags) 204 return(REW_HALT); 205 if (MAN_NOCLOSE & man_macros[n->parent->tok].flags) 206 return(REW_REWIND); 207 208 /* 209 * Next follow the implicit scope-smashings as defined by man.7: 210 * section, sub-section, etc. 211 */ 212 213 switch (tok) { 214 case (MAN_SH): 215 break; 216 case (MAN_SS): 217 /* Rewind to a section, if a block. */ 218 if (REW_NOHALT != (c = rew_block(MAN_SH, type, n))) 219 return(c); 220 break; 221 case (MAN_RS): 222 /* Rewind to a subsection, if a block. */ 223 if (REW_NOHALT != (c = rew_block(MAN_SS, type, n))) 224 return(c); 225 /* Rewind to a section, if a block. */ 226 if (REW_NOHALT != (c = rew_block(MAN_SH, type, n))) 227 return(c); 228 break; 229 default: 230 /* Rewind to an offsetter, if a block. */ 231 if (REW_NOHALT != (c = rew_block(MAN_RS, type, n))) 232 return(c); 233 /* Rewind to a subsection, if a block. */ 234 if (REW_NOHALT != (c = rew_block(MAN_SS, type, n))) 235 return(c); 236 /* Rewind to a section, if a block. */ 237 if (REW_NOHALT != (c = rew_block(MAN_SH, type, n))) 238 return(c); 239 break; 240 } 241 242 return(REW_NOHALT); 243 } 244 245 246 /* 247 * Rewinding entails ascending the parse tree until a coherent point, 248 * for example, the `SH' macro will close out any intervening `SS' 249 * scopes. When a scope is closed, it must be validated and actioned. 250 */ 251 static int 252 rew_scope(enum man_type type, struct man *m, enum mant tok) 253 { 254 struct man_node *n; 255 enum rew c; 256 257 /* LINTED */ 258 for (n = m->last; n; n = n->parent) { 259 /* 260 * Whether we should stop immediately (REW_HALT), stop 261 * and rewind until this point (REW_REWIND), or keep 262 * rewinding (REW_NOHALT). 263 */ 264 c = rew_dohalt(tok, type, n); 265 if (REW_HALT == c) 266 return(1); 267 if (REW_REWIND == c) 268 break; 269 } 270 271 /* 272 * Rewind until the current point. Warn if we're a roff 273 * instruction that's mowing over explicit scopes. 274 */ 275 assert(n); 276 if (MAN_NOCLOSE & man_macros[tok].flags) 277 return(man_unscope(m, n, WROFFSCOPE)); 278 279 return(man_unscope(m, n, WERRMAX)); 280 } 281 282 283 /* 284 * Closure for dotted macros (de, dei, am, ami, ign). This must handle 285 * any of these as the parent node, so it needs special handling. 286 * Beyond this, it's the same as blk_close(). 287 */ 288 /* ARGSUSED */ 289 int 290 blk_dotted(MACRO_PROT_ARGS) 291 { 292 enum mant ntok; 293 struct man_node *nn; 294 295 /* Check for any of the following parents... */ 296 297 for (nn = m->last->parent; nn; nn = nn->parent) 298 if (nn->tok == MAN_de || nn->tok == MAN_dei || 299 nn->tok == MAN_am || 300 nn->tok == MAN_ami || 301 nn->tok == MAN_ig) { 302 ntok = nn->tok; 303 break; 304 } 305 306 if (NULL == nn) { 307 if ( ! man_pwarn(m, line, ppos, WNOSCOPE)) 308 return(0); 309 return(1); 310 } 311 312 if ( ! rew_scope(MAN_BODY, m, ntok)) 313 return(0); 314 if ( ! rew_scope(MAN_BLOCK, m, ntok)) 315 return(0); 316 317 /* 318 * Restore flags set when we got here and also stipulate that we 319 * don't post-process the line when exiting the macro op 320 * function in man_pmacro(). See blk_exp(). 321 */ 322 323 m->flags = m->svflags | MAN_ILINE; 324 m->next = m->svnext; 325 return(1); 326 } 327 328 329 /* 330 * Close out a generic explicit macro. 331 */ 332 /* ARGSUSED */ 333 int 334 blk_close(MACRO_PROT_ARGS) 335 { 336 enum mant ntok; 337 const struct man_node *nn; 338 339 switch (tok) { 340 case (MAN_RE): 341 ntok = MAN_RS; 342 break; 343 default: 344 abort(); 345 /* NOTREACHED */ 346 } 347 348 for (nn = m->last->parent; nn; nn = nn->parent) 349 if (ntok == nn->tok) 350 break; 351 352 if (NULL == nn) 353 if ( ! man_pwarn(m, line, ppos, WNOSCOPE)) 354 return(0); 355 356 if ( ! rew_scope(MAN_BODY, m, ntok)) 357 return(0); 358 if ( ! rew_scope(MAN_BLOCK, m, ntok)) 359 return(0); 360 361 return(1); 362 } 363 364 365 int 366 blk_exp(MACRO_PROT_ARGS) 367 { 368 int w, la; 369 char *p; 370 371 /* 372 * Close out prior scopes. "Regular" explicit macros cannot be 373 * nested, but we allow roff macros to be placed just about 374 * anywhere. 375 */ 376 377 if ( ! (MAN_NOCLOSE & man_macros[tok].flags)) { 378 if ( ! rew_scope(MAN_BODY, m, tok)) 379 return(0); 380 if ( ! rew_scope(MAN_BLOCK, m, tok)) 381 return(0); 382 } else { 383 /* 384 * Save our state and next-scope indicator; we restore 385 * it when exiting from the roff instruction block. See 386 * blk_dotted(). 387 */ 388 m->svflags = m->flags; 389 m->svnext = m->next; 390 391 /* Make sure we drop any line modes. */ 392 m->flags = 0; 393 } 394 395 if ( ! man_block_alloc(m, line, ppos, tok)) 396 return(0); 397 if ( ! man_head_alloc(m, line, ppos, tok)) 398 return(0); 399 400 for (;;) { 401 la = *pos; 402 w = man_args(m, line, pos, buf, &p); 403 404 if (-1 == w) 405 return(0); 406 if (0 == w) 407 break; 408 409 if ( ! man_word_alloc(m, line, la, p)) 410 return(0); 411 } 412 413 assert(m); 414 assert(tok != MAN_MAX); 415 416 if ( ! rew_scope(MAN_HEAD, m, tok)) 417 return(0); 418 return(man_body_alloc(m, line, ppos, tok)); 419 } 420 421 422 423 /* 424 * Parse an implicit-block macro. These contain a MAN_HEAD and a 425 * MAN_BODY contained within a MAN_BLOCK. Rules for closing out other 426 * scopes, such as `SH' closing out an `SS', are defined in the rew 427 * routines. 428 */ 429 int 430 blk_imp(MACRO_PROT_ARGS) 431 { 432 int w, la; 433 char *p; 434 struct man_node *n; 435 436 /* Close out prior scopes. */ 437 438 if ( ! rew_scope(MAN_BODY, m, tok)) 439 return(0); 440 if ( ! rew_scope(MAN_BLOCK, m, tok)) 441 return(0); 442 443 /* Allocate new block & head scope. */ 444 445 if ( ! man_block_alloc(m, line, ppos, tok)) 446 return(0); 447 if ( ! man_head_alloc(m, line, ppos, tok)) 448 return(0); 449 450 n = m->last; 451 452 /* Add line arguments. */ 453 454 for (;;) { 455 la = *pos; 456 w = man_args(m, line, pos, buf, &p); 457 458 if (-1 == w) 459 return(0); 460 if (0 == w) 461 break; 462 463 if ( ! man_word_alloc(m, line, la, p)) 464 return(0); 465 } 466 467 /* Close out head and open body (unless MAN_SCOPE). */ 468 469 if (MAN_SCOPED & man_macros[tok].flags) { 470 /* If we're forcing scope (`TP'), keep it open. */ 471 if (MAN_FSCOPED & man_macros[tok].flags) { 472 m->flags |= MAN_BLINE; 473 return(1); 474 } else if (n == m->last) { 475 m->flags |= MAN_BLINE; 476 return(1); 477 } 478 } 479 480 if ( ! rew_scope(MAN_HEAD, m, tok)) 481 return(0); 482 return(man_body_alloc(m, line, ppos, tok)); 483 } 484 485 486 int 487 in_line_eoln(MACRO_PROT_ARGS) 488 { 489 int w, la; 490 char *p; 491 struct man_node *n; 492 493 if ( ! man_elem_alloc(m, line, ppos, tok)) 494 return(0); 495 496 n = m->last; 497 498 for (;;) { 499 la = *pos; 500 w = man_args(m, line, pos, buf, &p); 501 502 if (-1 == w) 503 return(0); 504 if (0 == w) 505 break; 506 if ( ! man_word_alloc(m, line, la, p)) 507 return(0); 508 } 509 510 /* 511 * If no arguments are specified and this is MAN_SCOPED (i.e., 512 * next-line scoped), then set our mode to indicate that we're 513 * waiting for terms to load into our context. 514 */ 515 516 if (n == m->last && MAN_SCOPED & man_macros[tok].flags) { 517 assert( ! (MAN_NSCOPED & man_macros[tok].flags)); 518 m->flags |= MAN_ELINE; 519 return(1); 520 } 521 522 /* Set ignorable context, if applicable. */ 523 524 if (MAN_NSCOPED & man_macros[tok].flags) { 525 assert( ! (MAN_SCOPED & man_macros[tok].flags)); 526 m->flags |= MAN_ILINE; 527 } 528 529 /* 530 * Rewind our element scope. Note that when TH is pruned, we'll 531 * be back at the root, so make sure that we don't clobber as 532 * its sibling. 533 */ 534 535 for ( ; m->last; m->last = m->last->parent) { 536 if (m->last == n) 537 break; 538 if (m->last->type == MAN_ROOT) 539 break; 540 if ( ! man_valid_post(m)) 541 return(0); 542 if ( ! man_action_post(m)) 543 return(0); 544 } 545 546 assert(m->last); 547 548 /* 549 * Same here regarding whether we're back at the root. 550 */ 551 552 if (m->last->type != MAN_ROOT && ! man_valid_post(m)) 553 return(0); 554 if (m->last->type != MAN_ROOT && ! man_action_post(m)) 555 return(0); 556 557 m->next = MAN_ROOT == m->last->type ? 558 MAN_NEXT_CHILD : MAN_NEXT_SIBLING; 559 560 return(1); 561 } 562 563 564 int 565 man_macroend(struct man *m) 566 { 567 568 return(man_unscope(m, m->first, WEXITSCOPE)); 569 } 570 571