1 /* $OpenBSD: mdoc_validate.c,v 1.254 2017/06/17 22:40:27 schwarze Exp $ */ 2 /* 3 * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv> 4 * Copyright (c) 2010-2017 Ingo Schwarze <schwarze@openbsd.org> 5 * Copyright (c) 2010 Joerg Sonnenberger <joerg@netbsd.org> 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 #ifndef OSNAME 21 #include <sys/utsname.h> 22 #endif 23 24 #include <assert.h> 25 #include <ctype.h> 26 #include <limits.h> 27 #include <stdio.h> 28 #include <stdlib.h> 29 #include <string.h> 30 #include <time.h> 31 32 #include "mandoc_aux.h" 33 #include "mandoc.h" 34 #include "roff.h" 35 #include "mdoc.h" 36 #include "libmandoc.h" 37 #include "roff_int.h" 38 #include "libmdoc.h" 39 40 /* FIXME: .Bl -diag can't have non-text children in HEAD. */ 41 42 #define POST_ARGS struct roff_man *mdoc 43 44 enum check_ineq { 45 CHECK_LT, 46 CHECK_GT, 47 CHECK_EQ 48 }; 49 50 typedef void (*v_post)(POST_ARGS); 51 52 static int build_list(struct roff_man *, int); 53 static void check_text(struct roff_man *, int, int, char *); 54 static void check_argv(struct roff_man *, 55 struct roff_node *, struct mdoc_argv *); 56 static void check_args(struct roff_man *, struct roff_node *); 57 static void check_toptext(struct roff_man *, int, int, const char *); 58 static int child_an(const struct roff_node *); 59 static size_t macro2len(enum roff_tok); 60 static void rewrite_macro2len(struct roff_man *, char **); 61 62 static void post_an(POST_ARGS); 63 static void post_an_norm(POST_ARGS); 64 static void post_at(POST_ARGS); 65 static void post_bd(POST_ARGS); 66 static void post_bf(POST_ARGS); 67 static void post_bk(POST_ARGS); 68 static void post_bl(POST_ARGS); 69 static void post_bl_block(POST_ARGS); 70 static void post_bl_head(POST_ARGS); 71 static void post_bl_norm(POST_ARGS); 72 static void post_bx(POST_ARGS); 73 static void post_defaults(POST_ARGS); 74 static void post_display(POST_ARGS); 75 static void post_dd(POST_ARGS); 76 static void post_delim(POST_ARGS); 77 static void post_dt(POST_ARGS); 78 static void post_en(POST_ARGS); 79 static void post_es(POST_ARGS); 80 static void post_eoln(POST_ARGS); 81 static void post_ex(POST_ARGS); 82 static void post_fa(POST_ARGS); 83 static void post_fn(POST_ARGS); 84 static void post_fname(POST_ARGS); 85 static void post_fo(POST_ARGS); 86 static void post_hyph(POST_ARGS); 87 static void post_ignpar(POST_ARGS); 88 static void post_it(POST_ARGS); 89 static void post_lb(POST_ARGS); 90 static void post_nd(POST_ARGS); 91 static void post_nm(POST_ARGS); 92 static void post_ns(POST_ARGS); 93 static void post_obsolete(POST_ARGS); 94 static void post_os(POST_ARGS); 95 static void post_par(POST_ARGS); 96 static void post_prevpar(POST_ARGS); 97 static void post_root(POST_ARGS); 98 static void post_rs(POST_ARGS); 99 static void post_rv(POST_ARGS); 100 static void post_sh(POST_ARGS); 101 static void post_sh_head(POST_ARGS); 102 static void post_sh_name(POST_ARGS); 103 static void post_sh_see_also(POST_ARGS); 104 static void post_sh_authors(POST_ARGS); 105 static void post_sm(POST_ARGS); 106 static void post_st(POST_ARGS); 107 static void post_std(POST_ARGS); 108 static void post_useless(POST_ARGS); 109 static void post_xr(POST_ARGS); 110 static void post_xx(POST_ARGS); 111 112 static const v_post __mdoc_valids[MDOC_MAX - MDOC_Dd] = { 113 post_dd, /* Dd */ 114 post_dt, /* Dt */ 115 post_os, /* Os */ 116 post_sh, /* Sh */ 117 post_ignpar, /* Ss */ 118 post_par, /* Pp */ 119 post_display, /* D1 */ 120 post_display, /* Dl */ 121 post_display, /* Bd */ 122 NULL, /* Ed */ 123 post_bl, /* Bl */ 124 NULL, /* El */ 125 post_it, /* It */ 126 post_delim, /* Ad */ 127 post_an, /* An */ 128 NULL, /* Ap */ 129 post_defaults, /* Ar */ 130 NULL, /* Cd */ 131 post_delim, /* Cm */ 132 post_delim, /* Dv */ 133 post_delim, /* Er */ 134 post_delim, /* Ev */ 135 post_ex, /* Ex */ 136 post_fa, /* Fa */ 137 NULL, /* Fd */ 138 post_delim, /* Fl */ 139 post_fn, /* Fn */ 140 post_delim, /* Ft */ 141 post_delim, /* Ic */ 142 post_delim, /* In */ 143 post_defaults, /* Li */ 144 post_nd, /* Nd */ 145 post_nm, /* Nm */ 146 post_delim, /* Op */ 147 post_obsolete, /* Ot */ 148 post_defaults, /* Pa */ 149 post_rv, /* Rv */ 150 post_st, /* St */ 151 post_delim, /* Va */ 152 post_delim, /* Vt */ 153 post_xr, /* Xr */ 154 NULL, /* %A */ 155 post_hyph, /* %B */ /* FIXME: can be used outside Rs/Re. */ 156 NULL, /* %D */ 157 NULL, /* %I */ 158 NULL, /* %J */ 159 post_hyph, /* %N */ 160 post_hyph, /* %O */ 161 NULL, /* %P */ 162 post_hyph, /* %R */ 163 post_hyph, /* %T */ /* FIXME: can be used outside Rs/Re. */ 164 NULL, /* %V */ 165 NULL, /* Ac */ 166 post_delim, /* Ao */ 167 post_delim, /* Aq */ 168 post_at, /* At */ 169 NULL, /* Bc */ 170 post_bf, /* Bf */ 171 post_delim, /* Bo */ 172 NULL, /* Bq */ 173 post_xx, /* Bsx */ 174 post_bx, /* Bx */ 175 post_obsolete, /* Db */ 176 NULL, /* Dc */ 177 NULL, /* Do */ 178 NULL, /* Dq */ 179 NULL, /* Ec */ 180 NULL, /* Ef */ 181 post_delim, /* Em */ 182 NULL, /* Eo */ 183 post_xx, /* Fx */ 184 post_delim, /* Ms */ 185 NULL, /* No */ 186 post_ns, /* Ns */ 187 post_xx, /* Nx */ 188 post_xx, /* Ox */ 189 NULL, /* Pc */ 190 NULL, /* Pf */ 191 post_delim, /* Po */ 192 post_delim, /* Pq */ 193 NULL, /* Qc */ 194 post_delim, /* Ql */ 195 post_delim, /* Qo */ 196 post_delim, /* Qq */ 197 NULL, /* Re */ 198 post_rs, /* Rs */ 199 NULL, /* Sc */ 200 post_delim, /* So */ 201 post_delim, /* Sq */ 202 post_sm, /* Sm */ 203 post_hyph, /* Sx */ 204 post_delim, /* Sy */ 205 post_useless, /* Tn */ 206 post_xx, /* Ux */ 207 NULL, /* Xc */ 208 NULL, /* Xo */ 209 post_fo, /* Fo */ 210 NULL, /* Fc */ 211 post_delim, /* Oo */ 212 NULL, /* Oc */ 213 post_bk, /* Bk */ 214 NULL, /* Ek */ 215 post_eoln, /* Bt */ 216 post_obsolete, /* Hf */ 217 post_obsolete, /* Fr */ 218 post_eoln, /* Ud */ 219 post_lb, /* Lb */ 220 post_par, /* Lp */ 221 post_delim, /* Lk */ 222 post_defaults, /* Mt */ 223 post_delim, /* Brq */ 224 post_delim, /* Bro */ 225 NULL, /* Brc */ 226 NULL, /* %C */ 227 post_es, /* Es */ 228 post_en, /* En */ 229 post_xx, /* Dx */ 230 NULL, /* %Q */ 231 NULL, /* %U */ 232 NULL, /* Ta */ 233 }; 234 static const v_post *const mdoc_valids = __mdoc_valids - MDOC_Dd; 235 236 #define RSORD_MAX 14 /* Number of `Rs' blocks. */ 237 238 static const enum roff_tok rsord[RSORD_MAX] = { 239 MDOC__A, 240 MDOC__T, 241 MDOC__B, 242 MDOC__I, 243 MDOC__J, 244 MDOC__R, 245 MDOC__N, 246 MDOC__V, 247 MDOC__U, 248 MDOC__P, 249 MDOC__Q, 250 MDOC__C, 251 MDOC__D, 252 MDOC__O 253 }; 254 255 static const char * const secnames[SEC__MAX] = { 256 NULL, 257 "NAME", 258 "LIBRARY", 259 "SYNOPSIS", 260 "DESCRIPTION", 261 "CONTEXT", 262 "IMPLEMENTATION NOTES", 263 "RETURN VALUES", 264 "ENVIRONMENT", 265 "FILES", 266 "EXIT STATUS", 267 "EXAMPLES", 268 "DIAGNOSTICS", 269 "COMPATIBILITY", 270 "ERRORS", 271 "SEE ALSO", 272 "STANDARDS", 273 "HISTORY", 274 "AUTHORS", 275 "CAVEATS", 276 "BUGS", 277 "SECURITY CONSIDERATIONS", 278 NULL 279 }; 280 281 282 void 283 mdoc_node_validate(struct roff_man *mdoc) 284 { 285 struct roff_node *n; 286 const v_post *p; 287 288 n = mdoc->last; 289 mdoc->last = mdoc->last->child; 290 while (mdoc->last != NULL) { 291 mdoc_node_validate(mdoc); 292 if (mdoc->last == n) 293 mdoc->last = mdoc->last->child; 294 else 295 mdoc->last = mdoc->last->next; 296 } 297 298 mdoc->last = n; 299 mdoc->next = ROFF_NEXT_SIBLING; 300 switch (n->type) { 301 case ROFFT_TEXT: 302 if (n->sec != SEC_SYNOPSIS || 303 (n->parent->tok != MDOC_Cd && n->parent->tok != MDOC_Fd)) 304 check_text(mdoc, n->line, n->pos, n->string); 305 if (n->parent->tok == MDOC_It || 306 (n->parent->type == ROFFT_BODY && 307 (n->parent->tok == MDOC_Sh || 308 n->parent->tok == MDOC_Ss))) 309 check_toptext(mdoc, n->line, n->pos, n->string); 310 break; 311 case ROFFT_EQN: 312 case ROFFT_TBL: 313 break; 314 case ROFFT_ROOT: 315 post_root(mdoc); 316 break; 317 default: 318 check_args(mdoc, mdoc->last); 319 320 /* 321 * Closing delimiters are not special at the 322 * beginning of a block, opening delimiters 323 * are not special at the end. 324 */ 325 326 if (n->child != NULL) 327 n->child->flags &= ~NODE_DELIMC; 328 if (n->last != NULL) 329 n->last->flags &= ~NODE_DELIMO; 330 331 /* Call the macro's postprocessor. */ 332 333 if (n->tok < ROFF_MAX) { 334 switch(n->tok) { 335 case ROFF_br: 336 case ROFF_sp: 337 post_par(mdoc); 338 break; 339 default: 340 roff_validate(mdoc); 341 break; 342 } 343 break; 344 } 345 346 assert(n->tok >= MDOC_Dd && n->tok < MDOC_MAX); 347 p = mdoc_valids + n->tok; 348 if (*p) 349 (*p)(mdoc); 350 if (mdoc->last == n) 351 mdoc_state(mdoc, n); 352 break; 353 } 354 } 355 356 static void 357 check_args(struct roff_man *mdoc, struct roff_node *n) 358 { 359 int i; 360 361 if (NULL == n->args) 362 return; 363 364 assert(n->args->argc); 365 for (i = 0; i < (int)n->args->argc; i++) 366 check_argv(mdoc, n, &n->args->argv[i]); 367 } 368 369 static void 370 check_argv(struct roff_man *mdoc, struct roff_node *n, struct mdoc_argv *v) 371 { 372 int i; 373 374 for (i = 0; i < (int)v->sz; i++) 375 check_text(mdoc, v->line, v->pos, v->value[i]); 376 } 377 378 static void 379 check_text(struct roff_man *mdoc, int ln, int pos, char *p) 380 { 381 char *cp; 382 383 if (MDOC_LITERAL & mdoc->flags) 384 return; 385 386 for (cp = p; NULL != (p = strchr(p, '\t')); p++) 387 mandoc_msg(MANDOCERR_FI_TAB, mdoc->parse, 388 ln, pos + (int)(p - cp), NULL); 389 } 390 391 static void 392 check_toptext(struct roff_man *mdoc, int ln, int pos, const char *p) 393 { 394 const char *cp, *cpr; 395 396 if (*p == '\0') 397 return; 398 399 if ((cp = strstr(p, "OpenBSD")) != NULL) 400 mandoc_msg(MANDOCERR_BX, mdoc->parse, 401 ln, pos + (cp - p), "Ox"); 402 if ((cp = strstr(p, "NetBSD")) != NULL) 403 mandoc_msg(MANDOCERR_BX, mdoc->parse, 404 ln, pos + (cp - p), "Nx"); 405 if ((cp = strstr(p, "FreeBSD")) != NULL) 406 mandoc_msg(MANDOCERR_BX, mdoc->parse, 407 ln, pos + (cp - p), "Fx"); 408 if ((cp = strstr(p, "DragonFly")) != NULL) 409 mandoc_msg(MANDOCERR_BX, mdoc->parse, 410 ln, pos + (cp - p), "Dx"); 411 412 cp = p; 413 while ((cp = strstr(cp + 1, "()")) != NULL) { 414 for (cpr = cp - 1; cpr >= p; cpr--) 415 if (*cpr != '_' && !isalnum((unsigned char)*cpr)) 416 break; 417 if ((cpr < p || *cpr == ' ') && cpr + 1 < cp) { 418 cpr++; 419 mandoc_vmsg(MANDOCERR_FUNC, mdoc->parse, 420 ln, pos + (cpr - p), 421 "%.*s()", (int)(cp - cpr), cpr); 422 } 423 } 424 } 425 426 static void 427 post_delim(POST_ARGS) 428 { 429 const struct roff_node *nch; 430 const char *lc, *cp; 431 int nw; 432 enum mdelim delim; 433 enum roff_tok tok; 434 435 /* 436 * Find candidates: at least two bytes, 437 * the last one a closing or middle delimiter. 438 */ 439 440 tok = mdoc->last->tok; 441 nch = mdoc->last->last; 442 if (nch == NULL || nch->type != ROFFT_TEXT) 443 return; 444 lc = strchr(nch->string, '\0') - 1; 445 if (lc <= nch->string) 446 return; 447 delim = mdoc_isdelim(lc); 448 if (delim == DELIM_NONE || delim == DELIM_OPEN) 449 return; 450 451 /* 452 * Reduce false positives by allowing various cases. 453 */ 454 455 /* Escaped delimiters. */ 456 if (lc > nch->string + 1 && lc[-2] == '\\' && 457 (lc[-1] == '&' || lc[-1] == 'e')) 458 return; 459 460 /* Specific byte sequences. */ 461 switch (*lc) { 462 case ')': 463 for (cp = lc; cp >= nch->string; cp--) 464 if (*cp == '(') 465 return; 466 break; 467 case '.': 468 if (lc > nch->string + 1 && lc[-2] == '.' && lc[-1] == '.') 469 return; 470 if (lc[-1] == '.') 471 return; 472 break; 473 case ';': 474 if (tok == MDOC_Vt) 475 return; 476 break; 477 case '?': 478 if (lc[-1] == '?') 479 return; 480 break; 481 case ']': 482 for (cp = lc; cp >= nch->string; cp--) 483 if (*cp == '[') 484 return; 485 break; 486 case '|': 487 if (lc == nch->string + 1 && lc[-1] == '|') 488 return; 489 default: 490 break; 491 } 492 493 /* Exactly two non-alphanumeric bytes. */ 494 if (lc == nch->string + 1 && !isalnum((unsigned char)lc[-1])) 495 return; 496 497 /* At least three alphabetic words with a sentence ending. */ 498 if (strchr("!.:?", *lc) != NULL && (tok == MDOC_Em || 499 tok == MDOC_Li || tok == MDOC_Po || tok == MDOC_Pq || 500 tok == MDOC_Sy)) { 501 nw = 0; 502 for (cp = lc - 1; cp >= nch->string; cp--) { 503 if (*cp == ' ') { 504 nw++; 505 if (cp > nch->string && cp[-1] == ',') 506 cp--; 507 } else if (isalpha((unsigned int)*cp)) { 508 if (nw > 1) 509 return; 510 } else 511 break; 512 } 513 } 514 515 mandoc_vmsg(MANDOCERR_DELIM, mdoc->parse, 516 nch->line, nch->pos + (lc - nch->string), 517 "%s%s %s", roff_name[tok], 518 nch == mdoc->last->child ? "" : " ...", nch->string); 519 } 520 521 static void 522 post_bl_norm(POST_ARGS) 523 { 524 struct roff_node *n; 525 struct mdoc_argv *argv, *wa; 526 int i; 527 enum mdocargt mdoclt; 528 enum mdoc_list lt; 529 530 n = mdoc->last->parent; 531 n->norm->Bl.type = LIST__NONE; 532 533 /* 534 * First figure out which kind of list to use: bind ourselves to 535 * the first mentioned list type and warn about any remaining 536 * ones. If we find no list type, we default to LIST_item. 537 */ 538 539 wa = (n->args == NULL) ? NULL : n->args->argv; 540 mdoclt = MDOC_ARG_MAX; 541 for (i = 0; n->args && i < (int)n->args->argc; i++) { 542 argv = n->args->argv + i; 543 lt = LIST__NONE; 544 switch (argv->arg) { 545 /* Set list types. */ 546 case MDOC_Bullet: 547 lt = LIST_bullet; 548 break; 549 case MDOC_Dash: 550 lt = LIST_dash; 551 break; 552 case MDOC_Enum: 553 lt = LIST_enum; 554 break; 555 case MDOC_Hyphen: 556 lt = LIST_hyphen; 557 break; 558 case MDOC_Item: 559 lt = LIST_item; 560 break; 561 case MDOC_Tag: 562 lt = LIST_tag; 563 break; 564 case MDOC_Diag: 565 lt = LIST_diag; 566 break; 567 case MDOC_Hang: 568 lt = LIST_hang; 569 break; 570 case MDOC_Ohang: 571 lt = LIST_ohang; 572 break; 573 case MDOC_Inset: 574 lt = LIST_inset; 575 break; 576 case MDOC_Column: 577 lt = LIST_column; 578 break; 579 /* Set list arguments. */ 580 case MDOC_Compact: 581 if (n->norm->Bl.comp) 582 mandoc_msg(MANDOCERR_ARG_REP, 583 mdoc->parse, argv->line, 584 argv->pos, "Bl -compact"); 585 n->norm->Bl.comp = 1; 586 break; 587 case MDOC_Width: 588 wa = argv; 589 if (0 == argv->sz) { 590 mandoc_msg(MANDOCERR_ARG_EMPTY, 591 mdoc->parse, argv->line, 592 argv->pos, "Bl -width"); 593 n->norm->Bl.width = "0n"; 594 break; 595 } 596 if (NULL != n->norm->Bl.width) 597 mandoc_vmsg(MANDOCERR_ARG_REP, 598 mdoc->parse, argv->line, 599 argv->pos, "Bl -width %s", 600 argv->value[0]); 601 rewrite_macro2len(mdoc, argv->value); 602 n->norm->Bl.width = argv->value[0]; 603 break; 604 case MDOC_Offset: 605 if (0 == argv->sz) { 606 mandoc_msg(MANDOCERR_ARG_EMPTY, 607 mdoc->parse, argv->line, 608 argv->pos, "Bl -offset"); 609 break; 610 } 611 if (NULL != n->norm->Bl.offs) 612 mandoc_vmsg(MANDOCERR_ARG_REP, 613 mdoc->parse, argv->line, 614 argv->pos, "Bl -offset %s", 615 argv->value[0]); 616 rewrite_macro2len(mdoc, argv->value); 617 n->norm->Bl.offs = argv->value[0]; 618 break; 619 default: 620 continue; 621 } 622 if (LIST__NONE == lt) 623 continue; 624 mdoclt = argv->arg; 625 626 /* Check: multiple list types. */ 627 628 if (LIST__NONE != n->norm->Bl.type) { 629 mandoc_vmsg(MANDOCERR_BL_REP, 630 mdoc->parse, n->line, n->pos, 631 "Bl -%s", mdoc_argnames[argv->arg]); 632 continue; 633 } 634 635 /* The list type should come first. */ 636 637 if (n->norm->Bl.width || 638 n->norm->Bl.offs || 639 n->norm->Bl.comp) 640 mandoc_vmsg(MANDOCERR_BL_LATETYPE, 641 mdoc->parse, n->line, n->pos, "Bl -%s", 642 mdoc_argnames[n->args->argv[0].arg]); 643 644 n->norm->Bl.type = lt; 645 if (LIST_column == lt) { 646 n->norm->Bl.ncols = argv->sz; 647 n->norm->Bl.cols = (void *)argv->value; 648 } 649 } 650 651 /* Allow lists to default to LIST_item. */ 652 653 if (LIST__NONE == n->norm->Bl.type) { 654 mandoc_msg(MANDOCERR_BL_NOTYPE, mdoc->parse, 655 n->line, n->pos, "Bl"); 656 n->norm->Bl.type = LIST_item; 657 mdoclt = MDOC_Item; 658 } 659 660 /* 661 * Validate the width field. Some list types don't need width 662 * types and should be warned about them. Others should have it 663 * and must also be warned. Yet others have a default and need 664 * no warning. 665 */ 666 667 switch (n->norm->Bl.type) { 668 case LIST_tag: 669 if (NULL == n->norm->Bl.width) 670 mandoc_msg(MANDOCERR_BL_NOWIDTH, mdoc->parse, 671 n->line, n->pos, "Bl -tag"); 672 break; 673 case LIST_column: 674 case LIST_diag: 675 case LIST_ohang: 676 case LIST_inset: 677 case LIST_item: 678 if (n->norm->Bl.width) 679 mandoc_vmsg(MANDOCERR_BL_SKIPW, mdoc->parse, 680 wa->line, wa->pos, "Bl -%s", 681 mdoc_argnames[mdoclt]); 682 break; 683 case LIST_bullet: 684 case LIST_dash: 685 case LIST_hyphen: 686 if (NULL == n->norm->Bl.width) 687 n->norm->Bl.width = "2n"; 688 break; 689 case LIST_enum: 690 if (NULL == n->norm->Bl.width) 691 n->norm->Bl.width = "3n"; 692 break; 693 default: 694 break; 695 } 696 } 697 698 static void 699 post_bd(POST_ARGS) 700 { 701 struct roff_node *n; 702 struct mdoc_argv *argv; 703 int i; 704 enum mdoc_disp dt; 705 706 n = mdoc->last; 707 for (i = 0; n->args && i < (int)n->args->argc; i++) { 708 argv = n->args->argv + i; 709 dt = DISP__NONE; 710 711 switch (argv->arg) { 712 case MDOC_Centred: 713 dt = DISP_centered; 714 break; 715 case MDOC_Ragged: 716 dt = DISP_ragged; 717 break; 718 case MDOC_Unfilled: 719 dt = DISP_unfilled; 720 break; 721 case MDOC_Filled: 722 dt = DISP_filled; 723 break; 724 case MDOC_Literal: 725 dt = DISP_literal; 726 break; 727 case MDOC_File: 728 mandoc_msg(MANDOCERR_BD_FILE, mdoc->parse, 729 n->line, n->pos, NULL); 730 break; 731 case MDOC_Offset: 732 if (0 == argv->sz) { 733 mandoc_msg(MANDOCERR_ARG_EMPTY, 734 mdoc->parse, argv->line, 735 argv->pos, "Bd -offset"); 736 break; 737 } 738 if (NULL != n->norm->Bd.offs) 739 mandoc_vmsg(MANDOCERR_ARG_REP, 740 mdoc->parse, argv->line, 741 argv->pos, "Bd -offset %s", 742 argv->value[0]); 743 rewrite_macro2len(mdoc, argv->value); 744 n->norm->Bd.offs = argv->value[0]; 745 break; 746 case MDOC_Compact: 747 if (n->norm->Bd.comp) 748 mandoc_msg(MANDOCERR_ARG_REP, 749 mdoc->parse, argv->line, 750 argv->pos, "Bd -compact"); 751 n->norm->Bd.comp = 1; 752 break; 753 default: 754 abort(); 755 } 756 if (DISP__NONE == dt) 757 continue; 758 759 if (DISP__NONE == n->norm->Bd.type) 760 n->norm->Bd.type = dt; 761 else 762 mandoc_vmsg(MANDOCERR_BD_REP, 763 mdoc->parse, n->line, n->pos, 764 "Bd -%s", mdoc_argnames[argv->arg]); 765 } 766 767 if (DISP__NONE == n->norm->Bd.type) { 768 mandoc_msg(MANDOCERR_BD_NOTYPE, mdoc->parse, 769 n->line, n->pos, "Bd"); 770 n->norm->Bd.type = DISP_ragged; 771 } 772 } 773 774 /* 775 * Stand-alone line macros. 776 */ 777 778 static void 779 post_an_norm(POST_ARGS) 780 { 781 struct roff_node *n; 782 struct mdoc_argv *argv; 783 size_t i; 784 785 n = mdoc->last; 786 if (n->args == NULL) 787 return; 788 789 for (i = 1; i < n->args->argc; i++) { 790 argv = n->args->argv + i; 791 mandoc_vmsg(MANDOCERR_AN_REP, 792 mdoc->parse, argv->line, argv->pos, 793 "An -%s", mdoc_argnames[argv->arg]); 794 } 795 796 argv = n->args->argv; 797 if (argv->arg == MDOC_Split) 798 n->norm->An.auth = AUTH_split; 799 else if (argv->arg == MDOC_Nosplit) 800 n->norm->An.auth = AUTH_nosplit; 801 else 802 abort(); 803 } 804 805 static void 806 post_eoln(POST_ARGS) 807 { 808 struct roff_node *n; 809 810 post_useless(mdoc); 811 n = mdoc->last; 812 if (n->child != NULL) 813 mandoc_vmsg(MANDOCERR_ARG_SKIP, mdoc->parse, n->line, 814 n->pos, "%s %s", roff_name[n->tok], n->child->string); 815 816 while (n->child != NULL) 817 roff_node_delete(mdoc, n->child); 818 819 roff_word_alloc(mdoc, n->line, n->pos, n->tok == MDOC_Bt ? 820 "is currently in beta test." : "currently under development."); 821 mdoc->last->flags |= NODE_EOS | NODE_NOSRC; 822 mdoc->last = n; 823 } 824 825 static int 826 build_list(struct roff_man *mdoc, int tok) 827 { 828 struct roff_node *n; 829 int ic; 830 831 n = mdoc->last->next; 832 for (ic = 1;; ic++) { 833 roff_elem_alloc(mdoc, n->line, n->pos, tok); 834 mdoc->last->flags |= NODE_NOSRC; 835 mdoc_node_relink(mdoc, n); 836 n = mdoc->last = mdoc->last->parent; 837 mdoc->next = ROFF_NEXT_SIBLING; 838 if (n->next == NULL) 839 return ic; 840 if (ic > 1 || n->next->next != NULL) { 841 roff_word_alloc(mdoc, n->line, n->pos, ","); 842 mdoc->last->flags |= NODE_DELIMC | NODE_NOSRC; 843 } 844 n = mdoc->last->next; 845 if (n->next == NULL) { 846 roff_word_alloc(mdoc, n->line, n->pos, "and"); 847 mdoc->last->flags |= NODE_NOSRC; 848 } 849 } 850 } 851 852 static void 853 post_ex(POST_ARGS) 854 { 855 struct roff_node *n; 856 int ic; 857 858 post_std(mdoc); 859 860 n = mdoc->last; 861 mdoc->next = ROFF_NEXT_CHILD; 862 roff_word_alloc(mdoc, n->line, n->pos, "The"); 863 mdoc->last->flags |= NODE_NOSRC; 864 865 if (mdoc->last->next != NULL) 866 ic = build_list(mdoc, MDOC_Nm); 867 else if (mdoc->meta.name != NULL) { 868 roff_elem_alloc(mdoc, n->line, n->pos, MDOC_Nm); 869 mdoc->last->flags |= NODE_NOSRC; 870 roff_word_alloc(mdoc, n->line, n->pos, mdoc->meta.name); 871 mdoc->last->flags |= NODE_NOSRC; 872 mdoc->last = mdoc->last->parent; 873 mdoc->next = ROFF_NEXT_SIBLING; 874 ic = 1; 875 } else { 876 mandoc_msg(MANDOCERR_EX_NONAME, mdoc->parse, 877 n->line, n->pos, "Ex"); 878 ic = 0; 879 } 880 881 roff_word_alloc(mdoc, n->line, n->pos, 882 ic > 1 ? "utilities exit\\~0" : "utility exits\\~0"); 883 mdoc->last->flags |= NODE_NOSRC; 884 roff_word_alloc(mdoc, n->line, n->pos, 885 "on success, and\\~>0 if an error occurs."); 886 mdoc->last->flags |= NODE_EOS | NODE_NOSRC; 887 mdoc->last = n; 888 } 889 890 static void 891 post_lb(POST_ARGS) 892 { 893 struct roff_node *n; 894 895 post_delim(mdoc); 896 897 n = mdoc->last; 898 assert(n->child->type == ROFFT_TEXT); 899 mdoc->next = ROFF_NEXT_CHILD; 900 roff_word_alloc(mdoc, n->line, n->pos, "library"); 901 mdoc->last->flags = NODE_NOSRC; 902 roff_word_alloc(mdoc, n->line, n->pos, "\\(Lq"); 903 mdoc->last->flags = NODE_DELIMO | NODE_NOSRC; 904 mdoc->last = mdoc->last->next; 905 roff_word_alloc(mdoc, n->line, n->pos, "\\(Rq"); 906 mdoc->last->flags = NODE_DELIMC | NODE_NOSRC; 907 mdoc->last = n; 908 } 909 910 static void 911 post_rv(POST_ARGS) 912 { 913 struct roff_node *n; 914 int ic; 915 916 post_std(mdoc); 917 918 n = mdoc->last; 919 mdoc->next = ROFF_NEXT_CHILD; 920 if (n->child != NULL) { 921 roff_word_alloc(mdoc, n->line, n->pos, "The"); 922 mdoc->last->flags |= NODE_NOSRC; 923 ic = build_list(mdoc, MDOC_Fn); 924 roff_word_alloc(mdoc, n->line, n->pos, 925 ic > 1 ? "functions return" : "function returns"); 926 mdoc->last->flags |= NODE_NOSRC; 927 roff_word_alloc(mdoc, n->line, n->pos, 928 "the value\\~0 if successful;"); 929 } else 930 roff_word_alloc(mdoc, n->line, n->pos, "Upon successful " 931 "completion, the value\\~0 is returned;"); 932 mdoc->last->flags |= NODE_NOSRC; 933 934 roff_word_alloc(mdoc, n->line, n->pos, "otherwise " 935 "the value\\~\\-1 is returned and the global variable"); 936 mdoc->last->flags |= NODE_NOSRC; 937 roff_elem_alloc(mdoc, n->line, n->pos, MDOC_Va); 938 mdoc->last->flags |= NODE_NOSRC; 939 roff_word_alloc(mdoc, n->line, n->pos, "errno"); 940 mdoc->last->flags |= NODE_NOSRC; 941 mdoc->last = mdoc->last->parent; 942 mdoc->next = ROFF_NEXT_SIBLING; 943 roff_word_alloc(mdoc, n->line, n->pos, 944 "is set to indicate the error."); 945 mdoc->last->flags |= NODE_EOS | NODE_NOSRC; 946 mdoc->last = n; 947 } 948 949 static void 950 post_std(POST_ARGS) 951 { 952 struct roff_node *n; 953 954 n = mdoc->last; 955 if (n->args && n->args->argc == 1) 956 if (n->args->argv[0].arg == MDOC_Std) 957 return; 958 959 mandoc_msg(MANDOCERR_ARG_STD, mdoc->parse, 960 n->line, n->pos, roff_name[n->tok]); 961 } 962 963 static void 964 post_st(POST_ARGS) 965 { 966 struct roff_node *n, *nch; 967 const char *p; 968 969 n = mdoc->last; 970 nch = n->child; 971 assert(nch->type == ROFFT_TEXT); 972 973 if ((p = mdoc_a2st(nch->string)) == NULL) { 974 mandoc_vmsg(MANDOCERR_ST_BAD, mdoc->parse, 975 nch->line, nch->pos, "St %s", nch->string); 976 roff_node_delete(mdoc, n); 977 return; 978 } 979 980 nch->flags |= NODE_NOPRT; 981 mdoc->next = ROFF_NEXT_CHILD; 982 roff_word_alloc(mdoc, nch->line, nch->pos, p); 983 mdoc->last->flags |= NODE_NOSRC; 984 mdoc->last= n; 985 } 986 987 static void 988 post_obsolete(POST_ARGS) 989 { 990 struct roff_node *n; 991 992 n = mdoc->last; 993 if (n->type == ROFFT_ELEM || n->type == ROFFT_BLOCK) 994 mandoc_msg(MANDOCERR_MACRO_OBS, mdoc->parse, 995 n->line, n->pos, roff_name[n->tok]); 996 } 997 998 static void 999 post_useless(POST_ARGS) 1000 { 1001 struct roff_node *n; 1002 1003 n = mdoc->last; 1004 mandoc_msg(MANDOCERR_MACRO_USELESS, mdoc->parse, 1005 n->line, n->pos, roff_name[n->tok]); 1006 } 1007 1008 /* 1009 * Block macros. 1010 */ 1011 1012 static void 1013 post_bf(POST_ARGS) 1014 { 1015 struct roff_node *np, *nch; 1016 1017 /* 1018 * Unlike other data pointers, these are "housed" by the HEAD 1019 * element, which contains the goods. 1020 */ 1021 1022 np = mdoc->last; 1023 if (np->type != ROFFT_HEAD) 1024 return; 1025 1026 assert(np->parent->type == ROFFT_BLOCK); 1027 assert(np->parent->tok == MDOC_Bf); 1028 1029 /* Check the number of arguments. */ 1030 1031 nch = np->child; 1032 if (np->parent->args == NULL) { 1033 if (nch == NULL) { 1034 mandoc_msg(MANDOCERR_BF_NOFONT, mdoc->parse, 1035 np->line, np->pos, "Bf"); 1036 return; 1037 } 1038 nch = nch->next; 1039 } 1040 if (nch != NULL) 1041 mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse, 1042 nch->line, nch->pos, "Bf ... %s", nch->string); 1043 1044 /* Extract argument into data. */ 1045 1046 if (np->parent->args != NULL) { 1047 switch (np->parent->args->argv[0].arg) { 1048 case MDOC_Emphasis: 1049 np->norm->Bf.font = FONT_Em; 1050 break; 1051 case MDOC_Literal: 1052 np->norm->Bf.font = FONT_Li; 1053 break; 1054 case MDOC_Symbolic: 1055 np->norm->Bf.font = FONT_Sy; 1056 break; 1057 default: 1058 abort(); 1059 } 1060 return; 1061 } 1062 1063 /* Extract parameter into data. */ 1064 1065 if ( ! strcmp(np->child->string, "Em")) 1066 np->norm->Bf.font = FONT_Em; 1067 else if ( ! strcmp(np->child->string, "Li")) 1068 np->norm->Bf.font = FONT_Li; 1069 else if ( ! strcmp(np->child->string, "Sy")) 1070 np->norm->Bf.font = FONT_Sy; 1071 else 1072 mandoc_vmsg(MANDOCERR_BF_BADFONT, mdoc->parse, 1073 np->child->line, np->child->pos, 1074 "Bf %s", np->child->string); 1075 } 1076 1077 static void 1078 post_fname(POST_ARGS) 1079 { 1080 const struct roff_node *n; 1081 const char *cp; 1082 size_t pos; 1083 1084 n = mdoc->last->child; 1085 pos = strcspn(n->string, "()"); 1086 cp = n->string + pos; 1087 if ( ! (cp[0] == '\0' || (cp[0] == '(' && cp[1] == '*'))) 1088 mandoc_msg(MANDOCERR_FN_PAREN, mdoc->parse, 1089 n->line, n->pos + pos, n->string); 1090 } 1091 1092 static void 1093 post_fn(POST_ARGS) 1094 { 1095 1096 post_fname(mdoc); 1097 post_fa(mdoc); 1098 } 1099 1100 static void 1101 post_fo(POST_ARGS) 1102 { 1103 const struct roff_node *n; 1104 1105 n = mdoc->last; 1106 1107 if (n->type != ROFFT_HEAD) 1108 return; 1109 1110 if (n->child == NULL) { 1111 mandoc_msg(MANDOCERR_FO_NOHEAD, mdoc->parse, 1112 n->line, n->pos, "Fo"); 1113 return; 1114 } 1115 if (n->child != n->last) { 1116 mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse, 1117 n->child->next->line, n->child->next->pos, 1118 "Fo ... %s", n->child->next->string); 1119 while (n->child != n->last) 1120 roff_node_delete(mdoc, n->last); 1121 } 1122 1123 post_fname(mdoc); 1124 } 1125 1126 static void 1127 post_fa(POST_ARGS) 1128 { 1129 const struct roff_node *n; 1130 const char *cp; 1131 1132 for (n = mdoc->last->child; n != NULL; n = n->next) { 1133 for (cp = n->string; *cp != '\0'; cp++) { 1134 /* Ignore callbacks and alterations. */ 1135 if (*cp == '(' || *cp == '{') 1136 break; 1137 if (*cp != ',') 1138 continue; 1139 mandoc_msg(MANDOCERR_FA_COMMA, mdoc->parse, 1140 n->line, n->pos + (cp - n->string), 1141 n->string); 1142 break; 1143 } 1144 } 1145 post_delim(mdoc); 1146 } 1147 1148 static void 1149 post_nm(POST_ARGS) 1150 { 1151 struct roff_node *n; 1152 1153 n = mdoc->last; 1154 1155 if (n->last != NULL && 1156 (n->last->tok == MDOC_Pp || 1157 n->last->tok == MDOC_Lp)) 1158 mdoc_node_relink(mdoc, n->last); 1159 1160 if (mdoc->meta.name == NULL) 1161 deroff(&mdoc->meta.name, n); 1162 1163 if (mdoc->meta.name == NULL || 1164 (mdoc->lastsec == SEC_NAME && n->child == NULL)) 1165 mandoc_msg(MANDOCERR_NM_NONAME, mdoc->parse, 1166 n->line, n->pos, "Nm"); 1167 1168 if (n->type == ROFFT_ELEM) 1169 post_delim(mdoc); 1170 1171 if ((n->type != ROFFT_ELEM && n->type != ROFFT_HEAD) || 1172 (n->child != NULL && n->child->type == ROFFT_TEXT) || 1173 mdoc->meta.name == NULL) 1174 return; 1175 1176 mdoc->next = ROFF_NEXT_CHILD; 1177 roff_word_alloc(mdoc, n->line, n->pos, mdoc->meta.name); 1178 mdoc->last->flags |= NODE_NOSRC; 1179 mdoc->last = n; 1180 } 1181 1182 static void 1183 post_nd(POST_ARGS) 1184 { 1185 struct roff_node *n; 1186 size_t sz; 1187 1188 n = mdoc->last; 1189 1190 if (n->type != ROFFT_BODY) 1191 return; 1192 1193 if (n->sec != SEC_NAME) 1194 mandoc_msg(MANDOCERR_ND_LATE, mdoc->parse, 1195 n->line, n->pos, "Nd"); 1196 1197 if (n->child == NULL) 1198 mandoc_msg(MANDOCERR_ND_EMPTY, mdoc->parse, 1199 n->line, n->pos, "Nd"); 1200 else if (n->last->type == ROFFT_TEXT && 1201 (sz = strlen(n->last->string)) != 0 && 1202 n->last->string[sz - 1] == '.') 1203 mandoc_msg(MANDOCERR_ND_DOT, mdoc->parse, 1204 n->last->line, n->last->pos + sz - 1, NULL); 1205 1206 post_hyph(mdoc); 1207 } 1208 1209 static void 1210 post_display(POST_ARGS) 1211 { 1212 struct roff_node *n, *np; 1213 1214 n = mdoc->last; 1215 switch (n->type) { 1216 case ROFFT_BODY: 1217 if (n->end != ENDBODY_NOT) { 1218 if (n->tok == MDOC_Bd && 1219 n->body->parent->args == NULL) 1220 roff_node_delete(mdoc, n); 1221 } else if (n->child == NULL) 1222 mandoc_msg(MANDOCERR_BLK_EMPTY, mdoc->parse, 1223 n->line, n->pos, roff_name[n->tok]); 1224 else if (n->tok == MDOC_D1) 1225 post_hyph(mdoc); 1226 break; 1227 case ROFFT_BLOCK: 1228 if (n->tok == MDOC_Bd) { 1229 if (n->args == NULL) { 1230 mandoc_msg(MANDOCERR_BD_NOARG, 1231 mdoc->parse, n->line, n->pos, "Bd"); 1232 mdoc->next = ROFF_NEXT_SIBLING; 1233 while (n->body->child != NULL) 1234 mdoc_node_relink(mdoc, 1235 n->body->child); 1236 roff_node_delete(mdoc, n); 1237 break; 1238 } 1239 post_bd(mdoc); 1240 post_prevpar(mdoc); 1241 } 1242 for (np = n->parent; np != NULL; np = np->parent) { 1243 if (np->type == ROFFT_BLOCK && np->tok == MDOC_Bd) { 1244 mandoc_vmsg(MANDOCERR_BD_NEST, 1245 mdoc->parse, n->line, n->pos, 1246 "%s in Bd", roff_name[n->tok]); 1247 break; 1248 } 1249 } 1250 break; 1251 default: 1252 break; 1253 } 1254 } 1255 1256 static void 1257 post_defaults(POST_ARGS) 1258 { 1259 struct roff_node *nn; 1260 1261 if (mdoc->last->child != NULL) { 1262 post_delim(mdoc); 1263 return; 1264 } 1265 1266 /* 1267 * The `Ar' defaults to "file ..." if no value is provided as an 1268 * argument; the `Mt' and `Pa' macros use "~"; the `Li' just 1269 * gets an empty string. 1270 */ 1271 1272 nn = mdoc->last; 1273 switch (nn->tok) { 1274 case MDOC_Ar: 1275 mdoc->next = ROFF_NEXT_CHILD; 1276 roff_word_alloc(mdoc, nn->line, nn->pos, "file"); 1277 mdoc->last->flags |= NODE_NOSRC; 1278 roff_word_alloc(mdoc, nn->line, nn->pos, "..."); 1279 mdoc->last->flags |= NODE_NOSRC; 1280 break; 1281 case MDOC_Pa: 1282 case MDOC_Mt: 1283 mdoc->next = ROFF_NEXT_CHILD; 1284 roff_word_alloc(mdoc, nn->line, nn->pos, "~"); 1285 mdoc->last->flags |= NODE_NOSRC; 1286 break; 1287 default: 1288 abort(); 1289 } 1290 mdoc->last = nn; 1291 } 1292 1293 static void 1294 post_at(POST_ARGS) 1295 { 1296 struct roff_node *n, *nch; 1297 const char *att; 1298 1299 n = mdoc->last; 1300 nch = n->child; 1301 1302 /* 1303 * If we have a child, look it up in the standard keys. If a 1304 * key exist, use that instead of the child; if it doesn't, 1305 * prefix "AT&T UNIX " to the existing data. 1306 */ 1307 1308 att = NULL; 1309 if (nch != NULL && ((att = mdoc_a2att(nch->string)) == NULL)) 1310 mandoc_vmsg(MANDOCERR_AT_BAD, mdoc->parse, 1311 nch->line, nch->pos, "At %s", nch->string); 1312 1313 mdoc->next = ROFF_NEXT_CHILD; 1314 if (att != NULL) { 1315 roff_word_alloc(mdoc, nch->line, nch->pos, att); 1316 nch->flags |= NODE_NOPRT; 1317 } else 1318 roff_word_alloc(mdoc, n->line, n->pos, "AT&T UNIX"); 1319 mdoc->last->flags |= NODE_NOSRC; 1320 mdoc->last = n; 1321 } 1322 1323 static void 1324 post_an(POST_ARGS) 1325 { 1326 struct roff_node *np, *nch; 1327 1328 post_an_norm(mdoc); 1329 1330 np = mdoc->last; 1331 nch = np->child; 1332 if (np->norm->An.auth == AUTH__NONE) { 1333 if (nch == NULL) 1334 mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse, 1335 np->line, np->pos, "An"); 1336 else 1337 post_delim(mdoc); 1338 } else if (nch != NULL) 1339 mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse, 1340 nch->line, nch->pos, "An ... %s", nch->string); 1341 } 1342 1343 static void 1344 post_en(POST_ARGS) 1345 { 1346 1347 post_obsolete(mdoc); 1348 if (mdoc->last->type == ROFFT_BLOCK) 1349 mdoc->last->norm->Es = mdoc->last_es; 1350 } 1351 1352 static void 1353 post_es(POST_ARGS) 1354 { 1355 1356 post_obsolete(mdoc); 1357 mdoc->last_es = mdoc->last; 1358 } 1359 1360 static void 1361 post_xx(POST_ARGS) 1362 { 1363 struct roff_node *n; 1364 const char *os; 1365 1366 post_delim(mdoc); 1367 1368 n = mdoc->last; 1369 switch (n->tok) { 1370 case MDOC_Bsx: 1371 os = "BSD/OS"; 1372 break; 1373 case MDOC_Dx: 1374 os = "DragonFly"; 1375 break; 1376 case MDOC_Fx: 1377 os = "FreeBSD"; 1378 break; 1379 case MDOC_Nx: 1380 os = "NetBSD"; 1381 break; 1382 case MDOC_Ox: 1383 os = "OpenBSD"; 1384 break; 1385 case MDOC_Ux: 1386 os = "UNIX"; 1387 break; 1388 default: 1389 abort(); 1390 } 1391 mdoc->next = ROFF_NEXT_CHILD; 1392 roff_word_alloc(mdoc, n->line, n->pos, os); 1393 mdoc->last->flags |= NODE_NOSRC; 1394 mdoc->last = n; 1395 } 1396 1397 static void 1398 post_it(POST_ARGS) 1399 { 1400 struct roff_node *nbl, *nit, *nch; 1401 int i, cols; 1402 enum mdoc_list lt; 1403 1404 post_prevpar(mdoc); 1405 1406 nit = mdoc->last; 1407 if (nit->type != ROFFT_BLOCK) 1408 return; 1409 1410 nbl = nit->parent->parent; 1411 lt = nbl->norm->Bl.type; 1412 1413 switch (lt) { 1414 case LIST_tag: 1415 case LIST_hang: 1416 case LIST_ohang: 1417 case LIST_inset: 1418 case LIST_diag: 1419 if (nit->head->child == NULL) 1420 mandoc_vmsg(MANDOCERR_IT_NOHEAD, 1421 mdoc->parse, nit->line, nit->pos, 1422 "Bl -%s It", 1423 mdoc_argnames[nbl->args->argv[0].arg]); 1424 break; 1425 case LIST_bullet: 1426 case LIST_dash: 1427 case LIST_enum: 1428 case LIST_hyphen: 1429 if (nit->body == NULL || nit->body->child == NULL) 1430 mandoc_vmsg(MANDOCERR_IT_NOBODY, 1431 mdoc->parse, nit->line, nit->pos, 1432 "Bl -%s It", 1433 mdoc_argnames[nbl->args->argv[0].arg]); 1434 /* FALLTHROUGH */ 1435 case LIST_item: 1436 if ((nch = nit->head->child) != NULL) 1437 mandoc_vmsg(MANDOCERR_ARG_SKIP, mdoc->parse, 1438 nit->line, nit->pos, "It %s", 1439 nch->string == NULL ? roff_name[nch->tok] : 1440 nch->string); 1441 break; 1442 case LIST_column: 1443 cols = (int)nbl->norm->Bl.ncols; 1444 1445 assert(nit->head->child == NULL); 1446 1447 i = 0; 1448 for (nch = nit->child; nch != NULL; nch = nch->next) 1449 if (nch->type == ROFFT_BODY) 1450 i++; 1451 1452 if (i < cols || i > cols + 1) 1453 mandoc_vmsg(MANDOCERR_BL_COL, 1454 mdoc->parse, nit->line, nit->pos, 1455 "%d columns, %d cells", cols, i); 1456 break; 1457 default: 1458 abort(); 1459 } 1460 } 1461 1462 static void 1463 post_bl_block(POST_ARGS) 1464 { 1465 struct roff_node *n, *ni, *nc; 1466 1467 post_prevpar(mdoc); 1468 1469 n = mdoc->last; 1470 for (ni = n->body->child; ni != NULL; ni = ni->next) { 1471 if (ni->body == NULL) 1472 continue; 1473 nc = ni->body->last; 1474 while (nc != NULL) { 1475 switch (nc->tok) { 1476 case MDOC_Pp: 1477 case MDOC_Lp: 1478 case ROFF_br: 1479 break; 1480 default: 1481 nc = NULL; 1482 continue; 1483 } 1484 if (ni->next == NULL) { 1485 mandoc_msg(MANDOCERR_PAR_MOVE, 1486 mdoc->parse, nc->line, nc->pos, 1487 roff_name[nc->tok]); 1488 mdoc_node_relink(mdoc, nc); 1489 } else if (n->norm->Bl.comp == 0 && 1490 n->norm->Bl.type != LIST_column) { 1491 mandoc_vmsg(MANDOCERR_PAR_SKIP, 1492 mdoc->parse, nc->line, nc->pos, 1493 "%s before It", roff_name[nc->tok]); 1494 roff_node_delete(mdoc, nc); 1495 } else 1496 break; 1497 nc = ni->body->last; 1498 } 1499 } 1500 } 1501 1502 /* 1503 * If the argument of -offset or -width is a macro, 1504 * replace it with the associated default width. 1505 */ 1506 static void 1507 rewrite_macro2len(struct roff_man *mdoc, char **arg) 1508 { 1509 size_t width; 1510 enum roff_tok tok; 1511 1512 if (*arg == NULL) 1513 return; 1514 else if ( ! strcmp(*arg, "Ds")) 1515 width = 6; 1516 else if ((tok = roffhash_find(mdoc->mdocmac, *arg, 0)) == TOKEN_NONE) 1517 return; 1518 else 1519 width = macro2len(tok); 1520 1521 free(*arg); 1522 mandoc_asprintf(arg, "%zun", width); 1523 } 1524 1525 static void 1526 post_bl_head(POST_ARGS) 1527 { 1528 struct roff_node *nbl, *nh, *nch, *nnext; 1529 struct mdoc_argv *argv; 1530 int i, j; 1531 1532 post_bl_norm(mdoc); 1533 1534 nh = mdoc->last; 1535 if (nh->norm->Bl.type != LIST_column) { 1536 if ((nch = nh->child) == NULL) 1537 return; 1538 mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse, 1539 nch->line, nch->pos, "Bl ... %s", nch->string); 1540 while (nch != NULL) { 1541 roff_node_delete(mdoc, nch); 1542 nch = nh->child; 1543 } 1544 return; 1545 } 1546 1547 /* 1548 * Append old-style lists, where the column width specifiers 1549 * trail as macro parameters, to the new-style ("normal-form") 1550 * lists where they're argument values following -column. 1551 */ 1552 1553 if (nh->child == NULL) 1554 return; 1555 1556 nbl = nh->parent; 1557 for (j = 0; j < (int)nbl->args->argc; j++) 1558 if (nbl->args->argv[j].arg == MDOC_Column) 1559 break; 1560 1561 assert(j < (int)nbl->args->argc); 1562 1563 /* 1564 * Accommodate for new-style groff column syntax. Shuffle the 1565 * child nodes, all of which must be TEXT, as arguments for the 1566 * column field. Then, delete the head children. 1567 */ 1568 1569 argv = nbl->args->argv + j; 1570 i = argv->sz; 1571 for (nch = nh->child; nch != NULL; nch = nch->next) 1572 argv->sz++; 1573 argv->value = mandoc_reallocarray(argv->value, 1574 argv->sz, sizeof(char *)); 1575 1576 nh->norm->Bl.ncols = argv->sz; 1577 nh->norm->Bl.cols = (void *)argv->value; 1578 1579 for (nch = nh->child; nch != NULL; nch = nnext) { 1580 argv->value[i++] = nch->string; 1581 nch->string = NULL; 1582 nnext = nch->next; 1583 roff_node_delete(NULL, nch); 1584 } 1585 nh->child = NULL; 1586 } 1587 1588 static void 1589 post_bl(POST_ARGS) 1590 { 1591 struct roff_node *nparent, *nprev; /* of the Bl block */ 1592 struct roff_node *nblock, *nbody; /* of the Bl */ 1593 struct roff_node *nchild, *nnext; /* of the Bl body */ 1594 const char *prev_Er; 1595 int order; 1596 1597 nbody = mdoc->last; 1598 switch (nbody->type) { 1599 case ROFFT_BLOCK: 1600 post_bl_block(mdoc); 1601 return; 1602 case ROFFT_HEAD: 1603 post_bl_head(mdoc); 1604 return; 1605 case ROFFT_BODY: 1606 break; 1607 default: 1608 return; 1609 } 1610 if (nbody->end != ENDBODY_NOT) 1611 return; 1612 1613 nchild = nbody->child; 1614 if (nchild == NULL) { 1615 mandoc_msg(MANDOCERR_BLK_EMPTY, mdoc->parse, 1616 nbody->line, nbody->pos, "Bl"); 1617 return; 1618 } 1619 while (nchild != NULL) { 1620 nnext = nchild->next; 1621 if (nchild->tok == MDOC_It || 1622 (nchild->tok == MDOC_Sm && 1623 nnext != NULL && nnext->tok == MDOC_It)) { 1624 nchild = nnext; 1625 continue; 1626 } 1627 1628 /* 1629 * In .Bl -column, the first rows may be implicit, 1630 * that is, they may not start with .It macros. 1631 * Such rows may be followed by nodes generated on the 1632 * roff level, for example .TS, which cannot be moved 1633 * out of the list. In that case, wrap such roff nodes 1634 * into an implicit row. 1635 */ 1636 1637 if (nchild->prev != NULL) { 1638 mdoc->last = nchild; 1639 mdoc->next = ROFF_NEXT_SIBLING; 1640 roff_block_alloc(mdoc, nchild->line, 1641 nchild->pos, MDOC_It); 1642 roff_head_alloc(mdoc, nchild->line, 1643 nchild->pos, MDOC_It); 1644 mdoc->next = ROFF_NEXT_SIBLING; 1645 roff_body_alloc(mdoc, nchild->line, 1646 nchild->pos, MDOC_It); 1647 while (nchild->tok != MDOC_It) { 1648 mdoc_node_relink(mdoc, nchild); 1649 if ((nchild = nnext) == NULL) 1650 break; 1651 nnext = nchild->next; 1652 mdoc->next = ROFF_NEXT_SIBLING; 1653 } 1654 mdoc->last = nbody; 1655 continue; 1656 } 1657 1658 mandoc_msg(MANDOCERR_BL_MOVE, mdoc->parse, 1659 nchild->line, nchild->pos, roff_name[nchild->tok]); 1660 1661 /* 1662 * Move the node out of the Bl block. 1663 * First, collect all required node pointers. 1664 */ 1665 1666 nblock = nbody->parent; 1667 nprev = nblock->prev; 1668 nparent = nblock->parent; 1669 1670 /* 1671 * Unlink this child. 1672 */ 1673 1674 nbody->child = nnext; 1675 if (nnext == NULL) 1676 nbody->last = NULL; 1677 else 1678 nnext->prev = NULL; 1679 1680 /* 1681 * Relink this child. 1682 */ 1683 1684 nchild->parent = nparent; 1685 nchild->prev = nprev; 1686 nchild->next = nblock; 1687 1688 nblock->prev = nchild; 1689 if (nprev == NULL) 1690 nparent->child = nchild; 1691 else 1692 nprev->next = nchild; 1693 1694 nchild = nnext; 1695 } 1696 1697 if (mdoc->meta.os_e != MDOC_OS_NETBSD) 1698 return; 1699 1700 prev_Er = NULL; 1701 for (nchild = nbody->child; nchild != NULL; nchild = nchild->next) { 1702 if (nchild->tok != MDOC_It) 1703 continue; 1704 if ((nnext = nchild->head->child) == NULL) 1705 continue; 1706 if (nnext->type == ROFFT_BLOCK) 1707 nnext = nnext->body->child; 1708 if (nnext == NULL || nnext->tok != MDOC_Er) 1709 continue; 1710 nnext = nnext->child; 1711 if (prev_Er != NULL) { 1712 order = strcmp(prev_Er, nnext->string); 1713 if (order > 0) 1714 mandoc_vmsg(MANDOCERR_ER_ORDER, 1715 mdoc->parse, nnext->line, nnext->pos, 1716 "Er %s %s", prev_Er, nnext->string); 1717 else if (order == 0) 1718 mandoc_vmsg(MANDOCERR_ER_REP, 1719 mdoc->parse, nnext->line, nnext->pos, 1720 "Er %s", prev_Er); 1721 } 1722 prev_Er = nnext->string; 1723 } 1724 } 1725 1726 static void 1727 post_bk(POST_ARGS) 1728 { 1729 struct roff_node *n; 1730 1731 n = mdoc->last; 1732 1733 if (n->type == ROFFT_BLOCK && n->body->child == NULL) { 1734 mandoc_msg(MANDOCERR_BLK_EMPTY, 1735 mdoc->parse, n->line, n->pos, "Bk"); 1736 roff_node_delete(mdoc, n); 1737 } 1738 } 1739 1740 static void 1741 post_sm(POST_ARGS) 1742 { 1743 struct roff_node *nch; 1744 1745 nch = mdoc->last->child; 1746 1747 if (nch == NULL) { 1748 mdoc->flags ^= MDOC_SMOFF; 1749 return; 1750 } 1751 1752 assert(nch->type == ROFFT_TEXT); 1753 1754 if ( ! strcmp(nch->string, "on")) { 1755 mdoc->flags &= ~MDOC_SMOFF; 1756 return; 1757 } 1758 if ( ! strcmp(nch->string, "off")) { 1759 mdoc->flags |= MDOC_SMOFF; 1760 return; 1761 } 1762 1763 mandoc_vmsg(MANDOCERR_SM_BAD, 1764 mdoc->parse, nch->line, nch->pos, 1765 "%s %s", roff_name[mdoc->last->tok], nch->string); 1766 mdoc_node_relink(mdoc, nch); 1767 return; 1768 } 1769 1770 static void 1771 post_root(POST_ARGS) 1772 { 1773 struct roff_node *n; 1774 1775 /* Add missing prologue data. */ 1776 1777 if (mdoc->meta.date == NULL) 1778 mdoc->meta.date = mdoc->quick ? mandoc_strdup("") : 1779 mandoc_normdate(mdoc, NULL, 0, 0); 1780 1781 if (mdoc->meta.title == NULL) { 1782 mandoc_msg(MANDOCERR_DT_NOTITLE, 1783 mdoc->parse, 0, 0, "EOF"); 1784 mdoc->meta.title = mandoc_strdup("UNTITLED"); 1785 } 1786 1787 if (mdoc->meta.vol == NULL) 1788 mdoc->meta.vol = mandoc_strdup("LOCAL"); 1789 1790 if (mdoc->meta.os == NULL) { 1791 mandoc_msg(MANDOCERR_OS_MISSING, 1792 mdoc->parse, 0, 0, NULL); 1793 mdoc->meta.os = mandoc_strdup(""); 1794 } else if (mdoc->meta.os_e && 1795 (mdoc->meta.rcsids & (1 << mdoc->meta.os_e)) == 0) 1796 mandoc_msg(MANDOCERR_RCS_MISSING, 1797 mdoc->parse, 0, 0, NULL); 1798 1799 /* Check that we begin with a proper `Sh'. */ 1800 1801 n = mdoc->first->child; 1802 while (n != NULL && n->tok != TOKEN_NONE && 1803 mdoc_macros[n->tok].flags & MDOC_PROLOGUE) 1804 n = n->next; 1805 1806 if (n == NULL) 1807 mandoc_msg(MANDOCERR_DOC_EMPTY, mdoc->parse, 0, 0, NULL); 1808 else if (n->tok != MDOC_Sh) 1809 mandoc_msg(MANDOCERR_SEC_BEFORE, mdoc->parse, 1810 n->line, n->pos, roff_name[n->tok]); 1811 } 1812 1813 static void 1814 post_rs(POST_ARGS) 1815 { 1816 struct roff_node *np, *nch, *next, *prev; 1817 int i, j; 1818 1819 np = mdoc->last; 1820 1821 if (np->type != ROFFT_BODY) 1822 return; 1823 1824 if (np->child == NULL) { 1825 mandoc_msg(MANDOCERR_RS_EMPTY, mdoc->parse, 1826 np->line, np->pos, "Rs"); 1827 return; 1828 } 1829 1830 /* 1831 * The full `Rs' block needs special handling to order the 1832 * sub-elements according to `rsord'. Pick through each element 1833 * and correctly order it. This is an insertion sort. 1834 */ 1835 1836 next = NULL; 1837 for (nch = np->child->next; nch != NULL; nch = next) { 1838 /* Determine order number of this child. */ 1839 for (i = 0; i < RSORD_MAX; i++) 1840 if (rsord[i] == nch->tok) 1841 break; 1842 1843 if (i == RSORD_MAX) { 1844 mandoc_msg(MANDOCERR_RS_BAD, mdoc->parse, 1845 nch->line, nch->pos, roff_name[nch->tok]); 1846 i = -1; 1847 } else if (nch->tok == MDOC__J || nch->tok == MDOC__B) 1848 np->norm->Rs.quote_T++; 1849 1850 /* 1851 * Remove this child from the chain. This somewhat 1852 * repeats roff_node_unlink(), but since we're 1853 * just re-ordering, there's no need for the 1854 * full unlink process. 1855 */ 1856 1857 if ((next = nch->next) != NULL) 1858 next->prev = nch->prev; 1859 1860 if ((prev = nch->prev) != NULL) 1861 prev->next = nch->next; 1862 1863 nch->prev = nch->next = NULL; 1864 1865 /* 1866 * Scan back until we reach a node that's 1867 * to be ordered before this child. 1868 */ 1869 1870 for ( ; prev ; prev = prev->prev) { 1871 /* Determine order of `prev'. */ 1872 for (j = 0; j < RSORD_MAX; j++) 1873 if (rsord[j] == prev->tok) 1874 break; 1875 if (j == RSORD_MAX) 1876 j = -1; 1877 1878 if (j <= i) 1879 break; 1880 } 1881 1882 /* 1883 * Set this child back into its correct place 1884 * in front of the `prev' node. 1885 */ 1886 1887 nch->prev = prev; 1888 1889 if (prev == NULL) { 1890 np->child->prev = nch; 1891 nch->next = np->child; 1892 np->child = nch; 1893 } else { 1894 if (prev->next) 1895 prev->next->prev = nch; 1896 nch->next = prev->next; 1897 prev->next = nch; 1898 } 1899 } 1900 } 1901 1902 /* 1903 * For some arguments of some macros, 1904 * convert all breakable hyphens into ASCII_HYPH. 1905 */ 1906 static void 1907 post_hyph(POST_ARGS) 1908 { 1909 struct roff_node *nch; 1910 char *cp; 1911 1912 for (nch = mdoc->last->child; nch != NULL; nch = nch->next) { 1913 if (nch->type != ROFFT_TEXT) 1914 continue; 1915 cp = nch->string; 1916 if (*cp == '\0') 1917 continue; 1918 while (*(++cp) != '\0') 1919 if (*cp == '-' && 1920 isalpha((unsigned char)cp[-1]) && 1921 isalpha((unsigned char)cp[1])) 1922 *cp = ASCII_HYPH; 1923 } 1924 } 1925 1926 static void 1927 post_ns(POST_ARGS) 1928 { 1929 1930 if (mdoc->last->flags & NODE_LINE) 1931 mandoc_msg(MANDOCERR_NS_SKIP, mdoc->parse, 1932 mdoc->last->line, mdoc->last->pos, NULL); 1933 } 1934 1935 static void 1936 post_sh(POST_ARGS) 1937 { 1938 1939 post_ignpar(mdoc); 1940 1941 switch (mdoc->last->type) { 1942 case ROFFT_HEAD: 1943 post_sh_head(mdoc); 1944 break; 1945 case ROFFT_BODY: 1946 switch (mdoc->lastsec) { 1947 case SEC_NAME: 1948 post_sh_name(mdoc); 1949 break; 1950 case SEC_SEE_ALSO: 1951 post_sh_see_also(mdoc); 1952 break; 1953 case SEC_AUTHORS: 1954 post_sh_authors(mdoc); 1955 break; 1956 default: 1957 break; 1958 } 1959 break; 1960 default: 1961 break; 1962 } 1963 } 1964 1965 static void 1966 post_sh_name(POST_ARGS) 1967 { 1968 struct roff_node *n; 1969 int hasnm, hasnd; 1970 1971 hasnm = hasnd = 0; 1972 1973 for (n = mdoc->last->child; n != NULL; n = n->next) { 1974 switch (n->tok) { 1975 case MDOC_Nm: 1976 if (hasnm && n->child != NULL) 1977 mandoc_vmsg(MANDOCERR_NAMESEC_PUNCT, 1978 mdoc->parse, n->line, n->pos, 1979 "Nm %s", n->child->string); 1980 hasnm = 1; 1981 continue; 1982 case MDOC_Nd: 1983 hasnd = 1; 1984 if (n->next != NULL) 1985 mandoc_msg(MANDOCERR_NAMESEC_ND, 1986 mdoc->parse, n->line, n->pos, NULL); 1987 break; 1988 case TOKEN_NONE: 1989 if (n->type == ROFFT_TEXT && 1990 n->string[0] == ',' && n->string[1] == '\0' && 1991 n->next != NULL && n->next->tok == MDOC_Nm) { 1992 n = n->next; 1993 continue; 1994 } 1995 /* FALLTHROUGH */ 1996 default: 1997 mandoc_msg(MANDOCERR_NAMESEC_BAD, mdoc->parse, 1998 n->line, n->pos, roff_name[n->tok]); 1999 continue; 2000 } 2001 break; 2002 } 2003 2004 if ( ! hasnm) 2005 mandoc_msg(MANDOCERR_NAMESEC_NONM, mdoc->parse, 2006 mdoc->last->line, mdoc->last->pos, NULL); 2007 if ( ! hasnd) 2008 mandoc_msg(MANDOCERR_NAMESEC_NOND, mdoc->parse, 2009 mdoc->last->line, mdoc->last->pos, NULL); 2010 } 2011 2012 static void 2013 post_sh_see_also(POST_ARGS) 2014 { 2015 const struct roff_node *n; 2016 const char *name, *sec; 2017 const char *lastname, *lastsec, *lastpunct; 2018 int cmp; 2019 2020 n = mdoc->last->child; 2021 lastname = lastsec = lastpunct = NULL; 2022 while (n != NULL) { 2023 if (n->tok != MDOC_Xr || 2024 n->child == NULL || 2025 n->child->next == NULL) 2026 break; 2027 2028 /* Process one .Xr node. */ 2029 2030 name = n->child->string; 2031 sec = n->child->next->string; 2032 if (lastsec != NULL) { 2033 if (lastpunct[0] != ',' || lastpunct[1] != '\0') 2034 mandoc_vmsg(MANDOCERR_XR_PUNCT, 2035 mdoc->parse, n->line, n->pos, 2036 "%s before %s(%s)", lastpunct, 2037 name, sec); 2038 cmp = strcmp(lastsec, sec); 2039 if (cmp > 0) 2040 mandoc_vmsg(MANDOCERR_XR_ORDER, 2041 mdoc->parse, n->line, n->pos, 2042 "%s(%s) after %s(%s)", name, 2043 sec, lastname, lastsec); 2044 else if (cmp == 0 && 2045 strcasecmp(lastname, name) > 0) 2046 mandoc_vmsg(MANDOCERR_XR_ORDER, 2047 mdoc->parse, n->line, n->pos, 2048 "%s after %s", name, lastname); 2049 } 2050 lastname = name; 2051 lastsec = sec; 2052 2053 /* Process the following node. */ 2054 2055 n = n->next; 2056 if (n == NULL) 2057 break; 2058 if (n->tok == MDOC_Xr) { 2059 lastpunct = "none"; 2060 continue; 2061 } 2062 if (n->type != ROFFT_TEXT) 2063 break; 2064 for (name = n->string; *name != '\0'; name++) 2065 if (isalpha((const unsigned char)*name)) 2066 return; 2067 lastpunct = n->string; 2068 if (n->next == NULL || n->next->tok == MDOC_Rs) 2069 mandoc_vmsg(MANDOCERR_XR_PUNCT, mdoc->parse, 2070 n->line, n->pos, "%s after %s(%s)", 2071 lastpunct, lastname, lastsec); 2072 n = n->next; 2073 } 2074 } 2075 2076 static int 2077 child_an(const struct roff_node *n) 2078 { 2079 2080 for (n = n->child; n != NULL; n = n->next) 2081 if ((n->tok == MDOC_An && n->child != NULL) || child_an(n)) 2082 return 1; 2083 return 0; 2084 } 2085 2086 static void 2087 post_sh_authors(POST_ARGS) 2088 { 2089 2090 if ( ! child_an(mdoc->last)) 2091 mandoc_msg(MANDOCERR_AN_MISSING, mdoc->parse, 2092 mdoc->last->line, mdoc->last->pos, NULL); 2093 } 2094 2095 static void 2096 post_sh_head(POST_ARGS) 2097 { 2098 struct roff_node *nch; 2099 const char *goodsec; 2100 enum roff_sec sec; 2101 2102 /* 2103 * Process a new section. Sections are either "named" or 2104 * "custom". Custom sections are user-defined, while named ones 2105 * follow a conventional order and may only appear in certain 2106 * manual sections. 2107 */ 2108 2109 sec = mdoc->last->sec; 2110 2111 /* The NAME should be first. */ 2112 2113 if (sec != SEC_NAME && mdoc->lastnamed == SEC_NONE) 2114 mandoc_vmsg(MANDOCERR_NAMESEC_FIRST, mdoc->parse, 2115 mdoc->last->line, mdoc->last->pos, "Sh %s", 2116 sec != SEC_CUSTOM ? secnames[sec] : 2117 (nch = mdoc->last->child) == NULL ? "" : 2118 nch->type == ROFFT_TEXT ? nch->string : 2119 roff_name[nch->tok]); 2120 2121 /* The SYNOPSIS gets special attention in other areas. */ 2122 2123 if (sec == SEC_SYNOPSIS) { 2124 roff_setreg(mdoc->roff, "nS", 1, '='); 2125 mdoc->flags |= MDOC_SYNOPSIS; 2126 } else { 2127 roff_setreg(mdoc->roff, "nS", 0, '='); 2128 mdoc->flags &= ~MDOC_SYNOPSIS; 2129 } 2130 2131 /* Mark our last section. */ 2132 2133 mdoc->lastsec = sec; 2134 2135 /* We don't care about custom sections after this. */ 2136 2137 if (sec == SEC_CUSTOM) 2138 return; 2139 2140 /* 2141 * Check whether our non-custom section is being repeated or is 2142 * out of order. 2143 */ 2144 2145 if (sec == mdoc->lastnamed) 2146 mandoc_vmsg(MANDOCERR_SEC_REP, mdoc->parse, 2147 mdoc->last->line, mdoc->last->pos, 2148 "Sh %s", secnames[sec]); 2149 2150 if (sec < mdoc->lastnamed) 2151 mandoc_vmsg(MANDOCERR_SEC_ORDER, mdoc->parse, 2152 mdoc->last->line, mdoc->last->pos, 2153 "Sh %s", secnames[sec]); 2154 2155 /* Mark the last named section. */ 2156 2157 mdoc->lastnamed = sec; 2158 2159 /* Check particular section/manual conventions. */ 2160 2161 if (mdoc->meta.msec == NULL) 2162 return; 2163 2164 goodsec = NULL; 2165 switch (sec) { 2166 case SEC_ERRORS: 2167 if (*mdoc->meta.msec == '4') 2168 break; 2169 goodsec = "2, 3, 4, 9"; 2170 /* FALLTHROUGH */ 2171 case SEC_RETURN_VALUES: 2172 case SEC_LIBRARY: 2173 if (*mdoc->meta.msec == '2') 2174 break; 2175 if (*mdoc->meta.msec == '3') 2176 break; 2177 if (NULL == goodsec) 2178 goodsec = "2, 3, 9"; 2179 /* FALLTHROUGH */ 2180 case SEC_CONTEXT: 2181 if (*mdoc->meta.msec == '9') 2182 break; 2183 if (NULL == goodsec) 2184 goodsec = "9"; 2185 mandoc_vmsg(MANDOCERR_SEC_MSEC, mdoc->parse, 2186 mdoc->last->line, mdoc->last->pos, 2187 "Sh %s for %s only", secnames[sec], goodsec); 2188 break; 2189 default: 2190 break; 2191 } 2192 } 2193 2194 static void 2195 post_xr(POST_ARGS) 2196 { 2197 struct roff_node *n, *nch; 2198 2199 n = mdoc->last; 2200 nch = n->child; 2201 if (nch->next == NULL) { 2202 mandoc_vmsg(MANDOCERR_XR_NOSEC, mdoc->parse, 2203 n->line, n->pos, "Xr %s", nch->string); 2204 } else 2205 assert(nch->next == n->last); 2206 post_delim(mdoc); 2207 } 2208 2209 static void 2210 post_ignpar(POST_ARGS) 2211 { 2212 struct roff_node *np; 2213 2214 switch (mdoc->last->type) { 2215 case ROFFT_BLOCK: 2216 post_prevpar(mdoc); 2217 return; 2218 case ROFFT_HEAD: 2219 post_hyph(mdoc); 2220 return; 2221 case ROFFT_BODY: 2222 break; 2223 default: 2224 return; 2225 } 2226 2227 if ((np = mdoc->last->child) != NULL) 2228 if (np->tok == MDOC_Pp || np->tok == MDOC_Lp) { 2229 mandoc_vmsg(MANDOCERR_PAR_SKIP, 2230 mdoc->parse, np->line, np->pos, 2231 "%s after %s", roff_name[np->tok], 2232 roff_name[mdoc->last->tok]); 2233 roff_node_delete(mdoc, np); 2234 } 2235 2236 if ((np = mdoc->last->last) != NULL) 2237 if (np->tok == MDOC_Pp || np->tok == MDOC_Lp) { 2238 mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse, 2239 np->line, np->pos, "%s at the end of %s", 2240 roff_name[np->tok], 2241 roff_name[mdoc->last->tok]); 2242 roff_node_delete(mdoc, np); 2243 } 2244 } 2245 2246 static void 2247 post_prevpar(POST_ARGS) 2248 { 2249 struct roff_node *n; 2250 2251 n = mdoc->last; 2252 if (NULL == n->prev) 2253 return; 2254 if (n->type != ROFFT_ELEM && n->type != ROFFT_BLOCK) 2255 return; 2256 2257 /* 2258 * Don't allow prior `Lp' or `Pp' prior to a paragraph-type 2259 * block: `Lp', `Pp', or non-compact `Bd' or `Bl'. 2260 */ 2261 2262 if (n->prev->tok != MDOC_Pp && 2263 n->prev->tok != MDOC_Lp && 2264 n->prev->tok != ROFF_br) 2265 return; 2266 if (n->tok == MDOC_Bl && n->norm->Bl.comp) 2267 return; 2268 if (n->tok == MDOC_Bd && n->norm->Bd.comp) 2269 return; 2270 if (n->tok == MDOC_It && n->parent->norm->Bl.comp) 2271 return; 2272 2273 mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse, 2274 n->prev->line, n->prev->pos, "%s before %s", 2275 roff_name[n->prev->tok], roff_name[n->tok]); 2276 roff_node_delete(mdoc, n->prev); 2277 } 2278 2279 static void 2280 post_par(POST_ARGS) 2281 { 2282 struct roff_node *np; 2283 2284 np = mdoc->last; 2285 if (np->tok != ROFF_br && np->tok != ROFF_sp) 2286 post_prevpar(mdoc); 2287 2288 if (np->tok == ROFF_sp) { 2289 if (np->child != NULL && np->child->next != NULL) 2290 mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse, 2291 np->child->next->line, np->child->next->pos, 2292 "sp ... %s", np->child->next->string); 2293 } else if (np->child != NULL) 2294 mandoc_vmsg(MANDOCERR_ARG_SKIP, 2295 mdoc->parse, np->line, np->pos, "%s %s", 2296 roff_name[np->tok], np->child->string); 2297 2298 if ((np = mdoc->last->prev) == NULL) { 2299 np = mdoc->last->parent; 2300 if (np->tok != MDOC_Sh && np->tok != MDOC_Ss) 2301 return; 2302 } else if (np->tok != MDOC_Pp && np->tok != MDOC_Lp && 2303 (mdoc->last->tok != ROFF_br || 2304 (np->tok != ROFF_sp && np->tok != ROFF_br))) 2305 return; 2306 2307 mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse, 2308 mdoc->last->line, mdoc->last->pos, "%s after %s", 2309 roff_name[mdoc->last->tok], roff_name[np->tok]); 2310 roff_node_delete(mdoc, mdoc->last); 2311 } 2312 2313 static void 2314 post_dd(POST_ARGS) 2315 { 2316 struct roff_node *n; 2317 char *datestr; 2318 2319 n = mdoc->last; 2320 n->flags |= NODE_NOPRT; 2321 2322 if (mdoc->meta.date != NULL) { 2323 mandoc_msg(MANDOCERR_PROLOG_REP, mdoc->parse, 2324 n->line, n->pos, "Dd"); 2325 free(mdoc->meta.date); 2326 } else if (mdoc->flags & MDOC_PBODY) 2327 mandoc_msg(MANDOCERR_PROLOG_LATE, mdoc->parse, 2328 n->line, n->pos, "Dd"); 2329 else if (mdoc->meta.title != NULL) 2330 mandoc_msg(MANDOCERR_PROLOG_ORDER, mdoc->parse, 2331 n->line, n->pos, "Dd after Dt"); 2332 else if (mdoc->meta.os != NULL) 2333 mandoc_msg(MANDOCERR_PROLOG_ORDER, mdoc->parse, 2334 n->line, n->pos, "Dd after Os"); 2335 2336 if (n->child == NULL || n->child->string[0] == '\0') { 2337 mdoc->meta.date = mdoc->quick ? mandoc_strdup("") : 2338 mandoc_normdate(mdoc, NULL, n->line, n->pos); 2339 return; 2340 } 2341 2342 datestr = NULL; 2343 deroff(&datestr, n); 2344 if (mdoc->quick) 2345 mdoc->meta.date = datestr; 2346 else { 2347 mdoc->meta.date = mandoc_normdate(mdoc, 2348 datestr, n->line, n->pos); 2349 free(datestr); 2350 } 2351 } 2352 2353 static void 2354 post_dt(POST_ARGS) 2355 { 2356 struct roff_node *nn, *n; 2357 const char *cp; 2358 char *p; 2359 2360 n = mdoc->last; 2361 n->flags |= NODE_NOPRT; 2362 2363 if (mdoc->flags & MDOC_PBODY) { 2364 mandoc_msg(MANDOCERR_DT_LATE, mdoc->parse, 2365 n->line, n->pos, "Dt"); 2366 return; 2367 } 2368 2369 if (mdoc->meta.title != NULL) 2370 mandoc_msg(MANDOCERR_PROLOG_REP, mdoc->parse, 2371 n->line, n->pos, "Dt"); 2372 else if (mdoc->meta.os != NULL) 2373 mandoc_msg(MANDOCERR_PROLOG_ORDER, mdoc->parse, 2374 n->line, n->pos, "Dt after Os"); 2375 2376 free(mdoc->meta.title); 2377 free(mdoc->meta.msec); 2378 free(mdoc->meta.vol); 2379 free(mdoc->meta.arch); 2380 2381 mdoc->meta.title = NULL; 2382 mdoc->meta.msec = NULL; 2383 mdoc->meta.vol = NULL; 2384 mdoc->meta.arch = NULL; 2385 2386 /* Mandatory first argument: title. */ 2387 2388 nn = n->child; 2389 if (nn == NULL || *nn->string == '\0') { 2390 mandoc_msg(MANDOCERR_DT_NOTITLE, 2391 mdoc->parse, n->line, n->pos, "Dt"); 2392 mdoc->meta.title = mandoc_strdup("UNTITLED"); 2393 } else { 2394 mdoc->meta.title = mandoc_strdup(nn->string); 2395 2396 /* Check that all characters are uppercase. */ 2397 2398 for (p = nn->string; *p != '\0'; p++) 2399 if (islower((unsigned char)*p)) { 2400 mandoc_vmsg(MANDOCERR_TITLE_CASE, 2401 mdoc->parse, nn->line, 2402 nn->pos + (p - nn->string), 2403 "Dt %s", nn->string); 2404 break; 2405 } 2406 } 2407 2408 /* Mandatory second argument: section. */ 2409 2410 if (nn != NULL) 2411 nn = nn->next; 2412 2413 if (nn == NULL) { 2414 mandoc_vmsg(MANDOCERR_MSEC_MISSING, 2415 mdoc->parse, n->line, n->pos, 2416 "Dt %s", mdoc->meta.title); 2417 mdoc->meta.vol = mandoc_strdup("LOCAL"); 2418 return; /* msec and arch remain NULL. */ 2419 } 2420 2421 mdoc->meta.msec = mandoc_strdup(nn->string); 2422 2423 /* Infer volume title from section number. */ 2424 2425 cp = mandoc_a2msec(nn->string); 2426 if (cp == NULL) { 2427 mandoc_vmsg(MANDOCERR_MSEC_BAD, mdoc->parse, 2428 nn->line, nn->pos, "Dt ... %s", nn->string); 2429 mdoc->meta.vol = mandoc_strdup(nn->string); 2430 } else 2431 mdoc->meta.vol = mandoc_strdup(cp); 2432 2433 /* Optional third argument: architecture. */ 2434 2435 if ((nn = nn->next) == NULL) 2436 return; 2437 2438 for (p = nn->string; *p != '\0'; p++) 2439 *p = tolower((unsigned char)*p); 2440 mdoc->meta.arch = mandoc_strdup(nn->string); 2441 2442 /* Ignore fourth and later arguments. */ 2443 2444 if ((nn = nn->next) != NULL) 2445 mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse, 2446 nn->line, nn->pos, "Dt ... %s", nn->string); 2447 } 2448 2449 static void 2450 post_bx(POST_ARGS) 2451 { 2452 struct roff_node *n, *nch; 2453 const char *macro; 2454 2455 post_delim(mdoc); 2456 2457 n = mdoc->last; 2458 nch = n->child; 2459 2460 if (nch != NULL) { 2461 macro = !strcmp(nch->string, "Open") ? "Ox" : 2462 !strcmp(nch->string, "Net") ? "Nx" : 2463 !strcmp(nch->string, "Free") ? "Fx" : 2464 !strcmp(nch->string, "DragonFly") ? "Dx" : NULL; 2465 if (macro != NULL) 2466 mandoc_msg(MANDOCERR_BX, mdoc->parse, 2467 n->line, n->pos, macro); 2468 mdoc->last = nch; 2469 nch = nch->next; 2470 mdoc->next = ROFF_NEXT_SIBLING; 2471 roff_elem_alloc(mdoc, n->line, n->pos, MDOC_Ns); 2472 mdoc->last->flags |= NODE_NOSRC; 2473 mdoc->next = ROFF_NEXT_SIBLING; 2474 } else 2475 mdoc->next = ROFF_NEXT_CHILD; 2476 roff_word_alloc(mdoc, n->line, n->pos, "BSD"); 2477 mdoc->last->flags |= NODE_NOSRC; 2478 2479 if (nch == NULL) { 2480 mdoc->last = n; 2481 return; 2482 } 2483 2484 roff_elem_alloc(mdoc, n->line, n->pos, MDOC_Ns); 2485 mdoc->last->flags |= NODE_NOSRC; 2486 mdoc->next = ROFF_NEXT_SIBLING; 2487 roff_word_alloc(mdoc, n->line, n->pos, "-"); 2488 mdoc->last->flags |= NODE_NOSRC; 2489 roff_elem_alloc(mdoc, n->line, n->pos, MDOC_Ns); 2490 mdoc->last->flags |= NODE_NOSRC; 2491 mdoc->last = n; 2492 2493 /* 2494 * Make `Bx's second argument always start with an uppercase 2495 * letter. Groff checks if it's an "accepted" term, but we just 2496 * uppercase blindly. 2497 */ 2498 2499 *nch->string = (char)toupper((unsigned char)*nch->string); 2500 } 2501 2502 static void 2503 post_os(POST_ARGS) 2504 { 2505 #ifndef OSNAME 2506 struct utsname utsname; 2507 static char *defbuf; 2508 #endif 2509 struct roff_node *n; 2510 2511 n = mdoc->last; 2512 n->flags |= NODE_NOPRT; 2513 2514 if (mdoc->meta.os != NULL) 2515 mandoc_msg(MANDOCERR_PROLOG_REP, mdoc->parse, 2516 n->line, n->pos, "Os"); 2517 else if (mdoc->flags & MDOC_PBODY) 2518 mandoc_msg(MANDOCERR_PROLOG_LATE, mdoc->parse, 2519 n->line, n->pos, "Os"); 2520 2521 /* 2522 * Set the operating system by way of the `Os' macro. 2523 * The order of precedence is: 2524 * 1. the argument of the `Os' macro, unless empty 2525 * 2. the -Ios=foo command line argument, if provided 2526 * 3. -DOSNAME="\"foo\"", if provided during compilation 2527 * 4. "sysname release" from uname(3) 2528 */ 2529 2530 free(mdoc->meta.os); 2531 mdoc->meta.os = NULL; 2532 deroff(&mdoc->meta.os, n); 2533 if (mdoc->meta.os) 2534 goto out; 2535 2536 if (mdoc->defos) { 2537 mdoc->meta.os = mandoc_strdup(mdoc->defos); 2538 goto out; 2539 } 2540 2541 #ifdef OSNAME 2542 mdoc->meta.os = mandoc_strdup(OSNAME); 2543 #else /*!OSNAME */ 2544 if (defbuf == NULL) { 2545 if (uname(&utsname) == -1) { 2546 mandoc_msg(MANDOCERR_OS_UNAME, mdoc->parse, 2547 n->line, n->pos, "Os"); 2548 defbuf = mandoc_strdup("UNKNOWN"); 2549 } else 2550 mandoc_asprintf(&defbuf, "%s %s", 2551 utsname.sysname, utsname.release); 2552 } 2553 mdoc->meta.os = mandoc_strdup(defbuf); 2554 #endif /*!OSNAME*/ 2555 2556 out: mdoc->meta.os_e = strstr(mdoc->meta.os, "OpenBSD") != NULL ? 2557 MDOC_OS_OPENBSD : strstr(mdoc->meta.os, "NetBSD") != NULL ? 2558 MDOC_OS_NETBSD : MDOC_OS_OTHER; 2559 2560 /* 2561 * This is the earliest point where we can check 2562 * Mdocdate conventions because we don't know 2563 * the operating system earlier. 2564 */ 2565 2566 while (n->tok != MDOC_Dd) 2567 if ((n = n->prev) == NULL) 2568 return; 2569 if ((n = n->child) == NULL) 2570 return; 2571 if (strncmp(n->string, "$" "Mdocdate", 9)) { 2572 if (mdoc->meta.os_e == MDOC_OS_OPENBSD) 2573 mandoc_vmsg(MANDOCERR_MDOCDATE_MISSING, 2574 mdoc->parse, n->line, n->pos, 2575 "Dd %s", n->string); 2576 } else { 2577 if (mdoc->meta.os_e == MDOC_OS_NETBSD) 2578 mandoc_vmsg(MANDOCERR_MDOCDATE, 2579 mdoc->parse, n->line, n->pos, 2580 "Dd %s", n->string); 2581 } 2582 } 2583 2584 enum roff_sec 2585 mdoc_a2sec(const char *p) 2586 { 2587 int i; 2588 2589 for (i = 0; i < (int)SEC__MAX; i++) 2590 if (secnames[i] && 0 == strcmp(p, secnames[i])) 2591 return (enum roff_sec)i; 2592 2593 return SEC_CUSTOM; 2594 } 2595 2596 static size_t 2597 macro2len(enum roff_tok macro) 2598 { 2599 2600 switch (macro) { 2601 case MDOC_Ad: 2602 return 12; 2603 case MDOC_Ao: 2604 return 12; 2605 case MDOC_An: 2606 return 12; 2607 case MDOC_Aq: 2608 return 12; 2609 case MDOC_Ar: 2610 return 12; 2611 case MDOC_Bo: 2612 return 12; 2613 case MDOC_Bq: 2614 return 12; 2615 case MDOC_Cd: 2616 return 12; 2617 case MDOC_Cm: 2618 return 10; 2619 case MDOC_Do: 2620 return 10; 2621 case MDOC_Dq: 2622 return 12; 2623 case MDOC_Dv: 2624 return 12; 2625 case MDOC_Eo: 2626 return 12; 2627 case MDOC_Em: 2628 return 10; 2629 case MDOC_Er: 2630 return 17; 2631 case MDOC_Ev: 2632 return 15; 2633 case MDOC_Fa: 2634 return 12; 2635 case MDOC_Fl: 2636 return 10; 2637 case MDOC_Fo: 2638 return 16; 2639 case MDOC_Fn: 2640 return 16; 2641 case MDOC_Ic: 2642 return 10; 2643 case MDOC_Li: 2644 return 16; 2645 case MDOC_Ms: 2646 return 6; 2647 case MDOC_Nm: 2648 return 10; 2649 case MDOC_No: 2650 return 12; 2651 case MDOC_Oo: 2652 return 10; 2653 case MDOC_Op: 2654 return 14; 2655 case MDOC_Pa: 2656 return 32; 2657 case MDOC_Pf: 2658 return 12; 2659 case MDOC_Po: 2660 return 12; 2661 case MDOC_Pq: 2662 return 12; 2663 case MDOC_Ql: 2664 return 16; 2665 case MDOC_Qo: 2666 return 12; 2667 case MDOC_So: 2668 return 12; 2669 case MDOC_Sq: 2670 return 12; 2671 case MDOC_Sy: 2672 return 6; 2673 case MDOC_Sx: 2674 return 16; 2675 case MDOC_Tn: 2676 return 10; 2677 case MDOC_Va: 2678 return 12; 2679 case MDOC_Vt: 2680 return 12; 2681 case MDOC_Xr: 2682 return 10; 2683 default: 2684 break; 2685 }; 2686 return 0; 2687 } 2688