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