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