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 #if !defined(NDEBUG) && defined(__minix) 601 struct mdoc_node *np; 602 #endif /* !defined(NDEBUG) && defined(__minix) */ 603 604 if (MDOC_BLOCK != n->type) { 605 #if !defined(NDEBUG) && defined(__minix) 606 if (ENDBODY_NOT != n->end) { 607 assert(n->pending); 608 np = n->pending->parent; 609 } else 610 np = n->parent; 611 612 assert(np); 613 assert(MDOC_BLOCK == np->type); 614 assert(MDOC_Bl == np->tok); 615 #endif /* !defined(NDEBUG) && defined(__minix) */ 616 return(1); 617 } 618 619 /* 620 * First figure out which kind of list to use: bind ourselves to 621 * the first mentioned list type and warn about any remaining 622 * ones. If we find no list type, we default to LIST_item. 623 */ 624 625 /* LINTED */ 626 for (i = 0; n->args && i < (int)n->args->argc; i++) { 627 lt = LIST__NONE; 628 dup = comp = 0; 629 width = offs = NULL; 630 switch (n->args->argv[i].arg) { 631 /* Set list types. */ 632 case (MDOC_Bullet): 633 lt = LIST_bullet; 634 break; 635 case (MDOC_Dash): 636 lt = LIST_dash; 637 break; 638 case (MDOC_Enum): 639 lt = LIST_enum; 640 break; 641 case (MDOC_Hyphen): 642 lt = LIST_hyphen; 643 break; 644 case (MDOC_Item): 645 lt = LIST_item; 646 break; 647 case (MDOC_Tag): 648 lt = LIST_tag; 649 break; 650 case (MDOC_Diag): 651 lt = LIST_diag; 652 break; 653 case (MDOC_Hang): 654 lt = LIST_hang; 655 break; 656 case (MDOC_Ohang): 657 lt = LIST_ohang; 658 break; 659 case (MDOC_Inset): 660 lt = LIST_inset; 661 break; 662 case (MDOC_Column): 663 lt = LIST_column; 664 break; 665 /* Set list arguments. */ 666 case (MDOC_Compact): 667 dup = n->norm->Bl.comp; 668 comp = 1; 669 break; 670 case (MDOC_Width): 671 /* NB: this can be empty! */ 672 if (n->args->argv[i].sz) { 673 width = n->args->argv[i].value[0]; 674 dup = (NULL != n->norm->Bl.width); 675 break; 676 } 677 mdoc_nmsg(mdoc, n, MANDOCERR_IGNARGV); 678 break; 679 case (MDOC_Offset): 680 /* NB: this can be empty! */ 681 if (n->args->argv[i].sz) { 682 offs = n->args->argv[i].value[0]; 683 dup = (NULL != n->norm->Bl.offs); 684 break; 685 } 686 mdoc_nmsg(mdoc, n, MANDOCERR_IGNARGV); 687 break; 688 default: 689 continue; 690 } 691 692 /* Check: duplicate auxiliary arguments. */ 693 694 if (dup) 695 mdoc_nmsg(mdoc, n, MANDOCERR_ARGVREP); 696 697 if (comp && ! dup) 698 n->norm->Bl.comp = comp; 699 if (offs && ! dup) 700 n->norm->Bl.offs = offs; 701 if (width && ! dup) 702 n->norm->Bl.width = width; 703 704 /* Check: multiple list types. */ 705 706 if (LIST__NONE != lt && n->norm->Bl.type != LIST__NONE) 707 mdoc_nmsg(mdoc, n, MANDOCERR_LISTREP); 708 709 /* Assign list type. */ 710 711 if (LIST__NONE != lt && n->norm->Bl.type == LIST__NONE) { 712 n->norm->Bl.type = lt; 713 /* Set column information, too. */ 714 if (LIST_column == lt) { 715 n->norm->Bl.ncols = 716 n->args->argv[i].sz; 717 n->norm->Bl.cols = (void *) 718 n->args->argv[i].value; 719 } 720 } 721 722 /* The list type should come first. */ 723 724 if (n->norm->Bl.type == LIST__NONE) 725 if (n->norm->Bl.width || 726 n->norm->Bl.offs || 727 n->norm->Bl.comp) 728 mdoc_nmsg(mdoc, n, MANDOCERR_LISTFIRST); 729 730 continue; 731 } 732 733 /* Allow lists to default to LIST_item. */ 734 735 if (LIST__NONE == n->norm->Bl.type) { 736 mdoc_nmsg(mdoc, n, MANDOCERR_LISTTYPE); 737 n->norm->Bl.type = LIST_item; 738 } 739 740 /* 741 * Validate the width field. Some list types don't need width 742 * types and should be warned about them. Others should have it 743 * and must also be warned. Yet others have a default and need 744 * no warning. 745 */ 746 747 switch (n->norm->Bl.type) { 748 case (LIST_tag): 749 if (NULL == n->norm->Bl.width) 750 mdoc_nmsg(mdoc, n, MANDOCERR_NOWIDTHARG); 751 break; 752 case (LIST_column): 753 /* FALLTHROUGH */ 754 case (LIST_diag): 755 /* FALLTHROUGH */ 756 case (LIST_ohang): 757 /* FALLTHROUGH */ 758 case (LIST_inset): 759 /* FALLTHROUGH */ 760 case (LIST_item): 761 if (n->norm->Bl.width) 762 mdoc_nmsg(mdoc, n, MANDOCERR_IGNARGV); 763 break; 764 case (LIST_bullet): 765 /* FALLTHROUGH */ 766 case (LIST_dash): 767 /* FALLTHROUGH */ 768 case (LIST_hyphen): 769 if (NULL == n->norm->Bl.width) 770 n->norm->Bl.width = "2n"; 771 break; 772 case (LIST_enum): 773 if (NULL == n->norm->Bl.width) 774 n->norm->Bl.width = "3n"; 775 break; 776 default: 777 break; 778 } 779 780 return(1); 781 } 782 783 784 static int 785 pre_bd(PRE_ARGS) 786 { 787 int i, dup, comp; 788 enum mdoc_disp dt; 789 const char *offs; 790 #if !defined(NDEBUG) && defined(__minix) 791 struct mdoc_node *np; 792 #endif /* !defined(NDEBUG) && defined(__minix) */ 793 794 if (MDOC_BLOCK != n->type) { 795 #if !defined(NDEBUG) && defined(__minix) 796 if (ENDBODY_NOT != n->end) { 797 assert(n->pending); 798 np = n->pending->parent; 799 } else 800 np = n->parent; 801 802 assert(np); 803 assert(MDOC_BLOCK == np->type); 804 assert(MDOC_Bd == np->tok); 805 #endif /* !defined(NDEBUG) && defined(__minix) */ 806 return(1); 807 } 808 809 /* LINTED */ 810 for (i = 0; n->args && i < (int)n->args->argc; i++) { 811 dt = DISP__NONE; 812 dup = comp = 0; 813 offs = NULL; 814 815 switch (n->args->argv[i].arg) { 816 case (MDOC_Centred): 817 dt = DISP_centred; 818 break; 819 case (MDOC_Ragged): 820 dt = DISP_ragged; 821 break; 822 case (MDOC_Unfilled): 823 dt = DISP_unfilled; 824 break; 825 case (MDOC_Filled): 826 dt = DISP_filled; 827 break; 828 case (MDOC_Literal): 829 dt = DISP_literal; 830 break; 831 case (MDOC_File): 832 mdoc_nmsg(mdoc, n, MANDOCERR_BADDISP); 833 return(0); 834 case (MDOC_Offset): 835 /* NB: this can be empty! */ 836 if (n->args->argv[i].sz) { 837 offs = n->args->argv[i].value[0]; 838 dup = (NULL != n->norm->Bd.offs); 839 break; 840 } 841 mdoc_nmsg(mdoc, n, MANDOCERR_IGNARGV); 842 break; 843 case (MDOC_Compact): 844 comp = 1; 845 dup = n->norm->Bd.comp; 846 break; 847 default: 848 abort(); 849 /* NOTREACHED */ 850 } 851 852 /* Check whether we have duplicates. */ 853 854 if (dup) 855 mdoc_nmsg(mdoc, n, MANDOCERR_ARGVREP); 856 857 /* Make our auxiliary assignments. */ 858 859 if (offs && ! dup) 860 n->norm->Bd.offs = offs; 861 if (comp && ! dup) 862 n->norm->Bd.comp = comp; 863 864 /* Check whether a type has already been assigned. */ 865 866 if (DISP__NONE != dt && n->norm->Bd.type != DISP__NONE) 867 mdoc_nmsg(mdoc, n, MANDOCERR_DISPREP); 868 869 /* Make our type assignment. */ 870 871 if (DISP__NONE != dt && n->norm->Bd.type == DISP__NONE) 872 n->norm->Bd.type = dt; 873 } 874 875 if (DISP__NONE == n->norm->Bd.type) { 876 mdoc_nmsg(mdoc, n, MANDOCERR_DISPTYPE); 877 n->norm->Bd.type = DISP_ragged; 878 } 879 880 return(1); 881 } 882 883 884 static int 885 pre_ss(PRE_ARGS) 886 { 887 888 if (MDOC_BLOCK != n->type) 889 return(1); 890 return(check_parent(mdoc, n, MDOC_Sh, MDOC_BODY)); 891 } 892 893 894 static int 895 pre_sh(PRE_ARGS) 896 { 897 898 if (MDOC_BLOCK != n->type) 899 return(1); 900 return(check_parent(mdoc, n, MDOC_MAX, MDOC_ROOT)); 901 } 902 903 904 static int 905 pre_it(PRE_ARGS) 906 { 907 908 if (MDOC_BLOCK != n->type) 909 return(1); 910 911 return(check_parent(mdoc, n, MDOC_Bl, MDOC_BODY)); 912 } 913 914 915 static int 916 pre_an(PRE_ARGS) 917 { 918 int i; 919 920 if (NULL == n->args) 921 return(1); 922 923 for (i = 1; i < (int)n->args->argc; i++) 924 mdoc_pmsg(mdoc, n->args->argv[i].line, 925 n->args->argv[i].pos, MANDOCERR_IGNARGV); 926 927 if (MDOC_Split == n->args->argv[0].arg) 928 n->norm->An.auth = AUTH_split; 929 else if (MDOC_Nosplit == n->args->argv[0].arg) 930 n->norm->An.auth = AUTH_nosplit; 931 else 932 abort(); 933 934 return(1); 935 } 936 937 static int 938 pre_std(PRE_ARGS) 939 { 940 941 if (n->args && 1 == n->args->argc) 942 if (MDOC_Std == n->args->argv[0].arg) 943 return(1); 944 945 mdoc_nmsg(mdoc, n, MANDOCERR_NOARGV); 946 return(1); 947 } 948 949 static int 950 pre_dt(PRE_ARGS) 951 { 952 953 if (NULL == mdoc->meta.date || mdoc->meta.os) 954 mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGOOO); 955 956 if (mdoc->meta.title) 957 mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGREP); 958 959 return(1); 960 } 961 962 static int 963 pre_os(PRE_ARGS) 964 { 965 966 if (NULL == mdoc->meta.title || NULL == mdoc->meta.date) 967 mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGOOO); 968 969 if (mdoc->meta.os) 970 mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGREP); 971 972 return(1); 973 } 974 975 static int 976 pre_dd(PRE_ARGS) 977 { 978 979 if (mdoc->meta.title || mdoc->meta.os) 980 mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGOOO); 981 982 if (mdoc->meta.date) 983 mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGREP); 984 985 return(1); 986 } 987 988 989 static int 990 post_bf(POST_ARGS) 991 { 992 struct mdoc_node *np; 993 enum mdocargt arg; 994 995 /* 996 * Unlike other data pointers, these are "housed" by the HEAD 997 * element, which contains the goods. 998 */ 999 1000 if (MDOC_HEAD != mdoc->last->type) { 1001 if (ENDBODY_NOT != mdoc->last->end) { 1002 assert(mdoc->last->pending); 1003 np = mdoc->last->pending->parent->head; 1004 } else if (MDOC_BLOCK != mdoc->last->type) { 1005 np = mdoc->last->parent->head; 1006 } else 1007 np = mdoc->last->head; 1008 1009 assert(np); 1010 assert(MDOC_HEAD == np->type); 1011 assert(MDOC_Bf == np->tok); 1012 return(1); 1013 } 1014 1015 np = mdoc->last; 1016 assert(MDOC_BLOCK == np->parent->type); 1017 assert(MDOC_Bf == np->parent->tok); 1018 1019 /* 1020 * Cannot have both argument and parameter. 1021 * If neither is specified, let it through with a warning. 1022 */ 1023 1024 if (np->parent->args && np->child) { 1025 mdoc_nmsg(mdoc, np, MANDOCERR_SYNTARGVCOUNT); 1026 return(0); 1027 } else if (NULL == np->parent->args && NULL == np->child) { 1028 mdoc_nmsg(mdoc, np, MANDOCERR_FONTTYPE); 1029 return(1); 1030 } 1031 1032 /* Extract argument into data. */ 1033 1034 if (np->parent->args) { 1035 arg = np->parent->args->argv[0].arg; 1036 if (MDOC_Emphasis == arg) 1037 np->norm->Bf.font = FONT_Em; 1038 else if (MDOC_Literal == arg) 1039 np->norm->Bf.font = FONT_Li; 1040 else if (MDOC_Symbolic == arg) 1041 np->norm->Bf.font = FONT_Sy; 1042 else 1043 abort(); 1044 return(1); 1045 } 1046 1047 /* Extract parameter into data. */ 1048 1049 if (0 == strcmp(np->child->string, "Em")) 1050 np->norm->Bf.font = FONT_Em; 1051 else if (0 == strcmp(np->child->string, "Li")) 1052 np->norm->Bf.font = FONT_Li; 1053 else if (0 == strcmp(np->child->string, "Sy")) 1054 np->norm->Bf.font = FONT_Sy; 1055 else 1056 mdoc_nmsg(mdoc, np, MANDOCERR_FONTTYPE); 1057 1058 return(1); 1059 } 1060 1061 static int 1062 post_lb(POST_ARGS) 1063 { 1064 const char *p; 1065 char *buf; 1066 size_t sz; 1067 1068 check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 1); 1069 1070 assert(mdoc->last->child); 1071 assert(MDOC_TEXT == mdoc->last->child->type); 1072 1073 p = mdoc_a2lib(mdoc->last->child->string); 1074 1075 /* If lookup ok, replace with table value. */ 1076 1077 if (p) { 1078 free(mdoc->last->child->string); 1079 mdoc->last->child->string = mandoc_strdup(p); 1080 return(1); 1081 } 1082 1083 /* If not, use "library ``xxxx''. */ 1084 1085 sz = strlen(mdoc->last->child->string) + 1086 2 + strlen("\\(lqlibrary\\(rq"); 1087 buf = mandoc_malloc(sz); 1088 snprintf(buf, sz, "library \\(lq%s\\(rq", 1089 mdoc->last->child->string); 1090 free(mdoc->last->child->string); 1091 mdoc->last->child->string = buf; 1092 return(1); 1093 } 1094 1095 static int 1096 post_eoln(POST_ARGS) 1097 { 1098 1099 if (mdoc->last->child) 1100 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_ARGSLOST); 1101 return(1); 1102 } 1103 1104 1105 static int 1106 post_vt(POST_ARGS) 1107 { 1108 const struct mdoc_node *n; 1109 1110 /* 1111 * The Vt macro comes in both ELEM and BLOCK form, both of which 1112 * have different syntaxes (yet more context-sensitive 1113 * behaviour). ELEM types must have a child, which is already 1114 * guaranteed by the in_line parsing routine; BLOCK types, 1115 * specifically the BODY, should only have TEXT children. 1116 */ 1117 1118 if (MDOC_BODY != mdoc->last->type) 1119 return(1); 1120 1121 for (n = mdoc->last->child; n; n = n->next) 1122 if (MDOC_TEXT != n->type) 1123 mdoc_nmsg(mdoc, n, MANDOCERR_CHILD); 1124 1125 return(1); 1126 } 1127 1128 1129 static int 1130 post_nm(POST_ARGS) 1131 { 1132 char buf[BUFSIZ]; 1133 int c; 1134 1135 if (NULL != mdoc->meta.name) 1136 return(1); 1137 1138 /* Try to use our children for setting the meta name. */ 1139 1140 if (NULL != mdoc->last->child) { 1141 buf[0] = '\0'; 1142 c = concat(buf, mdoc->last->child, BUFSIZ); 1143 } else 1144 c = 0; 1145 1146 switch (c) { 1147 case (-1): 1148 mdoc_nmsg(mdoc, mdoc->last->child, MANDOCERR_MEM); 1149 return(0); 1150 case (0): 1151 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NONAME); 1152 mdoc->meta.name = mandoc_strdup("UNKNOWN"); 1153 break; 1154 default: 1155 mdoc->meta.name = mandoc_strdup(buf); 1156 break; 1157 } 1158 return(1); 1159 } 1160 1161 static int 1162 post_literal(POST_ARGS) 1163 { 1164 1165 /* 1166 * The `Dl' (note "el" not "one") and `Bd' macros unset the 1167 * MDOC_LITERAL flag as they leave. Note that `Bd' only sets 1168 * this in literal mode, but it doesn't hurt to just switch it 1169 * off in general since displays can't be nested. 1170 */ 1171 1172 if (MDOC_BODY == mdoc->last->type) 1173 mdoc->flags &= ~MDOC_LITERAL; 1174 1175 return(1); 1176 } 1177 1178 static int 1179 post_defaults(POST_ARGS) 1180 { 1181 struct mdoc_node *nn; 1182 1183 /* 1184 * The `Ar' defaults to "file ..." if no value is provided as an 1185 * argument; the `Mt' and `Pa' macros use "~"; the `Li' just 1186 * gets an empty string. 1187 */ 1188 1189 if (mdoc->last->child) 1190 return(1); 1191 1192 nn = mdoc->last; 1193 mdoc->next = MDOC_NEXT_CHILD; 1194 1195 switch (nn->tok) { 1196 case (MDOC_Ar): 1197 if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "file")) 1198 return(0); 1199 if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "...")) 1200 return(0); 1201 break; 1202 case (MDOC_At): 1203 if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "AT&T")) 1204 return(0); 1205 if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "UNIX")) 1206 return(0); 1207 break; 1208 case (MDOC_Li): 1209 if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "")) 1210 return(0); 1211 break; 1212 case (MDOC_Pa): 1213 /* FALLTHROUGH */ 1214 case (MDOC_Mt): 1215 if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "~")) 1216 return(0); 1217 break; 1218 default: 1219 abort(); 1220 /* NOTREACHED */ 1221 } 1222 1223 mdoc->last = nn; 1224 return(1); 1225 } 1226 1227 static int 1228 post_at(POST_ARGS) 1229 { 1230 const char *p, *q; 1231 char *buf; 1232 size_t sz; 1233 1234 /* 1235 * If we have a child, look it up in the standard keys. If a 1236 * key exist, use that instead of the child; if it doesn't, 1237 * prefix "AT&T UNIX " to the existing data. 1238 */ 1239 1240 if (NULL == mdoc->last->child) 1241 return(1); 1242 1243 assert(MDOC_TEXT == mdoc->last->child->type); 1244 p = mdoc_a2att(mdoc->last->child->string); 1245 1246 if (p) { 1247 free(mdoc->last->child->string); 1248 mdoc->last->child->string = mandoc_strdup(p); 1249 } else { 1250 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADATT); 1251 p = "AT&T UNIX "; 1252 q = mdoc->last->child->string; 1253 sz = strlen(p) + strlen(q) + 1; 1254 buf = mandoc_malloc(sz); 1255 strlcpy(buf, p, sz); 1256 strlcat(buf, q, sz); 1257 free(mdoc->last->child->string); 1258 mdoc->last->child->string = buf; 1259 } 1260 1261 return(1); 1262 } 1263 1264 static int 1265 post_an(POST_ARGS) 1266 { 1267 struct mdoc_node *np; 1268 1269 np = mdoc->last; 1270 if (AUTH__NONE == np->norm->An.auth) { 1271 if (0 == np->child) 1272 check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_GT, 0); 1273 } else if (np->child) 1274 check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 0); 1275 1276 return(1); 1277 } 1278 1279 1280 static int 1281 post_it(POST_ARGS) 1282 { 1283 int i, cols; 1284 enum mdoc_list lt; 1285 struct mdoc_node *n, *c; 1286 enum mandocerr er; 1287 1288 if (MDOC_BLOCK != mdoc->last->type) 1289 return(1); 1290 1291 n = mdoc->last->parent->parent; 1292 lt = n->norm->Bl.type; 1293 1294 if (LIST__NONE == lt) { 1295 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_LISTTYPE); 1296 return(1); 1297 } 1298 1299 switch (lt) { 1300 case (LIST_tag): 1301 if (mdoc->last->head->child) 1302 break; 1303 /* FIXME: give this a dummy value. */ 1304 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOARGS); 1305 break; 1306 case (LIST_hang): 1307 /* FALLTHROUGH */ 1308 case (LIST_ohang): 1309 /* FALLTHROUGH */ 1310 case (LIST_inset): 1311 /* FALLTHROUGH */ 1312 case (LIST_diag): 1313 if (NULL == mdoc->last->head->child) 1314 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOARGS); 1315 break; 1316 case (LIST_bullet): 1317 /* FALLTHROUGH */ 1318 case (LIST_dash): 1319 /* FALLTHROUGH */ 1320 case (LIST_enum): 1321 /* FALLTHROUGH */ 1322 case (LIST_hyphen): 1323 if (NULL == mdoc->last->body->child) 1324 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOBODY); 1325 /* FALLTHROUGH */ 1326 case (LIST_item): 1327 if (mdoc->last->head->child) 1328 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_ARGSLOST); 1329 break; 1330 case (LIST_column): 1331 cols = (int)n->norm->Bl.ncols; 1332 1333 assert(NULL == mdoc->last->head->child); 1334 1335 if (NULL == mdoc->last->body->child) 1336 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOBODY); 1337 1338 for (i = 0, c = mdoc->last->child; c; c = c->next) 1339 if (MDOC_BODY == c->type) 1340 i++; 1341 1342 if (i < cols) 1343 er = MANDOCERR_ARGCOUNT; 1344 else if (i == cols || i == cols + 1) 1345 break; 1346 else 1347 er = MANDOCERR_SYNTARGCOUNT; 1348 1349 mandoc_vmsg(er, mdoc->parse, mdoc->last->line, 1350 mdoc->last->pos, 1351 "columns == %d (have %d)", cols, i); 1352 return(MANDOCERR_ARGCOUNT == er); 1353 default: 1354 break; 1355 } 1356 1357 return(1); 1358 } 1359 1360 static int 1361 post_bl_block(POST_ARGS) 1362 { 1363 struct mdoc_node *n, *ni, *nc; 1364 1365 /* 1366 * These are fairly complicated, so we've broken them into two 1367 * functions. post_bl_block_tag() is called when a -tag is 1368 * specified, but no -width (it must be guessed). The second 1369 * when a -width is specified (macro indicators must be 1370 * rewritten into real lengths). 1371 */ 1372 1373 n = mdoc->last; 1374 1375 if (LIST_tag == n->norm->Bl.type && 1376 NULL == n->norm->Bl.width) { 1377 if ( ! post_bl_block_tag(mdoc)) 1378 return(0); 1379 assert(n->norm->Bl.width); 1380 } else if (NULL != n->norm->Bl.width) { 1381 if ( ! post_bl_block_width(mdoc)) 1382 return(0); 1383 assert(n->norm->Bl.width); 1384 } 1385 1386 for (ni = n->body->child; ni; ni = ni->next) { 1387 if (NULL == ni->body) 1388 continue; 1389 nc = ni->body->last; 1390 while (NULL != nc) { 1391 switch (nc->tok) { 1392 case (MDOC_Pp): 1393 /* FALLTHROUGH */ 1394 case (MDOC_Lp): 1395 /* FALLTHROUGH */ 1396 case (MDOC_br): 1397 break; 1398 default: 1399 nc = NULL; 1400 continue; 1401 } 1402 if (NULL == ni->next) { 1403 mdoc_nmsg(mdoc, nc, MANDOCERR_MOVEPAR); 1404 if ( ! mdoc_node_relink(mdoc, nc)) 1405 return(0); 1406 } else if (0 == n->norm->Bl.comp && 1407 LIST_column != n->norm->Bl.type) { 1408 mdoc_nmsg(mdoc, nc, MANDOCERR_IGNPAR); 1409 mdoc_node_delete(mdoc, nc); 1410 } else 1411 break; 1412 nc = ni->body->last; 1413 } 1414 } 1415 return(1); 1416 } 1417 1418 static int 1419 post_bl_block_width(POST_ARGS) 1420 { 1421 size_t width; 1422 int i; 1423 enum mdoct tok; 1424 struct mdoc_node *n; 1425 char buf[NUMSIZ]; 1426 1427 n = mdoc->last; 1428 1429 /* 1430 * Calculate the real width of a list from the -width string, 1431 * which may contain a macro (with a known default width), a 1432 * literal string, or a scaling width. 1433 * 1434 * If the value to -width is a macro, then we re-write it to be 1435 * the macro's width as set in share/tmac/mdoc/doc-common. 1436 */ 1437 1438 if (0 == strcmp(n->norm->Bl.width, "Ds")) 1439 width = 6; 1440 else if (MDOC_MAX == (tok = mdoc_hash_find(n->norm->Bl.width))) 1441 return(1); 1442 else if (0 == (width = macro2len(tok))) { 1443 mdoc_nmsg(mdoc, n, MANDOCERR_BADWIDTH); 1444 return(1); 1445 } 1446 1447 /* The value already exists: free and reallocate it. */ 1448 1449 assert(n->args); 1450 1451 for (i = 0; i < (int)n->args->argc; i++) 1452 if (MDOC_Width == n->args->argv[i].arg) 1453 break; 1454 1455 assert(i < (int)n->args->argc); 1456 1457 snprintf(buf, NUMSIZ, "%un", (unsigned int)width); 1458 free(n->args->argv[i].value[0]); 1459 n->args->argv[i].value[0] = mandoc_strdup(buf); 1460 1461 /* Set our width! */ 1462 n->norm->Bl.width = n->args->argv[i].value[0]; 1463 return(1); 1464 } 1465 1466 static int 1467 post_bl_block_tag(POST_ARGS) 1468 { 1469 struct mdoc_node *n, *nn; 1470 size_t sz, ssz; 1471 int i; 1472 char buf[NUMSIZ]; 1473 1474 /* 1475 * Calculate the -width for a `Bl -tag' list if it hasn't been 1476 * provided. Uses the first head macro. NOTE AGAIN: this is 1477 * ONLY if the -width argument has NOT been provided. See 1478 * post_bl_block_width() for converting the -width string. 1479 */ 1480 1481 sz = 10; 1482 n = mdoc->last; 1483 1484 for (nn = n->body->child; nn; nn = nn->next) { 1485 if (MDOC_It != nn->tok) 1486 continue; 1487 1488 assert(MDOC_BLOCK == nn->type); 1489 nn = nn->head->child; 1490 1491 if (nn == NULL) 1492 break; 1493 1494 if (MDOC_TEXT == nn->type) { 1495 sz = strlen(nn->string) + 1; 1496 break; 1497 } 1498 1499 if (0 != (ssz = macro2len(nn->tok))) 1500 sz = ssz; 1501 1502 break; 1503 } 1504 1505 /* Defaults to ten ens. */ 1506 1507 snprintf(buf, NUMSIZ, "%un", (unsigned int)sz); 1508 1509 /* 1510 * We have to dynamically add this to the macro's argument list. 1511 * We're guaranteed that a MDOC_Width doesn't already exist. 1512 */ 1513 1514 assert(n->args); 1515 i = (int)(n->args->argc)++; 1516 1517 n->args->argv = mandoc_realloc(n->args->argv, 1518 n->args->argc * sizeof(struct mdoc_argv)); 1519 1520 n->args->argv[i].arg = MDOC_Width; 1521 n->args->argv[i].line = n->line; 1522 n->args->argv[i].pos = n->pos; 1523 n->args->argv[i].sz = 1; 1524 n->args->argv[i].value = mandoc_malloc(sizeof(char *)); 1525 n->args->argv[i].value[0] = mandoc_strdup(buf); 1526 1527 /* Set our width! */ 1528 n->norm->Bl.width = n->args->argv[i].value[0]; 1529 return(1); 1530 } 1531 1532 1533 static int 1534 post_bl_head(POST_ARGS) 1535 { 1536 struct mdoc_node *np, *nn, *nnp; 1537 int i, j; 1538 1539 if (LIST_column != mdoc->last->norm->Bl.type) 1540 /* FIXME: this should be ERROR class... */ 1541 return(hwarn_eq0(mdoc)); 1542 1543 /* 1544 * Convert old-style lists, where the column width specifiers 1545 * trail as macro parameters, to the new-style ("normal-form") 1546 * lists where they're argument values following -column. 1547 */ 1548 1549 /* First, disallow both types and allow normal-form. */ 1550 1551 /* 1552 * TODO: technically, we can accept both and just merge the two 1553 * lists, but I'll leave that for another day. 1554 */ 1555 1556 if (mdoc->last->norm->Bl.ncols && mdoc->last->nchild) { 1557 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_COLUMNS); 1558 return(0); 1559 } else if (NULL == mdoc->last->child) 1560 return(1); 1561 1562 np = mdoc->last->parent; 1563 assert(np->args); 1564 1565 for (j = 0; j < (int)np->args->argc; j++) 1566 if (MDOC_Column == np->args->argv[j].arg) 1567 break; 1568 1569 assert(j < (int)np->args->argc); 1570 assert(0 == np->args->argv[j].sz); 1571 1572 /* 1573 * Accommodate for new-style groff column syntax. Shuffle the 1574 * child nodes, all of which must be TEXT, as arguments for the 1575 * column field. Then, delete the head children. 1576 */ 1577 1578 np->args->argv[j].sz = (size_t)mdoc->last->nchild; 1579 np->args->argv[j].value = mandoc_malloc 1580 ((size_t)mdoc->last->nchild * sizeof(char *)); 1581 1582 mdoc->last->norm->Bl.ncols = np->args->argv[j].sz; 1583 mdoc->last->norm->Bl.cols = (void *)np->args->argv[j].value; 1584 1585 for (i = 0, nn = mdoc->last->child; nn; i++) { 1586 np->args->argv[j].value[i] = nn->string; 1587 nn->string = NULL; 1588 nnp = nn; 1589 nn = nn->next; 1590 mdoc_node_delete(NULL, nnp); 1591 } 1592 1593 mdoc->last->nchild = 0; 1594 mdoc->last->child = NULL; 1595 1596 return(1); 1597 } 1598 1599 static int 1600 post_bl(POST_ARGS) 1601 { 1602 struct mdoc_node *nparent, *nprev; /* of the Bl block */ 1603 struct mdoc_node *nblock, *nbody; /* of the Bl */ 1604 struct mdoc_node *nchild, *nnext; /* of the Bl body */ 1605 1606 nbody = mdoc->last; 1607 switch (nbody->type) { 1608 case (MDOC_BLOCK): 1609 return(post_bl_block(mdoc)); 1610 case (MDOC_HEAD): 1611 return(post_bl_head(mdoc)); 1612 case (MDOC_BODY): 1613 break; 1614 default: 1615 return(1); 1616 } 1617 1618 nchild = nbody->child; 1619 while (NULL != nchild) { 1620 if (MDOC_It == nchild->tok || MDOC_Sm == nchild->tok) { 1621 nchild = nchild->next; 1622 continue; 1623 } 1624 1625 mdoc_nmsg(mdoc, nchild, MANDOCERR_CHILD); 1626 1627 /* 1628 * Move the node out of the Bl block. 1629 * First, collect all required node pointers. 1630 */ 1631 1632 nblock = nbody->parent; 1633 nprev = nblock->prev; 1634 nparent = nblock->parent; 1635 nnext = nchild->next; 1636 1637 /* 1638 * Unlink this child. 1639 */ 1640 1641 assert(NULL == nchild->prev); 1642 if (0 == --nbody->nchild) { 1643 nbody->child = NULL; 1644 nbody->last = NULL; 1645 assert(NULL == nnext); 1646 } else { 1647 nbody->child = nnext; 1648 nnext->prev = NULL; 1649 } 1650 1651 /* 1652 * Relink this child. 1653 */ 1654 1655 nchild->parent = nparent; 1656 nchild->prev = nprev; 1657 nchild->next = nblock; 1658 1659 nblock->prev = nchild; 1660 nparent->nchild++; 1661 if (NULL == nprev) 1662 nparent->child = nchild; 1663 else 1664 nprev->next = nchild; 1665 1666 nchild = nnext; 1667 } 1668 1669 return(1); 1670 } 1671 1672 static int 1673 ebool(struct mdoc *mdoc) 1674 { 1675 1676 if (NULL == mdoc->last->child) { 1677 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_MACROEMPTY); 1678 mdoc_node_delete(mdoc, mdoc->last); 1679 return(1); 1680 } 1681 check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 1); 1682 1683 assert(MDOC_TEXT == mdoc->last->child->type); 1684 1685 if (0 == strcmp(mdoc->last->child->string, "on")) { 1686 if (MDOC_Sm == mdoc->last->tok) 1687 mdoc->flags &= ~MDOC_SMOFF; 1688 return(1); 1689 } 1690 if (0 == strcmp(mdoc->last->child->string, "off")) { 1691 if (MDOC_Sm == mdoc->last->tok) 1692 mdoc->flags |= MDOC_SMOFF; 1693 return(1); 1694 } 1695 1696 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADBOOL); 1697 return(1); 1698 } 1699 1700 static int 1701 post_root(POST_ARGS) 1702 { 1703 int erc; 1704 struct mdoc_node *n; 1705 1706 erc = 0; 1707 1708 /* Check that we have a finished prologue. */ 1709 1710 if ( ! (MDOC_PBODY & mdoc->flags)) { 1711 erc++; 1712 mdoc_nmsg(mdoc, mdoc->first, MANDOCERR_NODOCPROLOG); 1713 } 1714 1715 n = mdoc->first; 1716 assert(n); 1717 1718 /* Check that we begin with a proper `Sh'. */ 1719 1720 if (NULL == n->child) { 1721 erc++; 1722 mdoc_nmsg(mdoc, n, MANDOCERR_NODOCBODY); 1723 } else if (MDOC_BLOCK != n->child->type || 1724 MDOC_Sh != n->child->tok) { 1725 erc++; 1726 /* Can this be lifted? See rxdebug.1 for example. */ 1727 mdoc_nmsg(mdoc, n, MANDOCERR_NODOCBODY); 1728 } 1729 1730 return(erc ? 0 : 1); 1731 } 1732 1733 static int 1734 post_st(POST_ARGS) 1735 { 1736 struct mdoc_node *ch; 1737 const char *p; 1738 1739 if (NULL == (ch = mdoc->last->child)) { 1740 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_MACROEMPTY); 1741 mdoc_node_delete(mdoc, mdoc->last); 1742 return(1); 1743 } 1744 1745 assert(MDOC_TEXT == ch->type); 1746 1747 if (NULL == (p = mdoc_a2st(ch->string))) { 1748 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADSTANDARD); 1749 mdoc_node_delete(mdoc, mdoc->last); 1750 } else { 1751 free(ch->string); 1752 ch->string = mandoc_strdup(p); 1753 } 1754 1755 return(1); 1756 } 1757 1758 static int 1759 post_rs(POST_ARGS) 1760 { 1761 struct mdoc_node *nn, *next, *prev; 1762 int i, j; 1763 1764 switch (mdoc->last->type) { 1765 case (MDOC_HEAD): 1766 check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_EQ, 0); 1767 return(1); 1768 case (MDOC_BODY): 1769 if (mdoc->last->child) 1770 break; 1771 check_count(mdoc, MDOC_BODY, CHECK_WARN, CHECK_GT, 0); 1772 return(1); 1773 default: 1774 return(1); 1775 } 1776 1777 /* 1778 * Make sure only certain types of nodes are allowed within the 1779 * the `Rs' body. Delete offending nodes and raise a warning. 1780 * Do this before re-ordering for the sake of clarity. 1781 */ 1782 1783 next = NULL; 1784 for (nn = mdoc->last->child; nn; nn = next) { 1785 for (i = 0; i < RSORD_MAX; i++) 1786 if (nn->tok == rsord[i]) 1787 break; 1788 1789 if (i < RSORD_MAX) { 1790 if (MDOC__J == rsord[i] || MDOC__B == rsord[i]) 1791 mdoc->last->norm->Rs.quote_T++; 1792 next = nn->next; 1793 continue; 1794 } 1795 1796 next = nn->next; 1797 mdoc_nmsg(mdoc, nn, MANDOCERR_CHILD); 1798 mdoc_node_delete(mdoc, nn); 1799 } 1800 1801 /* 1802 * Nothing to sort if only invalid nodes were found 1803 * inside the `Rs' body. 1804 */ 1805 1806 if (NULL == mdoc->last->child) 1807 return(1); 1808 1809 /* 1810 * The full `Rs' block needs special handling to order the 1811 * sub-elements according to `rsord'. Pick through each element 1812 * and correctly order it. This is a insertion sort. 1813 */ 1814 1815 next = NULL; 1816 for (nn = mdoc->last->child->next; nn; nn = next) { 1817 /* Determine order of `nn'. */ 1818 for (i = 0; i < RSORD_MAX; i++) 1819 if (rsord[i] == nn->tok) 1820 break; 1821 1822 /* 1823 * Remove `nn' from the chain. This somewhat 1824 * repeats mdoc_node_unlink(), but since we're 1825 * just re-ordering, there's no need for the 1826 * full unlink process. 1827 */ 1828 1829 if (NULL != (next = nn->next)) 1830 next->prev = nn->prev; 1831 1832 if (NULL != (prev = nn->prev)) 1833 prev->next = nn->next; 1834 1835 nn->prev = nn->next = NULL; 1836 1837 /* 1838 * Scan back until we reach a node that's 1839 * ordered before `nn'. 1840 */ 1841 1842 for ( ; prev ; prev = prev->prev) { 1843 /* Determine order of `prev'. */ 1844 for (j = 0; j < RSORD_MAX; j++) 1845 if (rsord[j] == prev->tok) 1846 break; 1847 1848 if (j <= i) 1849 break; 1850 } 1851 1852 /* 1853 * Set `nn' back into its correct place in front 1854 * of the `prev' node. 1855 */ 1856 1857 nn->prev = prev; 1858 1859 if (prev) { 1860 if (prev->next) 1861 prev->next->prev = nn; 1862 nn->next = prev->next; 1863 prev->next = nn; 1864 } else { 1865 mdoc->last->child->prev = nn; 1866 nn->next = mdoc->last->child; 1867 mdoc->last->child = nn; 1868 } 1869 } 1870 1871 return(1); 1872 } 1873 1874 /* 1875 * For some arguments of some macros, 1876 * convert all breakable hyphens into ASCII_HYPH. 1877 */ 1878 static int 1879 post_hyph(POST_ARGS) 1880 { 1881 struct mdoc_node *n, *nch; 1882 char *cp; 1883 1884 n = mdoc->last; 1885 switch (n->type) { 1886 case (MDOC_HEAD): 1887 if (MDOC_Sh == n->tok || MDOC_Ss == n->tok) 1888 break; 1889 return(1); 1890 case (MDOC_BODY): 1891 if (MDOC_D1 == n->tok || MDOC_Nd == n->tok) 1892 break; 1893 return(1); 1894 case (MDOC_ELEM): 1895 break; 1896 default: 1897 return(1); 1898 } 1899 1900 for (nch = n->child; nch; nch = nch->next) { 1901 if (MDOC_TEXT != nch->type) 1902 continue; 1903 cp = nch->string; 1904 if (3 > strnlen(cp, 3)) 1905 continue; 1906 while ('\0' != *(++cp)) 1907 if ('-' == *cp && 1908 isalpha((unsigned char)cp[-1]) && 1909 isalpha((unsigned char)cp[1])) 1910 *cp = ASCII_HYPH; 1911 } 1912 return(1); 1913 } 1914 1915 static int 1916 post_ns(POST_ARGS) 1917 { 1918 1919 if (MDOC_LINE & mdoc->last->flags) 1920 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_IGNNS); 1921 return(1); 1922 } 1923 1924 static int 1925 post_sh(POST_ARGS) 1926 { 1927 1928 if (MDOC_HEAD == mdoc->last->type) 1929 return(post_sh_head(mdoc)); 1930 if (MDOC_BODY == mdoc->last->type) 1931 return(post_sh_body(mdoc)); 1932 1933 return(1); 1934 } 1935 1936 static int 1937 post_sh_body(POST_ARGS) 1938 { 1939 struct mdoc_node *n; 1940 1941 if (SEC_NAME != mdoc->lastsec) 1942 return(1); 1943 1944 /* 1945 * Warn if the NAME section doesn't contain the `Nm' and `Nd' 1946 * macros (can have multiple `Nm' and one `Nd'). Note that the 1947 * children of the BODY declaration can also be "text". 1948 */ 1949 1950 if (NULL == (n = mdoc->last->child)) { 1951 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADNAMESEC); 1952 return(1); 1953 } 1954 1955 for ( ; n && n->next; n = n->next) { 1956 if (MDOC_ELEM == n->type && MDOC_Nm == n->tok) 1957 continue; 1958 if (MDOC_TEXT == n->type) 1959 continue; 1960 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADNAMESEC); 1961 } 1962 1963 assert(n); 1964 if (MDOC_BLOCK == n->type && MDOC_Nd == n->tok) 1965 return(1); 1966 1967 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADNAMESEC); 1968 return(1); 1969 } 1970 1971 static int 1972 post_sh_head(POST_ARGS) 1973 { 1974 char buf[BUFSIZ]; 1975 struct mdoc_node *n; 1976 enum mdoc_sec sec; 1977 int c; 1978 1979 /* 1980 * Process a new section. Sections are either "named" or 1981 * "custom". Custom sections are user-defined, while named ones 1982 * follow a conventional order and may only appear in certain 1983 * manual sections. 1984 */ 1985 1986 sec = SEC_CUSTOM; 1987 buf[0] = '\0'; 1988 if (-1 == (c = concat(buf, mdoc->last->child, BUFSIZ))) { 1989 mdoc_nmsg(mdoc, mdoc->last->child, MANDOCERR_MEM); 1990 return(0); 1991 } else if (1 == c) 1992 sec = a2sec(buf); 1993 1994 /* The NAME should be first. */ 1995 1996 if (SEC_NAME != sec && SEC_NONE == mdoc->lastnamed) 1997 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NAMESECFIRST); 1998 1999 /* The SYNOPSIS gets special attention in other areas. */ 2000 2001 if (SEC_SYNOPSIS == sec) { 2002 roff_setreg(mdoc->roff, "nS", 1, '='); 2003 mdoc->flags |= MDOC_SYNOPSIS; 2004 } else { 2005 roff_setreg(mdoc->roff, "nS", 0, '='); 2006 mdoc->flags &= ~MDOC_SYNOPSIS; 2007 } 2008 2009 /* Mark our last section. */ 2010 2011 mdoc->lastsec = sec; 2012 2013 /* 2014 * Set the section attribute for the current HEAD, for its 2015 * parent BLOCK, and for the HEAD children; the latter can 2016 * only be TEXT nodes, so no recursion is needed. 2017 * For other blocks and elements, including .Sh BODY, this is 2018 * done when allocating the node data structures, but for .Sh 2019 * BLOCK and HEAD, the section is still unknown at that time. 2020 */ 2021 2022 mdoc->last->parent->sec = sec; 2023 mdoc->last->sec = sec; 2024 for (n = mdoc->last->child; n; n = n->next) 2025 n->sec = sec; 2026 2027 /* We don't care about custom sections after this. */ 2028 2029 if (SEC_CUSTOM == sec) 2030 return(1); 2031 2032 /* 2033 * Check whether our non-custom section is being repeated or is 2034 * out of order. 2035 */ 2036 2037 if (sec == mdoc->lastnamed) 2038 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_SECREP); 2039 2040 if (sec < mdoc->lastnamed) 2041 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_SECOOO); 2042 2043 /* Mark the last named section. */ 2044 2045 mdoc->lastnamed = sec; 2046 2047 /* Check particular section/manual conventions. */ 2048 2049 assert(mdoc->meta.msec); 2050 2051 switch (sec) { 2052 case (SEC_RETURN_VALUES): 2053 /* FALLTHROUGH */ 2054 case (SEC_ERRORS): 2055 /* FALLTHROUGH */ 2056 case (SEC_LIBRARY): 2057 if (*mdoc->meta.msec == '2') 2058 break; 2059 if (*mdoc->meta.msec == '3') 2060 break; 2061 if (*mdoc->meta.msec == '9') 2062 break; 2063 mandoc_msg(MANDOCERR_SECMSEC, mdoc->parse, 2064 mdoc->last->line, mdoc->last->pos, buf); 2065 break; 2066 default: 2067 break; 2068 } 2069 2070 return(1); 2071 } 2072 2073 static int 2074 post_ignpar(POST_ARGS) 2075 { 2076 struct mdoc_node *np; 2077 2078 if (MDOC_BODY != mdoc->last->type) 2079 return(1); 2080 2081 if (NULL != (np = mdoc->last->child)) 2082 if (MDOC_Pp == np->tok || MDOC_Lp == np->tok) { 2083 mdoc_nmsg(mdoc, np, MANDOCERR_IGNPAR); 2084 mdoc_node_delete(mdoc, np); 2085 } 2086 2087 if (NULL != (np = mdoc->last->last)) 2088 if (MDOC_Pp == np->tok || MDOC_Lp == np->tok) { 2089 mdoc_nmsg(mdoc, np, MANDOCERR_IGNPAR); 2090 mdoc_node_delete(mdoc, np); 2091 } 2092 2093 return(1); 2094 } 2095 2096 static int 2097 pre_par(PRE_ARGS) 2098 { 2099 2100 if (NULL == mdoc->last) 2101 return(1); 2102 if (MDOC_ELEM != n->type && MDOC_BLOCK != n->type) 2103 return(1); 2104 2105 /* 2106 * Don't allow prior `Lp' or `Pp' prior to a paragraph-type 2107 * block: `Lp', `Pp', or non-compact `Bd' or `Bl'. 2108 */ 2109 2110 if (MDOC_Pp != mdoc->last->tok && 2111 MDOC_Lp != mdoc->last->tok && 2112 MDOC_br != mdoc->last->tok) 2113 return(1); 2114 if (MDOC_Bl == n->tok && n->norm->Bl.comp) 2115 return(1); 2116 if (MDOC_Bd == n->tok && n->norm->Bd.comp) 2117 return(1); 2118 if (MDOC_It == n->tok && n->parent->norm->Bl.comp) 2119 return(1); 2120 2121 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_IGNPAR); 2122 mdoc_node_delete(mdoc, mdoc->last); 2123 return(1); 2124 } 2125 2126 static int 2127 post_par(POST_ARGS) 2128 { 2129 2130 if (MDOC_ELEM != mdoc->last->type && 2131 MDOC_BLOCK != mdoc->last->type) 2132 return(1); 2133 2134 if (NULL == mdoc->last->prev) { 2135 if (MDOC_Sh != mdoc->last->parent->tok && 2136 MDOC_Ss != mdoc->last->parent->tok) 2137 return(1); 2138 } else { 2139 if (MDOC_Pp != mdoc->last->prev->tok && 2140 MDOC_Lp != mdoc->last->prev->tok && 2141 (MDOC_br != mdoc->last->tok || 2142 (MDOC_sp != mdoc->last->prev->tok && 2143 MDOC_br != mdoc->last->prev->tok))) 2144 return(1); 2145 } 2146 2147 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_IGNPAR); 2148 mdoc_node_delete(mdoc, mdoc->last); 2149 return(1); 2150 } 2151 2152 static int 2153 pre_literal(PRE_ARGS) 2154 { 2155 2156 if (MDOC_BODY != n->type) 2157 return(1); 2158 2159 /* 2160 * The `Dl' (note "el" not "one") and `Bd -literal' and `Bd 2161 * -unfilled' macros set MDOC_LITERAL on entrance to the body. 2162 */ 2163 2164 switch (n->tok) { 2165 case (MDOC_Dl): 2166 mdoc->flags |= MDOC_LITERAL; 2167 break; 2168 case (MDOC_Bd): 2169 if (DISP_literal == n->norm->Bd.type) 2170 mdoc->flags |= MDOC_LITERAL; 2171 if (DISP_unfilled == n->norm->Bd.type) 2172 mdoc->flags |= MDOC_LITERAL; 2173 break; 2174 default: 2175 abort(); 2176 /* NOTREACHED */ 2177 } 2178 2179 return(1); 2180 } 2181 2182 static int 2183 post_dd(POST_ARGS) 2184 { 2185 char buf[DATESIZE]; 2186 struct mdoc_node *n; 2187 int c; 2188 2189 if (mdoc->meta.date) 2190 free(mdoc->meta.date); 2191 2192 n = mdoc->last; 2193 if (NULL == n->child || '\0' == n->child->string[0]) { 2194 mdoc->meta.date = mandoc_normdate 2195 (mdoc->parse, NULL, n->line, n->pos); 2196 return(1); 2197 } 2198 2199 buf[0] = '\0'; 2200 if (-1 == (c = concat(buf, n->child, DATESIZE))) { 2201 mdoc_nmsg(mdoc, n->child, MANDOCERR_MEM); 2202 return(0); 2203 } 2204 2205 assert(c); 2206 mdoc->meta.date = mandoc_normdate 2207 (mdoc->parse, buf, n->line, n->pos); 2208 2209 return(1); 2210 } 2211 2212 static int 2213 post_dt(POST_ARGS) 2214 { 2215 struct mdoc_node *nn, *n; 2216 const char *cp; 2217 char *p; 2218 2219 n = mdoc->last; 2220 2221 if (mdoc->meta.title) 2222 free(mdoc->meta.title); 2223 if (mdoc->meta.vol) 2224 free(mdoc->meta.vol); 2225 if (mdoc->meta.arch) 2226 free(mdoc->meta.arch); 2227 2228 mdoc->meta.title = mdoc->meta.vol = mdoc->meta.arch = NULL; 2229 2230 /* First make all characters uppercase. */ 2231 2232 if (NULL != (nn = n->child)) 2233 for (p = nn->string; *p; p++) { 2234 if (toupper((unsigned char)*p) == *p) 2235 continue; 2236 2237 /* 2238 * FIXME: don't be lazy: have this make all 2239 * characters be uppercase and just warn once. 2240 */ 2241 mdoc_nmsg(mdoc, nn, MANDOCERR_UPPERCASE); 2242 break; 2243 } 2244 2245 /* Handles: `.Dt' 2246 * --> title = unknown, volume = local, msec = 0, arch = NULL 2247 */ 2248 2249 if (NULL == (nn = n->child)) { 2250 /* XXX: make these macro values. */ 2251 /* FIXME: warn about missing values. */ 2252 mdoc->meta.title = mandoc_strdup("UNKNOWN"); 2253 mdoc->meta.vol = mandoc_strdup("LOCAL"); 2254 mdoc->meta.msec = mandoc_strdup("1"); 2255 return(1); 2256 } 2257 2258 /* Handles: `.Dt TITLE' 2259 * --> title = TITLE, volume = local, msec = 0, arch = NULL 2260 */ 2261 2262 mdoc->meta.title = mandoc_strdup 2263 ('\0' == nn->string[0] ? "UNKNOWN" : nn->string); 2264 2265 if (NULL == (nn = nn->next)) { 2266 /* FIXME: warn about missing msec. */ 2267 /* XXX: make this a macro value. */ 2268 mdoc->meta.vol = mandoc_strdup("LOCAL"); 2269 mdoc->meta.msec = mandoc_strdup("1"); 2270 return(1); 2271 } 2272 2273 /* Handles: `.Dt TITLE SEC' 2274 * --> title = TITLE, volume = SEC is msec ? 2275 * format(msec) : SEC, 2276 * msec = SEC is msec ? atoi(msec) : 0, 2277 * arch = NULL 2278 */ 2279 2280 cp = mandoc_a2msec(nn->string); 2281 if (cp) { 2282 mdoc->meta.vol = mandoc_strdup(cp); 2283 mdoc->meta.msec = mandoc_strdup(nn->string); 2284 } else { 2285 mdoc_nmsg(mdoc, n, MANDOCERR_BADMSEC); 2286 mdoc->meta.vol = mandoc_strdup(nn->string); 2287 mdoc->meta.msec = mandoc_strdup(nn->string); 2288 } 2289 2290 if (NULL == (nn = nn->next)) 2291 return(1); 2292 2293 /* Handles: `.Dt TITLE SEC VOL' 2294 * --> title = TITLE, volume = VOL is vol ? 2295 * format(VOL) : 2296 * VOL is arch ? format(arch) : 2297 * VOL 2298 */ 2299 2300 cp = mdoc_a2vol(nn->string); 2301 if (cp) { 2302 free(mdoc->meta.vol); 2303 mdoc->meta.vol = mandoc_strdup(cp); 2304 } else { 2305 cp = mdoc_a2arch(nn->string); 2306 if (NULL == cp) { 2307 mdoc_nmsg(mdoc, nn, MANDOCERR_BADVOLARCH); 2308 free(mdoc->meta.vol); 2309 mdoc->meta.vol = mandoc_strdup(nn->string); 2310 } else 2311 mdoc->meta.arch = mandoc_strdup(cp); 2312 } 2313 2314 /* Ignore any subsequent parameters... */ 2315 /* FIXME: warn about subsequent parameters. */ 2316 2317 return(1); 2318 } 2319 2320 static int 2321 post_prol(POST_ARGS) 2322 { 2323 /* 2324 * Remove prologue macros from the document after they're 2325 * processed. The final document uses mdoc_meta for these 2326 * values and discards the originals. 2327 */ 2328 2329 mdoc_node_delete(mdoc, mdoc->last); 2330 if (mdoc->meta.title && mdoc->meta.date && mdoc->meta.os) 2331 mdoc->flags |= MDOC_PBODY; 2332 2333 return(1); 2334 } 2335 2336 static int 2337 post_bx(POST_ARGS) 2338 { 2339 struct mdoc_node *n; 2340 2341 /* 2342 * Make `Bx's second argument always start with an uppercase 2343 * letter. Groff checks if it's an "accepted" term, but we just 2344 * uppercase blindly. 2345 */ 2346 2347 n = mdoc->last->child; 2348 if (n && NULL != (n = n->next)) 2349 *n->string = (char)toupper 2350 ((unsigned char)*n->string); 2351 2352 return(1); 2353 } 2354 2355 static int 2356 post_os(POST_ARGS) 2357 { 2358 struct mdoc_node *n; 2359 char buf[BUFSIZ]; 2360 int c; 2361 #ifndef OSNAME 2362 struct utsname utsname; 2363 #endif 2364 2365 n = mdoc->last; 2366 2367 /* 2368 * Set the operating system by way of the `Os' macro. 2369 * The order of precedence is: 2370 * 1. the argument of the `Os' macro, unless empty 2371 * 2. the -Ios=foo command line argument, if provided 2372 * 3. -DOSNAME="\"foo\"", if provided during compilation 2373 * 4. "sysname release" from uname(3) 2374 */ 2375 2376 free(mdoc->meta.os); 2377 2378 buf[0] = '\0'; 2379 if (-1 == (c = concat(buf, n->child, BUFSIZ))) { 2380 mdoc_nmsg(mdoc, n->child, MANDOCERR_MEM); 2381 return(0); 2382 } 2383 2384 assert(c); 2385 2386 if ('\0' == buf[0]) { 2387 if (mdoc->defos) { 2388 mdoc->meta.os = mandoc_strdup(mdoc->defos); 2389 return(1); 2390 } 2391 #ifdef OSNAME 2392 if (strlcat(buf, OSNAME, BUFSIZ) >= BUFSIZ) { 2393 mdoc_nmsg(mdoc, n, MANDOCERR_MEM); 2394 return(0); 2395 } 2396 #else /*!OSNAME */ 2397 if (-1 == uname(&utsname)) { 2398 mdoc_nmsg(mdoc, n, MANDOCERR_UNAME); 2399 mdoc->meta.os = mandoc_strdup("UNKNOWN"); 2400 return(post_prol(mdoc)); 2401 } 2402 2403 if (strlcat(buf, utsname.sysname, BUFSIZ) >= BUFSIZ) { 2404 mdoc_nmsg(mdoc, n, MANDOCERR_MEM); 2405 return(0); 2406 } 2407 if (strlcat(buf, " ", BUFSIZ) >= BUFSIZ) { 2408 mdoc_nmsg(mdoc, n, MANDOCERR_MEM); 2409 return(0); 2410 } 2411 if (strlcat(buf, utsname.release, BUFSIZ) >= BUFSIZ) { 2412 mdoc_nmsg(mdoc, n, MANDOCERR_MEM); 2413 return(0); 2414 } 2415 #endif /*!OSNAME*/ 2416 } 2417 2418 mdoc->meta.os = mandoc_strdup(buf); 2419 return(1); 2420 } 2421 2422 static int 2423 post_std(POST_ARGS) 2424 { 2425 struct mdoc_node *nn, *n; 2426 2427 n = mdoc->last; 2428 2429 /* 2430 * Macros accepting `-std' as an argument have the name of the 2431 * current document (`Nm') filled in as the argument if it's not 2432 * provided. 2433 */ 2434 2435 if (n->child) 2436 return(1); 2437 2438 if (NULL == mdoc->meta.name) 2439 return(1); 2440 2441 nn = n; 2442 mdoc->next = MDOC_NEXT_CHILD; 2443 2444 if ( ! mdoc_word_alloc(mdoc, n->line, n->pos, mdoc->meta.name)) 2445 return(0); 2446 2447 mdoc->last = nn; 2448 return(1); 2449 } 2450 2451 /* 2452 * Concatenate a node, stopping at the first non-text. 2453 * Concatenation is separated by a single whitespace. 2454 * Returns -1 on fatal (string overrun) error, 0 if child nodes were 2455 * encountered, 1 otherwise. 2456 */ 2457 static int 2458 concat(char *p, const struct mdoc_node *n, size_t sz) 2459 { 2460 2461 for ( ; NULL != n; n = n->next) { 2462 if (MDOC_TEXT != n->type) 2463 return(0); 2464 if ('\0' != p[0] && strlcat(p, " ", sz) >= sz) 2465 return(-1); 2466 if (strlcat(p, n->string, sz) >= sz) 2467 return(-1); 2468 concat(p, n->child, sz); 2469 } 2470 2471 return(1); 2472 } 2473 2474 static enum mdoc_sec 2475 a2sec(const char *p) 2476 { 2477 int i; 2478 2479 for (i = 0; i < (int)SEC__MAX; i++) 2480 if (secnames[i] && 0 == strcmp(p, secnames[i])) 2481 return((enum mdoc_sec)i); 2482 2483 return(SEC_CUSTOM); 2484 } 2485 2486 static size_t 2487 macro2len(enum mdoct macro) 2488 { 2489 2490 switch (macro) { 2491 case(MDOC_Ad): 2492 return(12); 2493 case(MDOC_Ao): 2494 return(12); 2495 case(MDOC_An): 2496 return(12); 2497 case(MDOC_Aq): 2498 return(12); 2499 case(MDOC_Ar): 2500 return(12); 2501 case(MDOC_Bo): 2502 return(12); 2503 case(MDOC_Bq): 2504 return(12); 2505 case(MDOC_Cd): 2506 return(12); 2507 case(MDOC_Cm): 2508 return(10); 2509 case(MDOC_Do): 2510 return(10); 2511 case(MDOC_Dq): 2512 return(12); 2513 case(MDOC_Dv): 2514 return(12); 2515 case(MDOC_Eo): 2516 return(12); 2517 case(MDOC_Em): 2518 return(10); 2519 case(MDOC_Er): 2520 return(17); 2521 case(MDOC_Ev): 2522 return(15); 2523 case(MDOC_Fa): 2524 return(12); 2525 case(MDOC_Fl): 2526 return(10); 2527 case(MDOC_Fo): 2528 return(16); 2529 case(MDOC_Fn): 2530 return(16); 2531 case(MDOC_Ic): 2532 return(10); 2533 case(MDOC_Li): 2534 return(16); 2535 case(MDOC_Ms): 2536 return(6); 2537 case(MDOC_Nm): 2538 return(10); 2539 case(MDOC_No): 2540 return(12); 2541 case(MDOC_Oo): 2542 return(10); 2543 case(MDOC_Op): 2544 return(14); 2545 case(MDOC_Pa): 2546 return(32); 2547 case(MDOC_Pf): 2548 return(12); 2549 case(MDOC_Po): 2550 return(12); 2551 case(MDOC_Pq): 2552 return(12); 2553 case(MDOC_Ql): 2554 return(16); 2555 case(MDOC_Qo): 2556 return(12); 2557 case(MDOC_So): 2558 return(12); 2559 case(MDOC_Sq): 2560 return(12); 2561 case(MDOC_Sy): 2562 return(6); 2563 case(MDOC_Sx): 2564 return(16); 2565 case(MDOC_Tn): 2566 return(10); 2567 case(MDOC_Va): 2568 return(12); 2569 case(MDOC_Vt): 2570 return(12); 2571 case(MDOC_Xr): 2572 return(10); 2573 default: 2574 break; 2575 }; 2576 return(0); 2577 } 2578