mdoc_validate.c revision 1.50
1/* $Id: mdoc_validate.c,v 1.50 2010/05/14 01:54:37 schwarze Exp $ */ 2/* 3 * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17#include <sys/types.h> 18 19#include <assert.h> 20#include <ctype.h> 21#include <limits.h> 22#include <stdarg.h> 23#include <stdlib.h> 24#include <string.h> 25 26#include "libmdoc.h" 27#include "libmandoc.h" 28 29/* FIXME: .Bl -diag can't have non-text children in HEAD. */ 30/* TODO: ignoring Pp (it's superfluous in some invocations). */ 31 32#define PRE_ARGS struct mdoc *mdoc, const struct mdoc_node *n 33#define POST_ARGS struct mdoc *mdoc 34 35typedef int (*v_pre)(PRE_ARGS); 36typedef int (*v_post)(POST_ARGS); 37 38struct valids { 39 v_pre *pre; 40 v_post *post; 41}; 42 43static int check_parent(PRE_ARGS, enum mdoct, enum mdoc_type); 44static int check_msec(PRE_ARGS, ...); 45static int check_sec(PRE_ARGS, ...); 46static int check_stdarg(PRE_ARGS); 47static int check_text(struct mdoc *, int, int, const char *); 48static int check_argv(struct mdoc *, 49 const struct mdoc_node *, 50 const struct mdoc_argv *); 51static int check_args(struct mdoc *, 52 const struct mdoc_node *); 53static int err_child_lt(struct mdoc *, const char *, int); 54static int warn_child_lt(struct mdoc *, const char *, int); 55static int err_child_gt(struct mdoc *, const char *, int); 56static int warn_child_gt(struct mdoc *, const char *, int); 57static int err_child_eq(struct mdoc *, const char *, int); 58static int warn_child_eq(struct mdoc *, const char *, int); 59static int warn_count(struct mdoc *, const char *, 60 int, const char *, int); 61static int err_count(struct mdoc *, const char *, 62 int, const char *, int); 63 64static int berr_ge1(POST_ARGS); 65static int bwarn_ge1(POST_ARGS); 66static int ebool(POST_ARGS); 67static int eerr_eq0(POST_ARGS); 68static int eerr_eq1(POST_ARGS); 69static int eerr_ge1(POST_ARGS); 70static int eerr_le1(POST_ARGS); 71static int ewarn_ge1(POST_ARGS); 72static int herr_eq0(POST_ARGS); 73static int herr_ge1(POST_ARGS); 74static int hwarn_eq1(POST_ARGS); 75static int hwarn_eq0(POST_ARGS); 76static int hwarn_le1(POST_ARGS); 77 78static int post_an(POST_ARGS); 79static int post_at(POST_ARGS); 80static int post_bf(POST_ARGS); 81static int post_bl(POST_ARGS); 82static int post_bl_head(POST_ARGS); 83static int post_it(POST_ARGS); 84static int post_lb(POST_ARGS); 85static int post_nm(POST_ARGS); 86static int post_root(POST_ARGS); 87static int post_rs(POST_ARGS); 88static int post_sh(POST_ARGS); 89static int post_sh_body(POST_ARGS); 90static int post_sh_head(POST_ARGS); 91static int post_st(POST_ARGS); 92static int post_vt(POST_ARGS); 93static int pre_an(PRE_ARGS); 94static int pre_bd(PRE_ARGS); 95static int pre_bl(PRE_ARGS); 96static int pre_dd(PRE_ARGS); 97static int pre_display(PRE_ARGS); 98static int pre_dt(PRE_ARGS); 99static int pre_ex(PRE_ARGS); 100static int pre_fd(PRE_ARGS); 101static int pre_it(PRE_ARGS); 102static int pre_lb(PRE_ARGS); 103static int pre_os(PRE_ARGS); 104static int pre_rv(PRE_ARGS); 105static int pre_sh(PRE_ARGS); 106static int pre_ss(PRE_ARGS); 107 108static v_post posts_an[] = { post_an, NULL }; 109static v_post posts_at[] = { post_at, NULL }; 110static v_post posts_bd[] = { hwarn_eq0, bwarn_ge1, NULL }; 111static v_post posts_bf[] = { hwarn_le1, post_bf, NULL }; 112static v_post posts_bl[] = { bwarn_ge1, post_bl, NULL }; 113static v_post posts_bool[] = { eerr_eq1, ebool, NULL }; 114static v_post posts_fo[] = { hwarn_eq1, bwarn_ge1, NULL }; 115static v_post posts_it[] = { post_it, NULL }; 116static v_post posts_lb[] = { eerr_eq1, post_lb, NULL }; 117static v_post posts_nd[] = { berr_ge1, NULL }; 118static v_post posts_nm[] = { post_nm, NULL }; 119static v_post posts_notext[] = { eerr_eq0, NULL }; 120static v_post posts_rs[] = { berr_ge1, herr_eq0, post_rs, NULL }; 121static v_post posts_sh[] = { herr_ge1, bwarn_ge1, post_sh, NULL }; 122static v_post posts_sp[] = { eerr_le1, NULL }; 123static v_post posts_ss[] = { herr_ge1, NULL }; 124static v_post posts_st[] = { eerr_eq1, post_st, NULL }; 125static v_post posts_text[] = { eerr_ge1, NULL }; 126static v_post posts_text1[] = { eerr_eq1, NULL }; 127static v_post posts_vt[] = { post_vt, NULL }; 128static v_post posts_wline[] = { bwarn_ge1, herr_eq0, NULL }; 129static v_post posts_wtext[] = { ewarn_ge1, NULL }; 130static v_post posts_xr[] = { ewarn_ge1, NULL }; 131static v_pre pres_an[] = { pre_an, NULL }; 132static v_pre pres_bd[] = { pre_display, pre_bd, NULL }; 133static v_pre pres_bl[] = { pre_bl, NULL }; 134static v_pre pres_d1[] = { pre_display, NULL }; 135static v_pre pres_dd[] = { pre_dd, NULL }; 136static v_pre pres_dt[] = { pre_dt, NULL }; 137static v_pre pres_er[] = { NULL, NULL }; 138static v_pre pres_ex[] = { pre_ex, NULL }; 139static v_pre pres_fd[] = { pre_fd, NULL }; 140static v_pre pres_it[] = { pre_it, NULL }; 141static v_pre pres_lb[] = { pre_lb, NULL }; 142static v_pre pres_os[] = { pre_os, NULL }; 143static v_pre pres_rv[] = { pre_rv, NULL }; 144static v_pre pres_sh[] = { pre_sh, NULL }; 145static v_pre pres_ss[] = { pre_ss, NULL }; 146 147const struct valids mdoc_valids[MDOC_MAX] = { 148 { NULL, NULL }, /* Ap */ 149 { pres_dd, posts_text }, /* Dd */ 150 { pres_dt, NULL }, /* Dt */ 151 { pres_os, NULL }, /* Os */ 152 { pres_sh, posts_sh }, /* Sh */ 153 { pres_ss, posts_ss }, /* Ss */ 154 { NULL, posts_notext }, /* Pp */ 155 { pres_d1, posts_wline }, /* D1 */ 156 { pres_d1, posts_wline }, /* Dl */ 157 { pres_bd, posts_bd }, /* Bd */ 158 { NULL, NULL }, /* Ed */ 159 { pres_bl, posts_bl }, /* Bl */ 160 { NULL, NULL }, /* El */ 161 { pres_it, posts_it }, /* It */ 162 { NULL, posts_text }, /* Ad */ 163 { pres_an, posts_an }, /* An */ 164 { NULL, NULL }, /* Ar */ 165 { NULL, posts_text }, /* Cd */ 166 { NULL, NULL }, /* Cm */ 167 { NULL, NULL }, /* Dv */ 168 { pres_er, posts_text }, /* Er */ 169 { NULL, NULL }, /* Ev */ 170 { pres_ex, NULL }, /* Ex */ 171 { NULL, NULL }, /* Fa */ 172 { pres_fd, posts_wtext }, /* Fd */ 173 { NULL, NULL }, /* Fl */ 174 { NULL, posts_text }, /* Fn */ 175 { NULL, posts_wtext }, /* Ft */ 176 { NULL, posts_text }, /* Ic */ 177 { NULL, posts_text1 }, /* In */ 178 { NULL, NULL }, /* Li */ 179 { NULL, posts_nd }, /* Nd */ 180 { NULL, posts_nm }, /* Nm */ 181 { NULL, posts_wline }, /* Op */ 182 { NULL, NULL }, /* Ot */ 183 { NULL, NULL }, /* Pa */ 184 { pres_rv, NULL }, /* Rv */ 185 { NULL, posts_st }, /* St */ 186 { NULL, NULL }, /* Va */ 187 { NULL, posts_vt }, /* Vt */ 188 { NULL, posts_xr }, /* Xr */ 189 { NULL, posts_text }, /* %A */ 190 { NULL, posts_text }, /* %B */ /* FIXME: can be used outside Rs/Re. */ 191 { NULL, posts_text }, /* %D */ /* FIXME: check date with mandoc_a2time(). */ 192 { NULL, posts_text }, /* %I */ 193 { NULL, posts_text }, /* %J */ 194 { NULL, posts_text }, /* %N */ 195 { NULL, posts_text }, /* %O */ 196 { NULL, posts_text }, /* %P */ 197 { NULL, posts_text }, /* %R */ 198 { NULL, posts_text }, /* %T */ /* FIXME: can be used outside Rs/Re. */ 199 { NULL, posts_text }, /* %V */ 200 { NULL, NULL }, /* Ac */ 201 { NULL, NULL }, /* Ao */ 202 { NULL, posts_wline }, /* Aq */ 203 { NULL, posts_at }, /* At */ 204 { NULL, NULL }, /* Bc */ 205 { NULL, posts_bf }, /* Bf */ 206 { NULL, NULL }, /* Bo */ 207 { NULL, posts_wline }, /* Bq */ 208 { NULL, NULL }, /* Bsx */ 209 { NULL, NULL }, /* Bx */ 210 { NULL, posts_bool }, /* Db */ 211 { NULL, NULL }, /* Dc */ 212 { NULL, NULL }, /* Do */ 213 { NULL, posts_wline }, /* Dq */ 214 { NULL, NULL }, /* Ec */ 215 { NULL, NULL }, /* Ef */ 216 { NULL, NULL }, /* Em */ 217 { NULL, NULL }, /* Eo */ 218 { NULL, NULL }, /* Fx */ 219 { NULL, posts_text }, /* Ms */ 220 { NULL, posts_notext }, /* No */ 221 { NULL, posts_notext }, /* Ns */ 222 { NULL, NULL }, /* Nx */ 223 { NULL, NULL }, /* Ox */ 224 { NULL, NULL }, /* Pc */ 225 { NULL, posts_text1 }, /* Pf */ 226 { NULL, NULL }, /* Po */ 227 { NULL, posts_wline }, /* Pq */ 228 { NULL, NULL }, /* Qc */ 229 { NULL, posts_wline }, /* Ql */ 230 { NULL, NULL }, /* Qo */ 231 { NULL, posts_wline }, /* Qq */ 232 { NULL, NULL }, /* Re */ 233 { NULL, posts_rs }, /* Rs */ 234 { NULL, NULL }, /* Sc */ 235 { NULL, NULL }, /* So */ 236 { NULL, posts_wline }, /* Sq */ 237 { NULL, posts_bool }, /* Sm */ 238 { NULL, posts_text }, /* Sx */ 239 { NULL, posts_text }, /* Sy */ 240 { NULL, posts_text }, /* Tn */ 241 { NULL, NULL }, /* Ux */ 242 { NULL, NULL }, /* Xc */ 243 { NULL, NULL }, /* Xo */ 244 { NULL, posts_fo }, /* Fo */ 245 { NULL, NULL }, /* Fc */ 246 { NULL, NULL }, /* Oo */ 247 { NULL, NULL }, /* Oc */ 248 { NULL, posts_wline }, /* Bk */ 249 { NULL, NULL }, /* Ek */ 250 { NULL, posts_notext }, /* Bt */ 251 { NULL, NULL }, /* Hf */ 252 { NULL, NULL }, /* Fr */ 253 { NULL, posts_notext }, /* Ud */ 254 { pres_lb, posts_lb }, /* Lb */ 255 { NULL, posts_notext }, /* Lp */ 256 { NULL, posts_text }, /* Lk */ 257 { NULL, posts_text }, /* Mt */ 258 { NULL, posts_wline }, /* Brq */ 259 { NULL, NULL }, /* Bro */ 260 { NULL, NULL }, /* Brc */ 261 { NULL, posts_text }, /* %C */ 262 { NULL, NULL }, /* Es */ 263 { NULL, NULL }, /* En */ 264 { NULL, NULL }, /* Dx */ 265 { NULL, posts_text }, /* %Q */ 266 { NULL, posts_notext }, /* br */ 267 { NULL, posts_sp }, /* sp */ 268 { NULL, posts_text1 }, /* %U */ 269 { NULL, NULL }, /* eos */ 270}; 271 272 273int 274mdoc_valid_pre(struct mdoc *mdoc, const struct mdoc_node *n) 275{ 276 v_pre *p; 277 int line, pos; 278 const char *tp; 279 280 if (MDOC_TEXT == n->type) { 281 tp = n->string; 282 line = n->line; 283 pos = n->pos; 284 return(check_text(mdoc, line, pos, tp)); 285 } 286 287 if ( ! check_args(mdoc, n)) 288 return(0); 289 if (NULL == mdoc_valids[n->tok].pre) 290 return(1); 291 for (p = mdoc_valids[n->tok].pre; *p; p++) 292 if ( ! (*p)(mdoc, n)) 293 return(0); 294 return(1); 295} 296 297 298int 299mdoc_valid_post(struct mdoc *mdoc) 300{ 301 v_post *p; 302 303 if (MDOC_VALID & mdoc->last->flags) 304 return(1); 305 mdoc->last->flags |= MDOC_VALID; 306 307 if (MDOC_TEXT == mdoc->last->type) 308 return(1); 309 if (MDOC_ROOT == mdoc->last->type) 310 return(post_root(mdoc)); 311 312 if (NULL == mdoc_valids[mdoc->last->tok].post) 313 return(1); 314 for (p = mdoc_valids[mdoc->last->tok].post; *p; p++) 315 if ( ! (*p)(mdoc)) 316 return(0); 317 318 return(1); 319} 320 321 322static inline int 323warn_count(struct mdoc *m, const char *k, 324 int want, const char *v, int has) 325{ 326 327 return(mdoc_vwarn(m, m->last->line, m->last->pos, 328 "suggests %s %s %d (has %d)", v, k, want, has)); 329} 330 331 332static inline int 333err_count(struct mdoc *m, const char *k, 334 int want, const char *v, int has) 335{ 336 337 return(mdoc_verr(m, m->last->line, m->last->pos, 338 "requires %s %s %d (has %d)", v, k, want, has)); 339} 340 341 342/* 343 * Build these up with macros because they're basically the same check 344 * for different inequalities. Yes, this could be done with functions, 345 * but this is reasonable for now. 346 */ 347 348#define CHECK_CHILD_DEFN(lvl, name, ineq) \ 349static int \ 350lvl##_child_##name(struct mdoc *mdoc, const char *p, int sz) \ 351{ \ 352 if (mdoc->last->nchild ineq sz) \ 353 return(1); \ 354 return(lvl##_count(mdoc, #ineq, sz, p, mdoc->last->nchild)); \ 355} 356 357#define CHECK_BODY_DEFN(name, lvl, func, num) \ 358static int \ 359b##lvl##_##name(POST_ARGS) \ 360{ \ 361 if (MDOC_BODY != mdoc->last->type) \ 362 return(1); \ 363 return(func(mdoc, "multi-line arguments", (num))); \ 364} 365 366#define CHECK_ELEM_DEFN(name, lvl, func, num) \ 367static int \ 368e##lvl##_##name(POST_ARGS) \ 369{ \ 370 assert(MDOC_ELEM == mdoc->last->type); \ 371 return(func(mdoc, "line arguments", (num))); \ 372} 373 374#define CHECK_HEAD_DEFN(name, lvl, func, num) \ 375static int \ 376h##lvl##_##name(POST_ARGS) \ 377{ \ 378 if (MDOC_HEAD != mdoc->last->type) \ 379 return(1); \ 380 return(func(mdoc, "line arguments", (num))); \ 381} 382 383 384CHECK_CHILD_DEFN(warn, gt, >) /* warn_child_gt() */ 385CHECK_CHILD_DEFN(err, gt, >) /* err_child_gt() */ 386CHECK_CHILD_DEFN(warn, eq, ==) /* warn_child_eq() */ 387CHECK_CHILD_DEFN(err, eq, ==) /* err_child_eq() */ 388CHECK_CHILD_DEFN(err, lt, <) /* err_child_lt() */ 389CHECK_CHILD_DEFN(warn, lt, <) /* warn_child_lt() */ 390CHECK_BODY_DEFN(ge1, warn, warn_child_gt, 0) /* bwarn_ge1() */ 391CHECK_BODY_DEFN(ge1, err, err_child_gt, 0) /* berr_ge1() */ 392CHECK_ELEM_DEFN(ge1, warn, warn_child_gt, 0) /* ewarn_gt1() */ 393CHECK_ELEM_DEFN(eq1, err, err_child_eq, 1) /* eerr_eq1() */ 394CHECK_ELEM_DEFN(le1, err, err_child_lt, 2) /* eerr_le1() */ 395CHECK_ELEM_DEFN(eq0, err, err_child_eq, 0) /* eerr_eq0() */ 396CHECK_ELEM_DEFN(ge1, err, err_child_gt, 0) /* eerr_ge1() */ 397CHECK_HEAD_DEFN(eq0, err, err_child_eq, 0) /* herr_eq0() */ 398CHECK_HEAD_DEFN(le1, warn, warn_child_lt, 2) /* hwarn_le1() */ 399CHECK_HEAD_DEFN(ge1, err, err_child_gt, 0) /* herr_ge1() */ 400CHECK_HEAD_DEFN(eq1, warn, warn_child_eq, 1) /* hwarn_eq1() */ 401CHECK_HEAD_DEFN(eq0, warn, warn_child_eq, 0) /* hwarn_eq0() */ 402 403 404static int 405check_stdarg(PRE_ARGS) 406{ 407 408 if (n->args && 1 == n->args->argc) 409 if (MDOC_Std == n->args->argv[0].arg) 410 return(1); 411 return(mdoc_nwarn(mdoc, n, EARGVAL)); 412} 413 414 415static int 416check_sec(PRE_ARGS, ...) 417{ 418 enum mdoc_sec sec; 419 va_list ap; 420 421 va_start(ap, n); 422 423 for (;;) { 424 /* LINTED */ 425 sec = (enum mdoc_sec)va_arg(ap, int); 426 if (SEC_CUSTOM == sec) 427 break; 428 if (sec != mdoc->lastsec) 429 continue; 430 va_end(ap); 431 return(1); 432 } 433 434 va_end(ap); 435 return(mdoc_nwarn(mdoc, n, EBADSEC)); 436} 437 438 439static int 440check_msec(PRE_ARGS, ...) 441{ 442 va_list ap; 443 int msec; 444 445 va_start(ap, n); 446 for (;;) { 447 /* LINTED */ 448 if (0 == (msec = va_arg(ap, int))) 449 break; 450 if (msec != mdoc->meta.msec) 451 continue; 452 va_end(ap); 453 return(1); 454 } 455 456 va_end(ap); 457 return(mdoc_nwarn(mdoc, n, EBADMSEC)); 458} 459 460 461static int 462check_args(struct mdoc *m, const struct mdoc_node *n) 463{ 464 int i; 465 466 if (NULL == n->args) 467 return(1); 468 469 assert(n->args->argc); 470 for (i = 0; i < (int)n->args->argc; i++) 471 if ( ! check_argv(m, n, &n->args->argv[i])) 472 return(0); 473 474 return(1); 475} 476 477 478static int 479check_argv(struct mdoc *m, const struct mdoc_node *n, 480 const struct mdoc_argv *v) 481{ 482 int i; 483 484 for (i = 0; i < (int)v->sz; i++) 485 if ( ! check_text(m, v->line, v->pos, v->value[i])) 486 return(0); 487 488 if (MDOC_Std == v->arg) { 489 /* `Nm' name must be set. */ 490 if (v->sz || m->meta.name) 491 return(1); 492 return(mdoc_nerr(m, n, ENAME)); 493 } 494 495 return(1); 496} 497 498 499static int 500check_text(struct mdoc *mdoc, int line, int pos, const char *p) 501{ 502 int c; 503 504 for ( ; *p; p++, pos++) { 505 if ('\t' == *p) { 506 if ( ! (MDOC_LITERAL & mdoc->flags)) 507 if ( ! mdoc_pwarn(mdoc, line, pos, EPRINT)) 508 return(0); 509 } else if ( ! isprint((u_char)*p)) 510 if ( ! mdoc_pwarn(mdoc, line, pos, EPRINT)) 511 return(0); 512 513 if ('\\' != *p) 514 continue; 515 516 c = mandoc_special(p); 517 if (c) { 518 p += c - 1; 519 pos += c - 1; 520 continue; 521 } 522 if ( ! (MDOC_IGN_ESCAPE & mdoc->pflags)) 523 return(mdoc_perr(mdoc, line, pos, EESCAPE)); 524 if ( ! mdoc_pwarn(mdoc, line, pos, EESCAPE)) 525 return(0); 526 } 527 528 return(1); 529} 530 531 532 533 534static int 535check_parent(PRE_ARGS, enum mdoct tok, enum mdoc_type t) 536{ 537 538 assert(n->parent); 539 if ((MDOC_ROOT == t || tok == n->parent->tok) && 540 (t == n->parent->type)) 541 return(1); 542 543 return(mdoc_verr(mdoc, n->line, n->pos, "require parent %s", 544 MDOC_ROOT == t ? "<root>" : mdoc_macronames[tok])); 545} 546 547 548 549static int 550pre_display(PRE_ARGS) 551{ 552 struct mdoc_node *node; 553 554 /* Display elements (`Bd', `D1'...) cannot be nested. */ 555 556 if (MDOC_BLOCK != n->type) 557 return(1); 558 559 /* LINTED */ 560 for (node = mdoc->last->parent; node; node = node->parent) 561 if (MDOC_BLOCK == node->type) 562 if (MDOC_Bd == node->tok) 563 break; 564 if (NULL == node) 565 return(1); 566 567 return(mdoc_nerr(mdoc, n, ENESTDISP)); 568} 569 570 571static int 572pre_bl(PRE_ARGS) 573{ 574 int pos, type, width, offset; 575 576 if (MDOC_BLOCK != n->type) 577 return(1); 578 if (NULL == n->args) 579 return(mdoc_nerr(mdoc, n, ELISTTYPE)); 580 581 /* Make sure that only one type of list is specified. */ 582 583 type = offset = width = -1; 584 585 /* LINTED */ 586 for (pos = 0; pos < (int)n->args->argc; pos++) 587 switch (n->args->argv[pos].arg) { 588 case (MDOC_Bullet): 589 /* FALLTHROUGH */ 590 case (MDOC_Dash): 591 /* FALLTHROUGH */ 592 case (MDOC_Enum): 593 /* FALLTHROUGH */ 594 case (MDOC_Hyphen): 595 /* FALLTHROUGH */ 596 case (MDOC_Item): 597 /* FALLTHROUGH */ 598 case (MDOC_Tag): 599 /* FALLTHROUGH */ 600 case (MDOC_Diag): 601 /* FALLTHROUGH */ 602 case (MDOC_Hang): 603 /* FALLTHROUGH */ 604 case (MDOC_Ohang): 605 /* FALLTHROUGH */ 606 case (MDOC_Inset): 607 /* FALLTHROUGH */ 608 case (MDOC_Column): 609 /* 610 * Note that if a duplicate is detected, we 611 * remove the duplicate instead of passing it 612 * over. If we don't do this, mdoc_action will 613 * become confused when it scans over multiple 614 * types whilst setting its bitmasks. 615 * 616 * FIXME: this should occur in mdoc_action.c. 617 */ 618 if (type >= 0) { 619 if ( ! mdoc_nwarn(mdoc, n, EMULTILIST)) 620 return(0); 621 mdoc_argn_free(n->args, pos); 622 break; 623 } 624 type = n->args->argv[pos].arg; 625 break; 626 case (MDOC_Compact): 627 if (type < 0 && ! mdoc_nwarn(mdoc, n, ENOTYPE)) 628 return(0); 629 break; 630 case (MDOC_Width): 631 if (width >= 0) 632 return(mdoc_nerr(mdoc, n, EARGREP)); 633 if (type < 0 && ! mdoc_nwarn(mdoc, n, ENOTYPE)) 634 return(0); 635 width = n->args->argv[pos].arg; 636 break; 637 case (MDOC_Offset): 638 if (offset >= 0) 639 return(mdoc_nerr(mdoc, n, EARGREP)); 640 if (type < 0 && ! mdoc_nwarn(mdoc, n, ENOTYPE)) 641 return(0); 642 offset = n->args->argv[pos].arg; 643 break; 644 default: 645 break; 646 } 647 648 if (type < 0) 649 return(mdoc_nerr(mdoc, n, ELISTTYPE)); 650 651 /* 652 * Validate the width field. Some list types don't need width 653 * types and should be warned about them. Others should have it 654 * and must also be warned. 655 */ 656 657 switch (type) { 658 case (MDOC_Tag): 659 if (width < 0 && ! mdoc_nwarn(mdoc, n, EMISSWIDTH)) 660 return(0); 661 break; 662 case (MDOC_Column): 663 /* FALLTHROUGH */ 664 case (MDOC_Diag): 665 /* FALLTHROUGH */ 666 case (MDOC_Ohang): 667 /* FALLTHROUGH */ 668 case (MDOC_Inset): 669 /* FALLTHROUGH */ 670 case (MDOC_Item): 671 if (width >= 0 && ! mdoc_nwarn(mdoc, n, ENOWIDTH)) 672 return(0); 673 break; 674 default: 675 break; 676 } 677 678 return(1); 679} 680 681 682static int 683pre_bd(PRE_ARGS) 684{ 685 int i, type, err; 686 687 if (MDOC_BLOCK != n->type) 688 return(1); 689 if (NULL == n->args) 690 return(mdoc_nerr(mdoc, n, EDISPTYPE)); 691 692 /* Make sure that only one type of display is specified. */ 693 694 /* LINTED */ 695 for (i = 0, err = type = 0; ! err && 696 i < (int)n->args->argc; i++) 697 switch (n->args->argv[i].arg) { 698 case (MDOC_Centred): 699 /* FALLTHROUGH */ 700 case (MDOC_Ragged): 701 /* FALLTHROUGH */ 702 case (MDOC_Unfilled): 703 /* FALLTHROUGH */ 704 case (MDOC_Filled): 705 /* FALLTHROUGH */ 706 case (MDOC_Literal): 707 if (0 == type++) 708 break; 709 return(mdoc_nerr(mdoc, n, EMULTIDISP)); 710 default: 711 break; 712 } 713 714 if (type) 715 return(1); 716 return(mdoc_nerr(mdoc, n, EDISPTYPE)); 717} 718 719 720static int 721pre_ss(PRE_ARGS) 722{ 723 724 if (MDOC_BLOCK != n->type) 725 return(1); 726 return(check_parent(mdoc, n, MDOC_Sh, MDOC_BODY)); 727} 728 729 730static int 731pre_sh(PRE_ARGS) 732{ 733 734 if (MDOC_BLOCK != n->type) 735 return(1); 736 return(check_parent(mdoc, n, MDOC_MAX, MDOC_ROOT)); 737} 738 739 740static int 741pre_it(PRE_ARGS) 742{ 743 744 if (MDOC_BLOCK != n->type) 745 return(1); 746 return(check_parent(mdoc, n, MDOC_Bl, MDOC_BODY)); 747} 748 749 750static int 751pre_an(PRE_ARGS) 752{ 753 754 if (NULL == n->args || 1 == n->args->argc) 755 return(1); 756 return(mdoc_verr(mdoc, n->line, n->pos, 757 "only one argument allowed")); 758} 759 760 761static int 762pre_lb(PRE_ARGS) 763{ 764 765 return(check_sec(mdoc, n, SEC_LIBRARY, SEC_CUSTOM)); 766} 767 768 769static int 770pre_rv(PRE_ARGS) 771{ 772 773 return(check_stdarg(mdoc, n)); 774} 775 776 777static int 778pre_ex(PRE_ARGS) 779{ 780 781 if ( ! check_msec(mdoc, n, 1, 6, 8, 0)) 782 return(0); 783 return(check_stdarg(mdoc, n)); 784} 785 786 787static int 788pre_dt(PRE_ARGS) 789{ 790 791 /* FIXME: make sure is capitalised. */ 792 793 if (0 == mdoc->meta.date || mdoc->meta.os) 794 if ( ! mdoc_nwarn(mdoc, n, EPROLOOO)) 795 return(0); 796 if (mdoc->meta.title) 797 if ( ! mdoc_nwarn(mdoc, n, EPROLREP)) 798 return(0); 799 return(1); 800} 801 802 803static int 804pre_os(PRE_ARGS) 805{ 806 807 if (NULL == mdoc->meta.title || 0 == mdoc->meta.date) 808 if ( ! mdoc_nwarn(mdoc, n, EPROLOOO)) 809 return(0); 810 if (mdoc->meta.os) 811 if ( ! mdoc_nwarn(mdoc, n, EPROLREP)) 812 return(0); 813 return(1); 814} 815 816 817static int 818pre_dd(PRE_ARGS) 819{ 820 821 if (mdoc->meta.title || mdoc->meta.os) 822 if ( ! mdoc_nwarn(mdoc, n, EPROLOOO)) 823 return(0); 824 if (mdoc->meta.date) 825 if ( ! mdoc_nwarn(mdoc, n, EPROLREP)) 826 return(0); 827 return(1); 828} 829 830 831static int 832post_bf(POST_ARGS) 833{ 834 char *p; 835 struct mdoc_node *head; 836 837 if (MDOC_BLOCK != mdoc->last->type) 838 return(1); 839 840 head = mdoc->last->head; 841 842 if (mdoc->last->args && head->child) 843 return(mdoc_nerr(mdoc, mdoc->last, ELINE)); 844 else if (mdoc->last->args) 845 return(1); 846 847 if (NULL == head->child || MDOC_TEXT != head->child->type) 848 return(mdoc_nerr(mdoc, mdoc->last, ELINE)); 849 850 p = head->child->string; 851 852 if (0 == strcmp(p, "Em")) 853 return(1); 854 else if (0 == strcmp(p, "Li")) 855 return(1); 856 else if (0 == strcmp(p, "Sy")) 857 return(1); 858 859 return(mdoc_nerr(mdoc, head, EFONT)); 860} 861 862 863static int 864post_lb(POST_ARGS) 865{ 866 867 if (mdoc_a2lib(mdoc->last->child->string)) 868 return(1); 869 return(mdoc_nwarn(mdoc, mdoc->last, ELIB)); 870} 871 872 873static int 874post_vt(POST_ARGS) 875{ 876 const struct mdoc_node *n; 877 878 /* 879 * The Vt macro comes in both ELEM and BLOCK form, both of which 880 * have different syntaxes (yet more context-sensitive 881 * behaviour). ELEM types must have a child; BLOCK types, 882 * specifically the BODY, should only have TEXT children. 883 */ 884 885 if (MDOC_ELEM == mdoc->last->type) 886 return(eerr_ge1(mdoc)); 887 if (MDOC_BODY != mdoc->last->type) 888 return(1); 889 890 for (n = mdoc->last->child; n; n = n->next) 891 if (MDOC_TEXT != n->type && 892 (MDOC_ELEM != n->type || MDOC_eos != n->tok)) 893 if ( ! mdoc_nwarn(mdoc, n, EBADCHILD)) 894 return(0); 895 896 return(1); 897} 898 899 900static int 901post_nm(POST_ARGS) 902{ 903 904 if (mdoc->last->child) 905 return(1); 906 if (mdoc->meta.name) 907 return(1); 908 return(mdoc_nerr(mdoc, mdoc->last, ENAME)); 909} 910 911 912static int 913post_at(POST_ARGS) 914{ 915 916 if (NULL == mdoc->last->child) 917 return(1); 918 if (MDOC_TEXT != mdoc->last->child->type) 919 return(mdoc_nerr(mdoc, mdoc->last, EATT)); 920 if (mdoc_a2att(mdoc->last->child->string)) 921 return(1); 922 return(mdoc_nerr(mdoc, mdoc->last, EATT)); 923} 924 925 926static int 927post_an(POST_ARGS) 928{ 929 930 if (mdoc->last->args) { 931 if (NULL == mdoc->last->child) 932 return(1); 933 return(mdoc_nerr(mdoc, mdoc->last, ENOLINE)); 934 } 935 936 if (mdoc->last->child) 937 return(1); 938 return(mdoc_nerr(mdoc, mdoc->last, ELINE)); 939} 940 941 942static int 943post_it(POST_ARGS) 944{ 945 int type, i, cols; 946 struct mdoc_node *n, *c; 947 948 if (MDOC_BLOCK != mdoc->last->type) 949 return(1); 950 951 n = mdoc->last->parent->parent; 952 if (NULL == n->args) 953 return(mdoc_nerr(mdoc, mdoc->last, ELISTTYPE)); 954 955 /* Some types require block-head, some not. */ 956 957 /* LINTED */ 958 for (cols = type = -1, i = 0; -1 == type && 959 i < (int)n->args->argc; i++) 960 switch (n->args->argv[i].arg) { 961 case (MDOC_Tag): 962 /* FALLTHROUGH */ 963 case (MDOC_Diag): 964 /* FALLTHROUGH */ 965 case (MDOC_Hang): 966 /* FALLTHROUGH */ 967 case (MDOC_Ohang): 968 /* FALLTHROUGH */ 969 case (MDOC_Inset): 970 /* FALLTHROUGH */ 971 case (MDOC_Bullet): 972 /* FALLTHROUGH */ 973 case (MDOC_Dash): 974 /* FALLTHROUGH */ 975 case (MDOC_Enum): 976 /* FALLTHROUGH */ 977 case (MDOC_Hyphen): 978 /* FALLTHROUGH */ 979 case (MDOC_Item): 980 type = n->args->argv[i].arg; 981 break; 982 case (MDOC_Column): 983 type = n->args->argv[i].arg; 984 cols = (int)n->args->argv[i].sz; 985 break; 986 default: 987 break; 988 } 989 990 if (-1 == type) 991 return(mdoc_nerr(mdoc, mdoc->last, ELISTTYPE)); 992 993 switch (type) { 994 case (MDOC_Tag): 995 if (NULL == mdoc->last->head->child) 996 if ( ! mdoc_nwarn(mdoc, mdoc->last, ELINE)) 997 return(0); 998 break; 999 case (MDOC_Hang): 1000 /* FALLTHROUGH */ 1001 case (MDOC_Ohang): 1002 /* FALLTHROUGH */ 1003 case (MDOC_Inset): 1004 /* FALLTHROUGH */ 1005 case (MDOC_Diag): 1006 if (NULL == mdoc->last->head->child) 1007 if ( ! mdoc_nwarn(mdoc, mdoc->last, ELINE)) 1008 return(0); 1009 if (NULL == mdoc->last->body->child) 1010 if ( ! mdoc_nwarn(mdoc, mdoc->last, EMULTILINE)) 1011 return(0); 1012 break; 1013 case (MDOC_Bullet): 1014 /* FALLTHROUGH */ 1015 case (MDOC_Dash): 1016 /* FALLTHROUGH */ 1017 case (MDOC_Enum): 1018 /* FALLTHROUGH */ 1019 case (MDOC_Hyphen): 1020 /* FALLTHROUGH */ 1021 case (MDOC_Item): 1022 if (mdoc->last->head->child) 1023 if ( ! mdoc_nwarn(mdoc, mdoc->last, ENOLINE)) 1024 return(0); 1025 if (NULL == mdoc->last->body->child) 1026 if ( ! mdoc_nwarn(mdoc, mdoc->last, EMULTILINE)) 1027 return(0); 1028 break; 1029 case (MDOC_Column): 1030 if (NULL == mdoc->last->head->child) 1031 if ( ! mdoc_nwarn(mdoc, mdoc->last, ELINE)) 1032 return(0); 1033 if (mdoc->last->body->child) 1034 if ( ! mdoc_nwarn(mdoc, mdoc->last, ENOMULTILINE)) 1035 return(0); 1036 c = mdoc->last->child; 1037 for (i = 0; c && MDOC_HEAD == c->type; c = c->next) 1038 i++; 1039 1040 if (i < cols || i == (cols + 1)) { 1041 if ( ! mdoc_vwarn(mdoc, mdoc->last->line, 1042 mdoc->last->pos, "column " 1043 "mismatch: have %d, want %d", 1044 i, cols)) 1045 return(0); 1046 break; 1047 } else if (i == cols) 1048 break; 1049 1050 return(mdoc_verr(mdoc, mdoc->last->line, 1051 mdoc->last->pos, "column mismatch: " 1052 "have %d, want %d", i, cols)); 1053 default: 1054 break; 1055 } 1056 1057 return(1); 1058} 1059 1060 1061static int 1062post_bl_head(POST_ARGS) 1063{ 1064 int i; 1065 const struct mdoc_node *n; 1066 const struct mdoc_argv *a; 1067 1068 n = mdoc->last->parent; 1069 assert(n->args); 1070 1071 for (i = 0; i < (int)n->args->argc; i++) { 1072 a = &n->args->argv[i]; 1073 if (a->arg == MDOC_Column) { 1074 if (a->sz && mdoc->last->nchild) 1075 return(mdoc_nerr(mdoc, n, ECOLMIS)); 1076 return(1); 1077 } 1078 } 1079 1080 if (0 == (i = mdoc->last->nchild)) 1081 return(1); 1082 return(warn_count(mdoc, "==", 0, "line arguments", i)); 1083} 1084 1085 1086static int 1087post_bl(POST_ARGS) 1088{ 1089 struct mdoc_node *n; 1090 1091 if (MDOC_HEAD == mdoc->last->type) 1092 return(post_bl_head(mdoc)); 1093 if (MDOC_BODY != mdoc->last->type) 1094 return(1); 1095 if (NULL == mdoc->last->child) 1096 return(1); 1097 1098 /* 1099 * We only allow certain children of `Bl'. This is usually on 1100 * `It', but apparently `Sm' occurs here and there, so we let 1101 * that one through, too. 1102 */ 1103 1104 /* LINTED */ 1105 for (n = mdoc->last->child; n; n = n->next) { 1106 if (MDOC_BLOCK == n->type && MDOC_It == n->tok) 1107 continue; 1108 if (MDOC_Sm == n->tok) 1109 continue; 1110 return(mdoc_nerr(mdoc, n, EBADCHILD)); 1111 } 1112 1113 return(1); 1114} 1115 1116 1117static int 1118ebool(struct mdoc *mdoc) 1119{ 1120 struct mdoc_node *n; 1121 1122 /* LINTED */ 1123 for (n = mdoc->last->child; n; n = n->next) { 1124 if (MDOC_TEXT != n->type) 1125 break; 1126 if (0 == strcmp(n->string, "on")) 1127 continue; 1128 if (0 == strcmp(n->string, "off")) 1129 continue; 1130 break; 1131 } 1132 1133 if (NULL == n) 1134 return(1); 1135 return(mdoc_nerr(mdoc, n, EBOOL)); 1136} 1137 1138 1139static int 1140post_root(POST_ARGS) 1141{ 1142 1143 if (NULL == mdoc->first->child) 1144 return(mdoc_nerr(mdoc, mdoc->first, ENODAT)); 1145 if ( ! (MDOC_PBODY & mdoc->flags)) 1146 return(mdoc_nerr(mdoc, mdoc->first, ENOPROLOGUE)); 1147 1148 if (MDOC_BLOCK != mdoc->first->child->type) 1149 return(mdoc_nerr(mdoc, mdoc->first, ENODAT)); 1150 if (MDOC_Sh != mdoc->first->child->tok) 1151 return(mdoc_nerr(mdoc, mdoc->first, ENODAT)); 1152 1153 return(1); 1154} 1155 1156 1157static int 1158post_st(POST_ARGS) 1159{ 1160 1161 if (mdoc_a2st(mdoc->last->child->string)) 1162 return(1); 1163 return(mdoc_nerr(mdoc, mdoc->last, EBADSTAND)); 1164} 1165 1166 1167static int 1168post_rs(POST_ARGS) 1169{ 1170 struct mdoc_node *nn; 1171 1172 if (MDOC_BODY != mdoc->last->type) 1173 return(1); 1174 1175 for (nn = mdoc->last->child; nn; nn = nn->next) 1176 switch (nn->tok) { 1177 case(MDOC__U): 1178 /* FALLTHROUGH */ 1179 case(MDOC__Q): 1180 /* FALLTHROUGH */ 1181 case(MDOC__C): 1182 /* FALLTHROUGH */ 1183 case(MDOC__A): 1184 /* FALLTHROUGH */ 1185 case(MDOC__B): 1186 /* FALLTHROUGH */ 1187 case(MDOC__D): 1188 /* FALLTHROUGH */ 1189 case(MDOC__I): 1190 /* FALLTHROUGH */ 1191 case(MDOC__J): 1192 /* FALLTHROUGH */ 1193 case(MDOC__N): 1194 /* FALLTHROUGH */ 1195 case(MDOC__O): 1196 /* FALLTHROUGH */ 1197 case(MDOC__P): 1198 /* FALLTHROUGH */ 1199 case(MDOC__R): 1200 /* FALLTHROUGH */ 1201 case(MDOC__T): 1202 /* FALLTHROUGH */ 1203 case(MDOC__V): 1204 break; 1205 default: 1206 return(mdoc_nerr(mdoc, nn, EBADCHILD)); 1207 } 1208 1209 return(1); 1210} 1211 1212 1213static int 1214post_sh(POST_ARGS) 1215{ 1216 1217 if (MDOC_HEAD == mdoc->last->type) 1218 return(post_sh_head(mdoc)); 1219 if (MDOC_BODY == mdoc->last->type) 1220 return(post_sh_body(mdoc)); 1221 1222 return(1); 1223} 1224 1225 1226static int 1227post_sh_body(POST_ARGS) 1228{ 1229 struct mdoc_node *n; 1230 1231 if (SEC_NAME != mdoc->lastsec) 1232 return(1); 1233 1234 /* 1235 * Warn if the NAME section doesn't contain the `Nm' and `Nd' 1236 * macros (can have multiple `Nm' and one `Nd'). Note that the 1237 * children of the BODY declaration can also be "text". 1238 */ 1239 1240 if (NULL == (n = mdoc->last->child)) 1241 return(mdoc_nwarn(mdoc, mdoc->last, ENAMESECINC)); 1242 1243 for ( ; n && n->next; n = n->next) { 1244 if (MDOC_ELEM == n->type && MDOC_Nm == n->tok) 1245 continue; 1246 if (MDOC_TEXT == n->type) 1247 continue; 1248 if ( ! mdoc_nwarn(mdoc, mdoc->last, ENAMESECINC)) 1249 return(0); 1250 } 1251 1252 assert(n); 1253 if (MDOC_BLOCK == n->type && MDOC_Nd == n->tok) 1254 return(1); 1255 return(mdoc_nwarn(mdoc, mdoc->last, ENAMESECINC)); 1256} 1257 1258 1259static int 1260post_sh_head(POST_ARGS) 1261{ 1262 char buf[64]; 1263 enum mdoc_sec sec; 1264 const struct mdoc_node *n; 1265 1266 /* 1267 * Process a new section. Sections are either "named" or 1268 * "custom"; custom sections are user-defined, while named ones 1269 * usually follow a conventional order and may only appear in 1270 * certain manual sections. 1271 */ 1272 1273 buf[0] = 0; 1274 1275 for (n = mdoc->last->child; n; n = n->next) { 1276 /* XXX - copied from compact(). */ 1277 assert(MDOC_TEXT == n->type); 1278 1279 if (strlcat(buf, n->string, 64) >= 64) 1280 return(mdoc_nerr(mdoc, n, ETOOLONG)); 1281 if (NULL == n->next) 1282 continue; 1283 if (strlcat(buf, " ", 64) >= 64) 1284 return(mdoc_nerr(mdoc, n, ETOOLONG)); 1285 } 1286 1287 sec = mdoc_atosec(buf); 1288 1289 /* 1290 * Check: NAME should always be first, CUSTOM has no roles, 1291 * non-CUSTOM has a conventional order to be followed. 1292 */ 1293 1294 if (SEC_NAME != sec && SEC_NONE == mdoc->lastnamed && 1295 ! mdoc_nwarn(mdoc, mdoc->last, ESECNAME)) 1296 return(0); 1297 if (SEC_CUSTOM == sec) 1298 return(1); 1299 if (sec == mdoc->lastnamed) 1300 if ( ! mdoc_nwarn(mdoc, mdoc->last, ESECREP)) 1301 return(0); 1302 if (sec < mdoc->lastnamed) 1303 if ( ! mdoc_nwarn(mdoc, mdoc->last, ESECOOO)) 1304 return(0); 1305 1306 /* 1307 * Check particular section/manual conventions. LIBRARY can 1308 * only occur in msec 2, 3 (TODO: are there more of these?). 1309 */ 1310 1311 switch (sec) { 1312 case (SEC_LIBRARY): 1313 switch (mdoc->meta.msec) { 1314 case (2): 1315 /* FALLTHROUGH */ 1316 case (3): 1317 break; 1318 default: 1319 return(mdoc_nwarn(mdoc, mdoc->last, EWRONGMSEC)); 1320 } 1321 break; 1322 default: 1323 break; 1324 } 1325 1326 return(1); 1327} 1328 1329 1330static int 1331pre_fd(PRE_ARGS) 1332{ 1333 1334 return(check_sec(mdoc, n, SEC_SYNOPSIS, SEC_CUSTOM)); 1335} 1336