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