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