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