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