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