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