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