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