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