1 /* $Id: mdoc_validate.c,v 1.9 2016/01/07 20:05:41 christos 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 struct mdoc_node *p = n->last; 907 mdoc_node_delete(mdoc, p); 908 } 909 } 910 911 post_fname(mdoc); 912 } 913 914 static void 915 post_fa(POST_ARGS) 916 { 917 const struct mdoc_node *n; 918 const char *cp; 919 920 for (n = mdoc->last->child; n != NULL; n = n->next) { 921 for (cp = n->string; *cp != '\0'; cp++) { 922 /* Ignore callbacks and alterations. */ 923 if (*cp == '(' || *cp == '{') 924 break; 925 if (*cp != ',') 926 continue; 927 mandoc_msg(MANDOCERR_FA_COMMA, mdoc->parse, 928 n->line, n->pos + (cp - n->string), 929 n->string); 930 break; 931 } 932 } 933 } 934 935 static void 936 post_vt(POST_ARGS) 937 { 938 const struct mdoc_node *n; 939 940 /* 941 * The Vt macro comes in both ELEM and BLOCK form, both of which 942 * have different syntaxes (yet more context-sensitive 943 * behaviour). ELEM types must have a child, which is already 944 * guaranteed by the in_line parsing routine; BLOCK types, 945 * specifically the BODY, should only have TEXT children. 946 */ 947 948 if (MDOC_BODY != mdoc->last->type) 949 return; 950 951 for (n = mdoc->last->child; n; n = n->next) 952 if (MDOC_TEXT != n->type) 953 mandoc_msg(MANDOCERR_VT_CHILD, mdoc->parse, 954 n->line, n->pos, mdoc_macronames[n->tok]); 955 } 956 957 static void 958 post_nm(POST_ARGS) 959 { 960 struct mdoc_node *n; 961 962 n = mdoc->last; 963 964 if (n->last != NULL && 965 (n->last->tok == MDOC_Pp || 966 n->last->tok == MDOC_Lp)) 967 mdoc_node_relink(mdoc, n->last); 968 969 if (NULL != mdoc->meta.name) 970 return; 971 972 mdoc_deroff(&mdoc->meta.name, n); 973 974 if (NULL == mdoc->meta.name) 975 mandoc_msg(MANDOCERR_NM_NONAME, mdoc->parse, 976 n->line, n->pos, "Nm"); 977 } 978 979 static void 980 post_nd(POST_ARGS) 981 { 982 struct mdoc_node *n; 983 984 n = mdoc->last; 985 986 if (n->type != MDOC_BODY) 987 return; 988 989 if (n->child == NULL) 990 mandoc_msg(MANDOCERR_ND_EMPTY, mdoc->parse, 991 n->line, n->pos, "Nd"); 992 993 post_hyph(mdoc); 994 } 995 996 static void 997 post_d1(POST_ARGS) 998 { 999 struct mdoc_node *n; 1000 1001 n = mdoc->last; 1002 1003 if (n->type != MDOC_BODY) 1004 return; 1005 1006 if (n->child == NULL) 1007 mandoc_msg(MANDOCERR_BLK_EMPTY, mdoc->parse, 1008 n->line, n->pos, "D1"); 1009 1010 post_hyph(mdoc); 1011 } 1012 1013 static void 1014 post_literal(POST_ARGS) 1015 { 1016 struct mdoc_node *n; 1017 1018 n = mdoc->last; 1019 1020 if (n->type != MDOC_BODY) 1021 return; 1022 1023 if (n->child == NULL) 1024 mandoc_msg(MANDOCERR_BLK_EMPTY, mdoc->parse, 1025 n->line, n->pos, mdoc_macronames[n->tok]); 1026 1027 if (n->tok == MDOC_Bd && 1028 n->norm->Bd.type != DISP_literal && 1029 n->norm->Bd.type != DISP_unfilled) 1030 return; 1031 1032 mdoc->flags &= ~MDOC_LITERAL; 1033 } 1034 1035 static void 1036 post_defaults(POST_ARGS) 1037 { 1038 struct mdoc_node *nn; 1039 1040 /* 1041 * The `Ar' defaults to "file ..." if no value is provided as an 1042 * argument; the `Mt' and `Pa' macros use "~"; the `Li' just 1043 * gets an empty string. 1044 */ 1045 1046 if (mdoc->last->child) 1047 return; 1048 1049 nn = mdoc->last; 1050 mdoc->next = MDOC_NEXT_CHILD; 1051 1052 switch (nn->tok) { 1053 case MDOC_Ar: 1054 mdoc_word_alloc(mdoc, nn->line, nn->pos, "file"); 1055 mdoc_word_alloc(mdoc, nn->line, nn->pos, "..."); 1056 break; 1057 case MDOC_Pa: 1058 /* FALLTHROUGH */ 1059 case MDOC_Mt: 1060 mdoc_word_alloc(mdoc, nn->line, nn->pos, "~"); 1061 break; 1062 default: 1063 abort(); 1064 /* NOTREACHED */ 1065 } 1066 mdoc->last = nn; 1067 } 1068 1069 static void 1070 post_at(POST_ARGS) 1071 { 1072 struct mdoc_node *n; 1073 const char *std_att; 1074 char *att; 1075 1076 n = mdoc->last; 1077 if (n->child == NULL) { 1078 mdoc->next = MDOC_NEXT_CHILD; 1079 mdoc_word_alloc(mdoc, n->line, n->pos, "AT&T UNIX"); 1080 mdoc->last = n; 1081 return; 1082 } 1083 1084 /* 1085 * If we have a child, look it up in the standard keys. If a 1086 * key exist, use that instead of the child; if it doesn't, 1087 * prefix "AT&T UNIX " to the existing data. 1088 */ 1089 1090 n = n->child; 1091 assert(MDOC_TEXT == n->type); 1092 if (NULL == (std_att = mdoc_a2att(n->string))) { 1093 mandoc_vmsg(MANDOCERR_AT_BAD, mdoc->parse, 1094 n->line, n->pos, "At %s", n->string); 1095 mandoc_asprintf(&att, "AT&T UNIX %s", n->string); 1096 } else 1097 att = mandoc_strdup(std_att); 1098 1099 free(n->string); 1100 n->string = att; 1101 } 1102 1103 static void 1104 post_an(POST_ARGS) 1105 { 1106 struct mdoc_node *np, *nch; 1107 1108 np = mdoc->last; 1109 nch = np->child; 1110 if (np->norm->An.auth == AUTH__NONE) { 1111 if (nch == NULL) 1112 mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse, 1113 np->line, np->pos, "An"); 1114 } else if (nch != NULL) 1115 mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse, 1116 nch->line, nch->pos, "An ... %s", nch->string); 1117 } 1118 1119 static void 1120 post_en(POST_ARGS) 1121 { 1122 1123 if (MDOC_BLOCK == mdoc->last->type) 1124 mdoc->last->norm->Es = mdoc->last_es; 1125 } 1126 1127 static void 1128 post_es(POST_ARGS) 1129 { 1130 1131 mdoc->last_es = mdoc->last; 1132 } 1133 1134 static void 1135 post_it(POST_ARGS) 1136 { 1137 int i, cols; 1138 enum mdoc_list lt; 1139 struct mdoc_node *nbl, *nit, *nch; 1140 1141 nit = mdoc->last; 1142 if (nit->type != MDOC_BLOCK) 1143 return; 1144 1145 nbl = nit->parent->parent; 1146 lt = nbl->norm->Bl.type; 1147 1148 switch (lt) { 1149 case LIST_tag: 1150 /* FALLTHROUGH */ 1151 case LIST_hang: 1152 /* FALLTHROUGH */ 1153 case LIST_ohang: 1154 /* FALLTHROUGH */ 1155 case LIST_inset: 1156 /* FALLTHROUGH */ 1157 case LIST_diag: 1158 if (nit->head->child == NULL) 1159 mandoc_vmsg(MANDOCERR_IT_NOHEAD, 1160 mdoc->parse, nit->line, nit->pos, 1161 "Bl -%s It", 1162 mdoc_argnames[nbl->args->argv[0].arg]); 1163 break; 1164 case LIST_bullet: 1165 /* FALLTHROUGH */ 1166 case LIST_dash: 1167 /* FALLTHROUGH */ 1168 case LIST_enum: 1169 /* FALLTHROUGH */ 1170 case LIST_hyphen: 1171 if (nit->body == NULL || nit->body->child == NULL) 1172 mandoc_vmsg(MANDOCERR_IT_NOBODY, 1173 mdoc->parse, nit->line, nit->pos, 1174 "Bl -%s It", 1175 mdoc_argnames[nbl->args->argv[0].arg]); 1176 /* FALLTHROUGH */ 1177 case LIST_item: 1178 if (nit->head->child != NULL) 1179 mandoc_vmsg(MANDOCERR_ARG_SKIP, 1180 mdoc->parse, nit->line, nit->pos, 1181 "It %s", nit->head->child->string); 1182 break; 1183 case LIST_column: 1184 cols = (int)nbl->norm->Bl.ncols; 1185 1186 assert(nit->head->child == NULL); 1187 1188 for (i = 0, nch = nit->child; nch; nch = nch->next) 1189 if (nch->type == MDOC_BODY) 1190 i++; 1191 1192 if (i < cols || i > cols + 1) 1193 mandoc_vmsg(MANDOCERR_BL_COL, 1194 mdoc->parse, nit->line, nit->pos, 1195 "%d columns, %d cells", cols, i); 1196 break; 1197 default: 1198 abort(); 1199 } 1200 } 1201 1202 static void 1203 post_bl_block(POST_ARGS) 1204 { 1205 struct mdoc_node *n, *ni, *nc; 1206 1207 /* 1208 * These are fairly complicated, so we've broken them into two 1209 * functions. post_bl_block_tag() is called when a -tag is 1210 * specified, but no -width (it must be guessed). The second 1211 * when a -width is specified (macro indicators must be 1212 * rewritten into real lengths). 1213 */ 1214 1215 n = mdoc->last; 1216 1217 if (LIST_tag == n->norm->Bl.type && 1218 NULL == n->norm->Bl.width) { 1219 post_bl_block_tag(mdoc); 1220 assert(n->norm->Bl.width); 1221 } 1222 1223 for (ni = n->body->child; ni; ni = ni->next) { 1224 if (NULL == ni->body) 1225 continue; 1226 nc = ni->body->last; 1227 while (NULL != nc) { 1228 switch (nc->tok) { 1229 case MDOC_Pp: 1230 /* FALLTHROUGH */ 1231 case MDOC_Lp: 1232 /* FALLTHROUGH */ 1233 case MDOC_br: 1234 break; 1235 default: 1236 nc = NULL; 1237 continue; 1238 } 1239 if (NULL == ni->next) { 1240 mandoc_msg(MANDOCERR_PAR_MOVE, 1241 mdoc->parse, nc->line, nc->pos, 1242 mdoc_macronames[nc->tok]); 1243 mdoc_node_relink(mdoc, nc); 1244 } else if (0 == n->norm->Bl.comp && 1245 LIST_column != n->norm->Bl.type) { 1246 mandoc_vmsg(MANDOCERR_PAR_SKIP, 1247 mdoc->parse, nc->line, nc->pos, 1248 "%s before It", 1249 mdoc_macronames[nc->tok]); 1250 mdoc_node_delete(mdoc, nc); 1251 } else 1252 break; 1253 nc = ni->body->last; 1254 } 1255 } 1256 } 1257 1258 /* 1259 * If the argument of -offset or -width is a macro, 1260 * replace it with the associated default width. 1261 */ 1262 void 1263 rewrite_macro2len(char **arg) 1264 { 1265 size_t width; 1266 enum mdoct tok; 1267 1268 if (*arg == NULL) 1269 return; 1270 else if ( ! strcmp(*arg, "Ds")) 1271 width = 6; 1272 else if ((tok = mdoc_hash_find(*arg)) == MDOC_MAX) 1273 return; 1274 else 1275 width = macro2len(tok); 1276 1277 free(*arg); 1278 mandoc_asprintf(arg, "%zun", width); 1279 } 1280 1281 static void 1282 post_bl_block_tag(POST_ARGS) 1283 { 1284 struct mdoc_node *n, *nn; 1285 size_t sz, ssz; 1286 int i; 1287 char buf[24]; 1288 1289 /* 1290 * Calculate the -width for a `Bl -tag' list if it hasn't been 1291 * provided. Uses the first head macro. NOTE AGAIN: this is 1292 * ONLY if the -width argument has NOT been provided. See 1293 * rewrite_macro2len() for converting the -width string. 1294 */ 1295 1296 sz = 10; 1297 n = mdoc->last; 1298 1299 for (nn = n->body->child; nn; nn = nn->next) { 1300 if (MDOC_It != nn->tok) 1301 continue; 1302 1303 assert(MDOC_BLOCK == nn->type); 1304 nn = nn->head->child; 1305 1306 if (nn == NULL) 1307 break; 1308 1309 if (MDOC_TEXT == nn->type) { 1310 sz = strlen(nn->string) + 1; 1311 break; 1312 } 1313 1314 if (0 != (ssz = macro2len(nn->tok))) 1315 sz = ssz; 1316 1317 break; 1318 } 1319 1320 /* Defaults to ten ens. */ 1321 1322 (void)snprintf(buf, sizeof(buf), "%un", (unsigned int)sz); 1323 1324 /* 1325 * We have to dynamically add this to the macro's argument list. 1326 * We're guaranteed that a MDOC_Width doesn't already exist. 1327 */ 1328 1329 assert(n->args); 1330 i = (int)(n->args->argc)++; 1331 1332 n->args->argv = mandoc_reallocarray(n->args->argv, 1333 n->args->argc, sizeof(struct mdoc_argv)); 1334 1335 n->args->argv[i].arg = MDOC_Width; 1336 n->args->argv[i].line = n->line; 1337 n->args->argv[i].pos = n->pos; 1338 n->args->argv[i].sz = 1; 1339 n->args->argv[i].value = mandoc_malloc(sizeof(char *)); 1340 n->args->argv[i].value[0] = mandoc_strdup(buf); 1341 1342 /* Set our width! */ 1343 n->norm->Bl.width = n->args->argv[i].value[0]; 1344 } 1345 1346 static void 1347 post_bl_head(POST_ARGS) 1348 { 1349 struct mdoc_node *nbl, *nh, *nch, *nnext; 1350 struct mdoc_argv *argv; 1351 int i, j; 1352 1353 nh = mdoc->last; 1354 1355 if (nh->norm->Bl.type != LIST_column) { 1356 if ((nch = nh->child) == NULL) 1357 return; 1358 mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse, 1359 nch->line, nch->pos, "Bl ... %s", nch->string); 1360 while (nch != NULL) { 1361 mdoc_node_delete(mdoc, nch); 1362 nch = nh->child; 1363 } 1364 return; 1365 } 1366 1367 /* 1368 * Append old-style lists, where the column width specifiers 1369 * trail as macro parameters, to the new-style ("normal-form") 1370 * lists where they're argument values following -column. 1371 */ 1372 1373 if (nh->child == NULL) 1374 return; 1375 1376 nbl = nh->parent; 1377 for (j = 0; j < (int)nbl->args->argc; j++) 1378 if (nbl->args->argv[j].arg == MDOC_Column) 1379 break; 1380 1381 assert(j < (int)nbl->args->argc); 1382 1383 /* 1384 * Accommodate for new-style groff column syntax. Shuffle the 1385 * child nodes, all of which must be TEXT, as arguments for the 1386 * column field. Then, delete the head children. 1387 */ 1388 1389 argv = nbl->args->argv + j; 1390 i = argv->sz; 1391 argv->sz += nh->nchild; 1392 argv->value = mandoc_reallocarray(argv->value, 1393 argv->sz, sizeof(char *)); 1394 1395 nh->norm->Bl.ncols = argv->sz; 1396 nh->norm->Bl.cols = (void *)argv->value; 1397 1398 for (nch = nh->child; nch != NULL; nch = nnext) { 1399 argv->value[i++] = nch->string; 1400 nch->string = NULL; 1401 nnext = nch->next; 1402 mdoc_node_delete(NULL, nch); 1403 } 1404 nh->nchild = 0; 1405 nh->child = NULL; 1406 } 1407 1408 static void 1409 post_bl(POST_ARGS) 1410 { 1411 struct mdoc_node *nparent, *nprev; /* of the Bl block */ 1412 struct mdoc_node *nblock, *nbody; /* of the Bl */ 1413 struct mdoc_node *nchild, *nnext; /* of the Bl body */ 1414 1415 nbody = mdoc->last; 1416 switch (nbody->type) { 1417 case MDOC_BLOCK: 1418 post_bl_block(mdoc); 1419 return; 1420 case MDOC_HEAD: 1421 post_bl_head(mdoc); 1422 return; 1423 case MDOC_BODY: 1424 break; 1425 default: 1426 return; 1427 } 1428 1429 nchild = nbody->child; 1430 if (nchild == NULL) { 1431 mandoc_msg(MANDOCERR_BLK_EMPTY, mdoc->parse, 1432 nbody->line, nbody->pos, "Bl"); 1433 return; 1434 } 1435 while (nchild != NULL) { 1436 if (nchild->tok == MDOC_It || 1437 (nchild->tok == MDOC_Sm && 1438 nchild->next != NULL && 1439 nchild->next->tok == MDOC_It)) { 1440 nchild = nchild->next; 1441 continue; 1442 } 1443 1444 mandoc_msg(MANDOCERR_BL_MOVE, mdoc->parse, 1445 nchild->line, nchild->pos, 1446 mdoc_macronames[nchild->tok]); 1447 1448 /* 1449 * Move the node out of the Bl block. 1450 * First, collect all required node pointers. 1451 */ 1452 1453 nblock = nbody->parent; 1454 nprev = nblock->prev; 1455 nparent = nblock->parent; 1456 nnext = nchild->next; 1457 1458 /* 1459 * Unlink this child. 1460 */ 1461 1462 assert(NULL == nchild->prev); 1463 if (0 == --nbody->nchild) { 1464 nbody->child = NULL; 1465 nbody->last = NULL; 1466 assert(NULL == nnext); 1467 } else { 1468 nbody->child = nnext; 1469 if (nnext) 1470 nnext->prev = NULL; 1471 } 1472 1473 /* 1474 * Relink this child. 1475 */ 1476 1477 nchild->parent = nparent; 1478 nchild->prev = nprev; 1479 nchild->next = nblock; 1480 1481 nblock->prev = nchild; 1482 nparent->nchild++; 1483 if (NULL == nprev) 1484 nparent->child = nchild; 1485 else 1486 nprev->next = nchild; 1487 1488 nchild = nnext; 1489 } 1490 } 1491 1492 static void 1493 post_bk(POST_ARGS) 1494 { 1495 struct mdoc_node *n; 1496 1497 n = mdoc->last; 1498 1499 if (n->type == MDOC_BLOCK && n->body->child == NULL) { 1500 mandoc_msg(MANDOCERR_BLK_EMPTY, 1501 mdoc->parse, n->line, n->pos, "Bk"); 1502 mdoc_node_delete(mdoc, n); 1503 } 1504 } 1505 1506 static void 1507 post_sm(struct mdoc *mdoc) 1508 { 1509 struct mdoc_node *nch; 1510 1511 nch = mdoc->last->child; 1512 1513 if (nch == NULL) { 1514 mdoc->flags ^= MDOC_SMOFF; 1515 return; 1516 } 1517 1518 assert(nch->type == MDOC_TEXT); 1519 1520 if ( ! strcmp(nch->string, "on")) { 1521 mdoc->flags &= ~MDOC_SMOFF; 1522 return; 1523 } 1524 if ( ! strcmp(nch->string, "off")) { 1525 mdoc->flags |= MDOC_SMOFF; 1526 return; 1527 } 1528 1529 mandoc_vmsg(MANDOCERR_SM_BAD, 1530 mdoc->parse, nch->line, nch->pos, 1531 "%s %s", mdoc_macronames[mdoc->last->tok], nch->string); 1532 mdoc_node_relink(mdoc, nch); 1533 return; 1534 } 1535 1536 static void 1537 post_root(POST_ARGS) 1538 { 1539 struct mdoc_node *n; 1540 1541 /* Add missing prologue data. */ 1542 1543 if (mdoc->meta.date == NULL) 1544 mdoc->meta.date = mdoc->quick ? 1545 mandoc_strdup("") : 1546 mandoc_normdate(mdoc->parse, NULL, 0, 0); 1547 1548 if (mdoc->meta.title == NULL) { 1549 mandoc_msg(MANDOCERR_DT_NOTITLE, 1550 mdoc->parse, 0, 0, "EOF"); 1551 mdoc->meta.title = mandoc_strdup("UNTITLED"); 1552 } 1553 1554 if (mdoc->meta.vol == NULL) 1555 mdoc->meta.vol = mandoc_strdup("LOCAL"); 1556 1557 if (mdoc->meta.os == NULL) { 1558 mandoc_msg(MANDOCERR_OS_MISSING, 1559 mdoc->parse, 0, 0, NULL); 1560 mdoc->meta.os = mandoc_strdup(""); 1561 } 1562 1563 /* Check that we begin with a proper `Sh'. */ 1564 1565 n = mdoc->first->child; 1566 while (n != NULL && mdoc_macros[n->tok].flags & MDOC_PROLOGUE) 1567 n = n->next; 1568 1569 if (n == NULL) 1570 mandoc_msg(MANDOCERR_DOC_EMPTY, mdoc->parse, 0, 0, NULL); 1571 else if (n->tok != MDOC_Sh) 1572 mandoc_msg(MANDOCERR_SEC_BEFORE, mdoc->parse, 1573 n->line, n->pos, mdoc_macronames[n->tok]); 1574 } 1575 1576 static void 1577 post_st(POST_ARGS) 1578 { 1579 struct mdoc_node *n, *nch; 1580 const char *p; 1581 1582 n = mdoc->last; 1583 nch = n->child; 1584 1585 assert(MDOC_TEXT == nch->type); 1586 1587 if (NULL == (p = mdoc_a2st(nch->string))) { 1588 mandoc_vmsg(MANDOCERR_ST_BAD, mdoc->parse, 1589 nch->line, nch->pos, "St %s", nch->string); 1590 mdoc_node_delete(mdoc, n); 1591 } else { 1592 free(nch->string); 1593 nch->string = mandoc_strdup(p); 1594 } 1595 } 1596 1597 static void 1598 post_rs(POST_ARGS) 1599 { 1600 struct mdoc_node *np, *nch, *next, *prev; 1601 int i, j; 1602 1603 np = mdoc->last; 1604 1605 if (np->type != MDOC_BODY) 1606 return; 1607 1608 if (np->child == NULL) { 1609 mandoc_msg(MANDOCERR_RS_EMPTY, mdoc->parse, 1610 np->line, np->pos, "Rs"); 1611 return; 1612 } 1613 1614 /* 1615 * The full `Rs' block needs special handling to order the 1616 * sub-elements according to `rsord'. Pick through each element 1617 * and correctly order it. This is an insertion sort. 1618 */ 1619 1620 next = NULL; 1621 for (nch = np->child->next; nch != NULL; nch = next) { 1622 /* Determine order number of this child. */ 1623 for (i = 0; i < RSORD_MAX; i++) 1624 if (rsord[i] == nch->tok) 1625 break; 1626 1627 if (i == RSORD_MAX) { 1628 mandoc_msg(MANDOCERR_RS_BAD, 1629 mdoc->parse, nch->line, nch->pos, 1630 mdoc_macronames[nch->tok]); 1631 i = -1; 1632 } else if (nch->tok == MDOC__J || nch->tok == MDOC__B) 1633 np->norm->Rs.quote_T++; 1634 1635 /* 1636 * Remove this child from the chain. This somewhat 1637 * repeats mdoc_node_unlink(), but since we're 1638 * just re-ordering, there's no need for the 1639 * full unlink process. 1640 */ 1641 1642 if ((next = nch->next) != NULL) 1643 next->prev = nch->prev; 1644 1645 if ((prev = nch->prev) != NULL) 1646 prev->next = nch->next; 1647 1648 nch->prev = nch->next = NULL; 1649 1650 /* 1651 * Scan back until we reach a node that's 1652 * to be ordered before this child. 1653 */ 1654 1655 for ( ; prev ; prev = prev->prev) { 1656 /* Determine order of `prev'. */ 1657 for (j = 0; j < RSORD_MAX; j++) 1658 if (rsord[j] == prev->tok) 1659 break; 1660 if (j == RSORD_MAX) 1661 j = -1; 1662 1663 if (j <= i) 1664 break; 1665 } 1666 1667 /* 1668 * Set this child back into its correct place 1669 * in front of the `prev' node. 1670 */ 1671 1672 nch->prev = prev; 1673 1674 if (prev == NULL) { 1675 np->child->prev = nch; 1676 nch->next = np->child; 1677 np->child = nch; 1678 } else { 1679 if (prev->next) 1680 prev->next->prev = nch; 1681 nch->next = prev->next; 1682 prev->next = nch; 1683 } 1684 } 1685 } 1686 1687 /* 1688 * For some arguments of some macros, 1689 * convert all breakable hyphens into ASCII_HYPH. 1690 */ 1691 static void 1692 post_hyph(POST_ARGS) 1693 { 1694 struct mdoc_node *nch; 1695 char *cp; 1696 1697 for (nch = mdoc->last->child; nch != NULL; nch = nch->next) { 1698 if (nch->type != MDOC_TEXT) 1699 continue; 1700 cp = nch->string; 1701 if (*cp == '\0') 1702 continue; 1703 while (*(++cp) != '\0') 1704 if (*cp == '-' && 1705 isalpha((unsigned char)cp[-1]) && 1706 isalpha((unsigned char)cp[1])) 1707 *cp = ASCII_HYPH; 1708 } 1709 } 1710 1711 static void 1712 post_ns(POST_ARGS) 1713 { 1714 1715 if (MDOC_LINE & mdoc->last->flags) 1716 mandoc_msg(MANDOCERR_NS_SKIP, mdoc->parse, 1717 mdoc->last->line, mdoc->last->pos, NULL); 1718 } 1719 1720 static void 1721 post_sh(POST_ARGS) 1722 { 1723 1724 post_ignpar(mdoc); 1725 1726 switch (mdoc->last->type) { 1727 case MDOC_HEAD: 1728 post_sh_head(mdoc); 1729 break; 1730 case MDOC_BODY: 1731 switch (mdoc->lastsec) { 1732 case SEC_NAME: 1733 post_sh_name(mdoc); 1734 break; 1735 case SEC_SEE_ALSO: 1736 post_sh_see_also(mdoc); 1737 break; 1738 case SEC_AUTHORS: 1739 post_sh_authors(mdoc); 1740 break; 1741 default: 1742 break; 1743 } 1744 break; 1745 default: 1746 break; 1747 } 1748 } 1749 1750 static void 1751 post_sh_name(POST_ARGS) 1752 { 1753 struct mdoc_node *n; 1754 int hasnm, hasnd; 1755 1756 hasnm = hasnd = 0; 1757 1758 for (n = mdoc->last->child; n != NULL; n = n->next) { 1759 switch (n->tok) { 1760 case MDOC_Nm: 1761 hasnm = 1; 1762 break; 1763 case MDOC_Nd: 1764 hasnd = 1; 1765 if (n->next != NULL) 1766 mandoc_msg(MANDOCERR_NAMESEC_ND, 1767 mdoc->parse, n->line, n->pos, NULL); 1768 break; 1769 case MDOC_MAX: 1770 if (hasnm) 1771 break; 1772 /* FALLTHROUGH */ 1773 default: 1774 mandoc_msg(MANDOCERR_NAMESEC_BAD, mdoc->parse, 1775 n->line, n->pos, mdoc_macronames[n->tok]); 1776 break; 1777 } 1778 } 1779 1780 if ( ! hasnm) 1781 mandoc_msg(MANDOCERR_NAMESEC_NONM, mdoc->parse, 1782 mdoc->last->line, mdoc->last->pos, NULL); 1783 if ( ! hasnd) 1784 mandoc_msg(MANDOCERR_NAMESEC_NOND, mdoc->parse, 1785 mdoc->last->line, mdoc->last->pos, NULL); 1786 } 1787 1788 static void 1789 post_sh_see_also(POST_ARGS) 1790 { 1791 const struct mdoc_node *n; 1792 const char *name, *sec; 1793 const char *lastname, *lastsec, *lastpunct; 1794 int cmp; 1795 1796 n = mdoc->last->child; 1797 lastname = lastsec = lastpunct = NULL; 1798 while (n != NULL) { 1799 if (n->tok != MDOC_Xr || n->nchild < 2) 1800 break; 1801 1802 /* Process one .Xr node. */ 1803 1804 name = n->child->string; 1805 sec = n->child->next->string; 1806 if (lastsec != NULL) { 1807 if (lastpunct[0] != ',' || lastpunct[1] != '\0') 1808 mandoc_vmsg(MANDOCERR_XR_PUNCT, 1809 mdoc->parse, n->line, n->pos, 1810 "%s before %s(%s)", lastpunct, 1811 name, sec); 1812 cmp = strcmp(lastsec, sec); 1813 if (cmp > 0) 1814 mandoc_vmsg(MANDOCERR_XR_ORDER, 1815 mdoc->parse, n->line, n->pos, 1816 "%s(%s) after %s(%s)", name, 1817 sec, lastname, lastsec); 1818 else if (cmp == 0 && 1819 strcasecmp(lastname, name) > 0) 1820 mandoc_vmsg(MANDOCERR_XR_ORDER, 1821 mdoc->parse, n->line, n->pos, 1822 "%s after %s", name, lastname); 1823 } 1824 lastname = name; 1825 lastsec = sec; 1826 1827 /* Process the following node. */ 1828 1829 n = n->next; 1830 if (n == NULL) 1831 break; 1832 if (n->tok == MDOC_Xr) { 1833 lastpunct = "none"; 1834 continue; 1835 } 1836 if (n->type != MDOC_TEXT) 1837 break; 1838 for (name = n->string; *name != '\0'; name++) 1839 if (isalpha((const unsigned char)*name)) 1840 return; 1841 lastpunct = n->string; 1842 if (n->next == NULL) 1843 mandoc_vmsg(MANDOCERR_XR_PUNCT, mdoc->parse, 1844 n->line, n->pos, "%s after %s(%s)", 1845 lastpunct, lastname, lastsec); 1846 n = n->next; 1847 } 1848 } 1849 1850 static int 1851 child_an(const struct mdoc_node *n) 1852 { 1853 1854 for (n = n->child; n != NULL; n = n->next) 1855 if ((n->tok == MDOC_An && n->nchild) || child_an(n)) 1856 return(1); 1857 return(0); 1858 } 1859 1860 static void 1861 post_sh_authors(POST_ARGS) 1862 { 1863 1864 if ( ! child_an(mdoc->last)) 1865 mandoc_msg(MANDOCERR_AN_MISSING, mdoc->parse, 1866 mdoc->last->line, mdoc->last->pos, NULL); 1867 } 1868 1869 static void 1870 post_sh_head(POST_ARGS) 1871 { 1872 struct mdoc_node *n; 1873 const char *goodsec; 1874 char *secname; 1875 enum mdoc_sec sec; 1876 1877 /* 1878 * Process a new section. Sections are either "named" or 1879 * "custom". Custom sections are user-defined, while named ones 1880 * follow a conventional order and may only appear in certain 1881 * manual sections. 1882 */ 1883 1884 secname = NULL; 1885 sec = SEC_CUSTOM; 1886 mdoc_deroff(&secname, mdoc->last); 1887 sec = NULL == secname ? SEC_CUSTOM : a2sec(secname); 1888 1889 /* The NAME should be first. */ 1890 1891 if (SEC_NAME != sec && SEC_NONE == mdoc->lastnamed) 1892 mandoc_vmsg(MANDOCERR_NAMESEC_FIRST, mdoc->parse, 1893 mdoc->last->line, mdoc->last->pos, 1894 "Sh %s", secname); 1895 1896 /* The SYNOPSIS gets special attention in other areas. */ 1897 1898 if (SEC_SYNOPSIS == sec) { 1899 roff_setreg(mdoc->roff, "nS", 1, '='); 1900 mdoc->flags |= MDOC_SYNOPSIS; 1901 } else { 1902 roff_setreg(mdoc->roff, "nS", 0, '='); 1903 mdoc->flags &= ~MDOC_SYNOPSIS; 1904 } 1905 1906 /* Mark our last section. */ 1907 1908 mdoc->lastsec = sec; 1909 1910 /* 1911 * Set the section attribute for the current HEAD, for its 1912 * parent BLOCK, and for the HEAD children; the latter can 1913 * only be TEXT nodes, so no recursion is needed. 1914 * For other blocks and elements, including .Sh BODY, this is 1915 * done when allocating the node data structures, but for .Sh 1916 * BLOCK and HEAD, the section is still unknown at that time. 1917 */ 1918 1919 mdoc->last->parent->sec = sec; 1920 mdoc->last->sec = sec; 1921 for (n = mdoc->last->child; n; n = n->next) 1922 n->sec = sec; 1923 1924 /* We don't care about custom sections after this. */ 1925 1926 if (SEC_CUSTOM == sec) { 1927 free(secname); 1928 return; 1929 } 1930 1931 /* 1932 * Check whether our non-custom section is being repeated or is 1933 * out of order. 1934 */ 1935 1936 if (sec == mdoc->lastnamed) 1937 mandoc_vmsg(MANDOCERR_SEC_REP, mdoc->parse, 1938 mdoc->last->line, mdoc->last->pos, 1939 "Sh %s", secname); 1940 1941 if (sec < mdoc->lastnamed) 1942 mandoc_vmsg(MANDOCERR_SEC_ORDER, mdoc->parse, 1943 mdoc->last->line, mdoc->last->pos, 1944 "Sh %s", secname); 1945 1946 /* Mark the last named section. */ 1947 1948 mdoc->lastnamed = sec; 1949 1950 /* Check particular section/manual conventions. */ 1951 1952 if (mdoc->meta.msec == NULL) { 1953 free(secname); 1954 return; 1955 } 1956 1957 goodsec = NULL; 1958 switch (sec) { 1959 case SEC_ERRORS: 1960 if (*mdoc->meta.msec == '4') 1961 break; 1962 goodsec = "2, 3, 4, 9"; 1963 /* FALLTHROUGH */ 1964 case SEC_RETURN_VALUES: 1965 /* FALLTHROUGH */ 1966 case SEC_LIBRARY: 1967 if (*mdoc->meta.msec == '2') 1968 break; 1969 if (*mdoc->meta.msec == '3') 1970 break; 1971 if (NULL == goodsec) 1972 goodsec = "2, 3, 9"; 1973 /* FALLTHROUGH */ 1974 case SEC_CONTEXT: 1975 if (*mdoc->meta.msec == '9') 1976 break; 1977 if (NULL == goodsec) 1978 goodsec = "9"; 1979 mandoc_vmsg(MANDOCERR_SEC_MSEC, mdoc->parse, 1980 mdoc->last->line, mdoc->last->pos, 1981 "Sh %s for %s only", secname, goodsec); 1982 break; 1983 default: 1984 break; 1985 } 1986 free(secname); 1987 } 1988 1989 static void 1990 post_ignpar(POST_ARGS) 1991 { 1992 struct mdoc_node *np; 1993 1994 switch (mdoc->last->type) { 1995 case MDOC_HEAD: 1996 post_hyph(mdoc); 1997 return; 1998 case MDOC_BODY: 1999 break; 2000 default: 2001 return; 2002 } 2003 2004 if (NULL != (np = mdoc->last->child)) 2005 if (MDOC_Pp == np->tok || MDOC_Lp == np->tok) { 2006 mandoc_vmsg(MANDOCERR_PAR_SKIP, 2007 mdoc->parse, np->line, np->pos, 2008 "%s after %s", mdoc_macronames[np->tok], 2009 mdoc_macronames[mdoc->last->tok]); 2010 mdoc_node_delete(mdoc, np); 2011 } 2012 2013 if (NULL != (np = mdoc->last->last)) 2014 if (MDOC_Pp == np->tok || MDOC_Lp == np->tok) { 2015 mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse, 2016 np->line, np->pos, "%s at the end of %s", 2017 mdoc_macronames[np->tok], 2018 mdoc_macronames[mdoc->last->tok]); 2019 mdoc_node_delete(mdoc, np); 2020 } 2021 } 2022 2023 static void 2024 pre_par(PRE_ARGS) 2025 { 2026 2027 if (NULL == mdoc->last) 2028 return; 2029 if (MDOC_ELEM != n->type && MDOC_BLOCK != n->type) 2030 return; 2031 2032 /* 2033 * Don't allow prior `Lp' or `Pp' prior to a paragraph-type 2034 * block: `Lp', `Pp', or non-compact `Bd' or `Bl'. 2035 */ 2036 2037 if (MDOC_Pp != mdoc->last->tok && 2038 MDOC_Lp != mdoc->last->tok && 2039 MDOC_br != mdoc->last->tok) 2040 return; 2041 if (MDOC_Bl == n->tok && n->norm->Bl.comp) 2042 return; 2043 if (MDOC_Bd == n->tok && n->norm->Bd.comp) 2044 return; 2045 if (MDOC_It == n->tok && n->parent->norm->Bl.comp) 2046 return; 2047 2048 mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse, 2049 mdoc->last->line, mdoc->last->pos, 2050 "%s before %s", mdoc_macronames[mdoc->last->tok], 2051 mdoc_macronames[n->tok]); 2052 mdoc_node_delete(mdoc, mdoc->last); 2053 } 2054 2055 static void 2056 post_par(POST_ARGS) 2057 { 2058 struct mdoc_node *np; 2059 2060 np = mdoc->last; 2061 2062 if (np->tok == MDOC_sp) { 2063 if (np->nchild > 1) 2064 mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse, 2065 np->child->next->line, np->child->next->pos, 2066 "sp ... %s", np->child->next->string); 2067 } else if (np->child != NULL) 2068 mandoc_vmsg(MANDOCERR_ARG_SKIP, 2069 mdoc->parse, np->line, np->pos, "%s %s", 2070 mdoc_macronames[np->tok], np->child->string); 2071 2072 if (NULL == (np = mdoc->last->prev)) { 2073 np = mdoc->last->parent; 2074 if (MDOC_Sh != np->tok && MDOC_Ss != np->tok) 2075 return; 2076 } else if (MDOC_Pp != np->tok && MDOC_Lp != np->tok && 2077 (MDOC_br != mdoc->last->tok || 2078 (MDOC_sp != np->tok && MDOC_br != np->tok))) 2079 return; 2080 2081 mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse, 2082 mdoc->last->line, mdoc->last->pos, 2083 "%s after %s", mdoc_macronames[mdoc->last->tok], 2084 mdoc_macronames[np->tok]); 2085 mdoc_node_delete(mdoc, mdoc->last); 2086 } 2087 2088 static void 2089 pre_literal(PRE_ARGS) 2090 { 2091 2092 pre_display(mdoc, n); 2093 2094 if (MDOC_BODY != n->type) 2095 return; 2096 2097 /* 2098 * The `Dl' (note "el" not "one") and `Bd -literal' and `Bd 2099 * -unfilled' macros set MDOC_LITERAL on entrance to the body. 2100 */ 2101 2102 switch (n->tok) { 2103 case MDOC_Dl: 2104 mdoc->flags |= MDOC_LITERAL; 2105 break; 2106 case MDOC_Bd: 2107 if (DISP_literal == n->norm->Bd.type) 2108 mdoc->flags |= MDOC_LITERAL; 2109 if (DISP_unfilled == n->norm->Bd.type) 2110 mdoc->flags |= MDOC_LITERAL; 2111 break; 2112 default: 2113 abort(); 2114 /* NOTREACHED */ 2115 } 2116 } 2117 2118 static void 2119 post_dd(POST_ARGS) 2120 { 2121 struct mdoc_node *n; 2122 char *datestr; 2123 2124 if (mdoc->meta.date) 2125 free(mdoc->meta.date); 2126 2127 n = mdoc->last; 2128 if (NULL == n->child || '\0' == n->child->string[0]) { 2129 mdoc->meta.date = mdoc->quick ? mandoc_strdup("") : 2130 mandoc_normdate(mdoc->parse, NULL, n->line, n->pos); 2131 goto out; 2132 } 2133 2134 datestr = NULL; 2135 mdoc_deroff(&datestr, n); 2136 if (mdoc->quick) 2137 mdoc->meta.date = datestr; 2138 else { 2139 mdoc->meta.date = mandoc_normdate(mdoc->parse, 2140 datestr, n->line, n->pos); 2141 free(datestr); 2142 } 2143 out: 2144 mdoc_node_delete(mdoc, n); 2145 } 2146 2147 static void 2148 post_dt(POST_ARGS) 2149 { 2150 struct mdoc_node *nn, *n; 2151 const char *cp; 2152 char *p; 2153 2154 n = mdoc->last; 2155 2156 free(mdoc->meta.title); 2157 free(mdoc->meta.msec); 2158 free(mdoc->meta.vol); 2159 free(mdoc->meta.arch); 2160 2161 mdoc->meta.title = NULL; 2162 mdoc->meta.msec = NULL; 2163 mdoc->meta.vol = NULL; 2164 mdoc->meta.arch = NULL; 2165 2166 /* Mandatory first argument: title. */ 2167 2168 nn = n->child; 2169 if (nn == NULL || *nn->string == '\0') { 2170 mandoc_msg(MANDOCERR_DT_NOTITLE, 2171 mdoc->parse, n->line, n->pos, "Dt"); 2172 mdoc->meta.title = mandoc_strdup("UNTITLED"); 2173 } else { 2174 mdoc->meta.title = mandoc_strdup(nn->string); 2175 2176 /* Check that all characters are uppercase. */ 2177 2178 for (p = nn->string; *p != '\0'; p++) 2179 if (islower((unsigned char)*p)) { 2180 mandoc_vmsg(MANDOCERR_TITLE_CASE, 2181 mdoc->parse, nn->line, 2182 nn->pos + (p - nn->string), 2183 "Dt %s", nn->string); 2184 break; 2185 } 2186 } 2187 2188 /* Mandatory second argument: section.�*/ 2189 2190 if (nn != NULL) 2191 nn = nn->next; 2192 2193 if (nn == NULL) { 2194 mandoc_vmsg(MANDOCERR_MSEC_MISSING, 2195 mdoc->parse, n->line, n->pos, 2196 "Dt %s", mdoc->meta.title); 2197 mdoc->meta.vol = mandoc_strdup("LOCAL"); 2198 goto out; /* msec and arch remain NULL. */ 2199 } 2200 2201 mdoc->meta.msec = mandoc_strdup(nn->string); 2202 2203 /* Infer volume title from section number. */ 2204 2205 cp = mandoc_a2msec(nn->string); 2206 if (cp == NULL) { 2207 mandoc_vmsg(MANDOCERR_MSEC_BAD, mdoc->parse, 2208 nn->line, nn->pos, "Dt ... %s", nn->string); 2209 mdoc->meta.vol = mandoc_strdup(nn->string); 2210 } else 2211 mdoc->meta.vol = mandoc_strdup(cp); 2212 2213 /* Optional third argument: architecture. */ 2214 2215 if ((nn = nn->next) == NULL) 2216 goto out; 2217 2218 for (p = nn->string; *p != '\0'; p++) 2219 *p = tolower((unsigned char)*p); 2220 mdoc->meta.arch = mandoc_strdup(nn->string); 2221 2222 /* Ignore fourth and later arguments. */ 2223 2224 if ((nn = nn->next) != NULL) 2225 mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse, 2226 nn->line, nn->pos, "Dt ... %s", nn->string); 2227 2228 out: 2229 mdoc_node_delete(mdoc, n); 2230 } 2231 2232 static void 2233 post_bx(POST_ARGS) 2234 { 2235 struct mdoc_node *n; 2236 2237 /* 2238 * Make `Bx's second argument always start with an uppercase 2239 * letter. Groff checks if it's an "accepted" term, but we just 2240 * uppercase blindly. 2241 */ 2242 2243 n = mdoc->last->child; 2244 if (n && NULL != (n = n->next)) 2245 *n->string = (char)toupper((unsigned char)*n->string); 2246 } 2247 2248 static void 2249 post_os(POST_ARGS) 2250 { 2251 #ifndef OSNAME 2252 struct utsname utsname; 2253 static char *defbuf; 2254 #endif 2255 struct mdoc_node *n; 2256 2257 n = mdoc->last; 2258 2259 /* 2260 * Set the operating system by way of the `Os' macro. 2261 * The order of precedence is: 2262 * 1. the argument of the `Os' macro, unless empty 2263 * 2. the -Ios=foo command line argument, if provided 2264 * 3. -DOSNAME="\"foo\"", if provided during compilation 2265 * 4. "sysname release" from uname(3) 2266 */ 2267 2268 free(mdoc->meta.os); 2269 mdoc->meta.os = NULL; 2270 mdoc_deroff(&mdoc->meta.os, n); 2271 if (mdoc->meta.os) 2272 goto out; 2273 2274 if (mdoc->defos) { 2275 mdoc->meta.os = mandoc_strdup(mdoc->defos); 2276 goto out; 2277 } 2278 2279 #ifdef OSNAME 2280 mdoc->meta.os = mandoc_strdup(OSNAME); 2281 #else /*!OSNAME */ 2282 if (NULL == defbuf) { 2283 if (-1 == uname(&utsname)) { 2284 mandoc_msg(MANDOCERR_OS_UNAME, mdoc->parse, 2285 n->line, n->pos, "Os"); 2286 defbuf = mandoc_strdup("UNKNOWN"); 2287 } else 2288 mandoc_asprintf(&defbuf, "%s %s", 2289 utsname.sysname, utsname.release); 2290 } 2291 mdoc->meta.os = mandoc_strdup(defbuf); 2292 #endif /*!OSNAME*/ 2293 2294 out: 2295 mdoc_node_delete(mdoc, n); 2296 } 2297 2298 /* 2299 * If no argument is provided, 2300 * fill in the name of the current manual page. 2301 */ 2302 static void 2303 post_ex(POST_ARGS) 2304 { 2305 struct mdoc_node *n; 2306 2307 n = mdoc->last; 2308 2309 if (n->child) 2310 return; 2311 2312 if (mdoc->meta.name == NULL) { 2313 mandoc_msg(MANDOCERR_EX_NONAME, mdoc->parse, 2314 n->line, n->pos, "Ex"); 2315 return; 2316 } 2317 2318 mdoc->next = MDOC_NEXT_CHILD; 2319 mdoc_word_alloc(mdoc, n->line, n->pos, mdoc->meta.name); 2320 mdoc->last = n; 2321 } 2322 2323 static enum mdoc_sec 2324 a2sec(const char *p) 2325 { 2326 int i; 2327 2328 for (i = 0; i < (int)SEC__MAX; i++) 2329 if (secnames[i] && 0 == strcmp(p, secnames[i])) 2330 return((enum mdoc_sec)i); 2331 2332 return(SEC_CUSTOM); 2333 } 2334 2335 static size_t 2336 macro2len(enum mdoct macro) 2337 { 2338 2339 switch (macro) { 2340 case MDOC_Ad: 2341 return(12); 2342 case MDOC_Ao: 2343 return(12); 2344 case MDOC_An: 2345 return(12); 2346 case MDOC_Aq: 2347 return(12); 2348 case MDOC_Ar: 2349 return(12); 2350 case MDOC_Bo: 2351 return(12); 2352 case MDOC_Bq: 2353 return(12); 2354 case MDOC_Cd: 2355 return(12); 2356 case MDOC_Cm: 2357 return(10); 2358 case MDOC_Do: 2359 return(10); 2360 case MDOC_Dq: 2361 return(12); 2362 case MDOC_Dv: 2363 return(12); 2364 case MDOC_Eo: 2365 return(12); 2366 case MDOC_Em: 2367 return(10); 2368 case MDOC_Er: 2369 return(17); 2370 case MDOC_Ev: 2371 return(15); 2372 case MDOC_Fa: 2373 return(12); 2374 case MDOC_Fl: 2375 return(10); 2376 case MDOC_Fo: 2377 return(16); 2378 case MDOC_Fn: 2379 return(16); 2380 case MDOC_Ic: 2381 return(10); 2382 case MDOC_Li: 2383 return(16); 2384 case MDOC_Ms: 2385 return(6); 2386 case MDOC_Nm: 2387 return(10); 2388 case MDOC_No: 2389 return(12); 2390 case MDOC_Oo: 2391 return(10); 2392 case MDOC_Op: 2393 return(14); 2394 case MDOC_Pa: 2395 return(32); 2396 case MDOC_Pf: 2397 return(12); 2398 case MDOC_Po: 2399 return(12); 2400 case MDOC_Pq: 2401 return(12); 2402 case MDOC_Ql: 2403 return(16); 2404 case MDOC_Qo: 2405 return(12); 2406 case MDOC_So: 2407 return(12); 2408 case MDOC_Sq: 2409 return(12); 2410 case MDOC_Sy: 2411 return(6); 2412 case MDOC_Sx: 2413 return(16); 2414 case MDOC_Tn: 2415 return(10); 2416 case MDOC_Va: 2417 return(12); 2418 case MDOC_Vt: 2419 return(12); 2420 case MDOC_Xr: 2421 return(10); 2422 default: 2423 break; 2424 }; 2425 return(0); 2426 } 2427