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