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