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