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