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