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