1 /* $Id: mdoc_validate.c,v 1.38 2009/10/27 21:40:07 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 eerr_le1(POST_ARGS); 74 static int ewarn_ge1(POST_ARGS); 75 static int herr_eq0(POST_ARGS); 76 static int herr_ge1(POST_ARGS); 77 static int hwarn_eq1(POST_ARGS); 78 static int hwarn_le1(POST_ARGS); 79 80 static int post_an(POST_ARGS); 81 static int post_at(POST_ARGS); 82 static int post_bf(POST_ARGS); 83 static int post_bl(POST_ARGS); 84 static int post_bl_head(POST_ARGS); 85 static int post_it(POST_ARGS); 86 static int post_lb(POST_ARGS); 87 static int post_nm(POST_ARGS); 88 static int post_root(POST_ARGS); 89 static int post_rs(POST_ARGS); 90 static int post_sh(POST_ARGS); 91 static int post_sh_body(POST_ARGS); 92 static int post_sh_head(POST_ARGS); 93 static int post_st(POST_ARGS); 94 static int pre_an(PRE_ARGS); 95 static int pre_bd(PRE_ARGS); 96 static int pre_bl(PRE_ARGS); 97 static int pre_cd(PRE_ARGS); 98 static int pre_dd(PRE_ARGS); 99 static int pre_display(PRE_ARGS); 100 static int pre_dt(PRE_ARGS); 101 static int pre_er(PRE_ARGS); 102 static int pre_ex(PRE_ARGS); 103 static int pre_fd(PRE_ARGS); 104 static int pre_it(PRE_ARGS); 105 static int pre_lb(PRE_ARGS); 106 static int pre_os(PRE_ARGS); 107 static int pre_rv(PRE_ARGS); 108 static int pre_sh(PRE_ARGS); 109 static int pre_ss(PRE_ARGS); 110 111 static v_post posts_an[] = { post_an, NULL }; 112 static v_post posts_at[] = { post_at, NULL }; 113 static v_post posts_bd[] = { herr_eq0, bwarn_ge1, NULL }; 114 static v_post posts_bf[] = { hwarn_le1, post_bf, NULL }; 115 static v_post posts_bl[] = { bwarn_ge1, post_bl, NULL }; 116 static v_post posts_bool[] = { eerr_eq1, ebool, NULL }; 117 static v_post posts_fo[] = { hwarn_eq1, bwarn_ge1, 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_rs[] = { berr_ge1, herr_eq0, post_rs, NULL }; 124 static v_post posts_sh[] = { herr_ge1, bwarn_ge1, post_sh, NULL }; 125 static v_post posts_sp[] = { eerr_le1, 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_text1[] = { eerr_eq1, NULL }; 130 static v_post posts_wline[] = { bwarn_ge1, herr_eq0, NULL }; 131 static v_post posts_wtext[] = { ewarn_ge1, NULL }; 132 static v_post posts_xr[] = { eerr_ge1, eerr_le2, NULL }; 133 static v_pre pres_an[] = { pre_an, NULL }; 134 static v_pre pres_bd[] = { pre_display, pre_bd, NULL }; 135 static v_pre pres_bl[] = { pre_bl, NULL }; 136 static v_pre pres_cd[] = { pre_cd, NULL }; 137 static v_pre pres_d1[] = { pre_display, NULL }; 138 static v_pre pres_dd[] = { pre_dd, NULL }; 139 static v_pre pres_dt[] = { pre_dt, NULL }; 140 static v_pre pres_er[] = { pre_er, NULL }; 141 static v_pre pres_ex[] = { pre_ex, NULL }; 142 static v_pre pres_fd[] = { pre_fd, NULL }; 143 static v_pre pres_it[] = { pre_it, NULL }; 144 static v_pre pres_lb[] = { pre_lb, NULL }; 145 static v_pre pres_os[] = { pre_os, NULL }; 146 static v_pre pres_rv[] = { pre_rv, NULL }; 147 static v_pre pres_sh[] = { pre_sh, NULL }; 148 static v_pre pres_ss[] = { pre_ss, NULL }; 149 150 const 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_text }, /* 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 */ 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 }; 273 274 275 int 276 mdoc_valid_pre(struct mdoc *mdoc, const struct mdoc_node *n) 277 { 278 v_pre *p; 279 int line, pos; 280 const char *tp; 281 282 if (MDOC_TEXT == n->type) { 283 tp = n->string; 284 line = n->line; 285 pos = n->pos; 286 return(check_text(mdoc, line, pos, tp)); 287 } 288 289 if ( ! check_args(mdoc, n)) 290 return(0); 291 if (NULL == mdoc_valids[n->tok].pre) 292 return(1); 293 for (p = mdoc_valids[n->tok].pre; *p; p++) 294 if ( ! (*p)(mdoc, n)) 295 return(0); 296 return(1); 297 } 298 299 300 int 301 mdoc_valid_post(struct mdoc *mdoc) 302 { 303 v_post *p; 304 305 if (MDOC_VALID & mdoc->last->flags) 306 return(1); 307 mdoc->last->flags |= MDOC_VALID; 308 309 if (MDOC_TEXT == mdoc->last->type) 310 return(1); 311 if (MDOC_ROOT == mdoc->last->type) 312 return(post_root(mdoc)); 313 314 if (NULL == mdoc_valids[mdoc->last->tok].post) 315 return(1); 316 for (p = mdoc_valids[mdoc->last->tok].post; *p; p++) 317 if ( ! (*p)(mdoc)) 318 return(0); 319 320 return(1); 321 } 322 323 324 static int 325 warn_print(struct mdoc *m, int ln, int pos) 326 { 327 328 if (MDOC_IGN_CHARS & m->pflags) 329 return(mdoc_pwarn(m, ln, pos, EPRINT)); 330 return(mdoc_perr(m, ln, pos, EPRINT)); 331 } 332 333 334 static inline int 335 warn_count(struct mdoc *m, const char *k, 336 int want, const char *v, int has) 337 { 338 339 return(mdoc_vwarn(m, m->last->line, m->last->pos, 340 "suggests %s %s %d (has %d)", v, k, want, has)); 341 } 342 343 344 static inline int 345 err_count(struct mdoc *m, const char *k, 346 int want, const char *v, int has) 347 { 348 349 return(mdoc_verr(m, m->last->line, m->last->pos, 350 "requires %s %s %d (has %d)", v, k, want, has)); 351 } 352 353 354 /* 355 * Build these up with macros because they're basically the same check 356 * for different inequalities. Yes, this could be done with functions, 357 * but this is reasonable for now. 358 */ 359 360 #define CHECK_CHILD_DEFN(lvl, name, ineq) \ 361 static int \ 362 lvl##_child_##name(struct mdoc *mdoc, const char *p, int sz) \ 363 { \ 364 if (mdoc->last->nchild ineq sz) \ 365 return(1); \ 366 return(lvl##_count(mdoc, #ineq, sz, p, mdoc->last->nchild)); \ 367 } 368 369 #define CHECK_BODY_DEFN(name, lvl, func, num) \ 370 static int \ 371 b##lvl##_##name(POST_ARGS) \ 372 { \ 373 if (MDOC_BODY != mdoc->last->type) \ 374 return(1); \ 375 return(func(mdoc, "multi-line arguments", (num))); \ 376 } 377 378 #define CHECK_ELEM_DEFN(name, lvl, func, num) \ 379 static int \ 380 e##lvl##_##name(POST_ARGS) \ 381 { \ 382 assert(MDOC_ELEM == mdoc->last->type); \ 383 return(func(mdoc, "line arguments", (num))); \ 384 } 385 386 #define CHECK_HEAD_DEFN(name, lvl, func, num) \ 387 static int \ 388 h##lvl##_##name(POST_ARGS) \ 389 { \ 390 if (MDOC_HEAD != mdoc->last->type) \ 391 return(1); \ 392 return(func(mdoc, "line arguments", (num))); \ 393 } 394 395 396 CHECK_CHILD_DEFN(warn, gt, >) /* warn_child_gt() */ 397 CHECK_CHILD_DEFN(err, gt, >) /* err_child_gt() */ 398 CHECK_CHILD_DEFN(warn, eq, ==) /* warn_child_eq() */ 399 CHECK_CHILD_DEFN(err, eq, ==) /* err_child_eq() */ 400 CHECK_CHILD_DEFN(err, lt, <) /* err_child_lt() */ 401 CHECK_CHILD_DEFN(warn, lt, <) /* warn_child_lt() */ 402 CHECK_BODY_DEFN(ge1, warn, warn_child_gt, 0) /* bwarn_ge1() */ 403 CHECK_BODY_DEFN(ge1, err, err_child_gt, 0) /* berr_ge1() */ 404 CHECK_ELEM_DEFN(ge1, warn, warn_child_gt, 0) /* ewarn_gt1() */ 405 CHECK_ELEM_DEFN(eq1, err, err_child_eq, 1) /* eerr_eq1() */ 406 CHECK_ELEM_DEFN(le2, err, err_child_lt, 3) /* eerr_le2() */ 407 CHECK_ELEM_DEFN(le1, err, err_child_lt, 2) /* eerr_le1() */ 408 CHECK_ELEM_DEFN(eq0, err, err_child_eq, 0) /* eerr_eq0() */ 409 CHECK_ELEM_DEFN(ge1, err, err_child_gt, 0) /* eerr_ge1() */ 410 CHECK_HEAD_DEFN(eq0, err, err_child_eq, 0) /* herr_eq0() */ 411 CHECK_HEAD_DEFN(le1, warn, warn_child_lt, 2) /* hwarn_le1() */ 412 CHECK_HEAD_DEFN(ge1, err, err_child_gt, 0) /* herr_ge1() */ 413 CHECK_HEAD_DEFN(eq1, warn, warn_child_eq, 1) /* hwarn_eq1() */ 414 415 416 static int 417 check_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 427 static int 428 check_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 451 static int 452 check_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 473 static int 474 check_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 490 static int 491 check_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 511 static int 512 check_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 546 static int 547 check_parent(PRE_ARGS, int 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 561 static int 562 pre_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 583 static int 584 pre_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_Inset): 666 /* FALLTHROUGH */ 667 case (MDOC_Item): 668 if (width >= 0 && ! mdoc_nwarn(mdoc, n, ENOWIDTH)) 669 return(0); 670 break; 671 default: 672 break; 673 } 674 675 return(1); 676 } 677 678 679 static int 680 pre_bd(PRE_ARGS) 681 { 682 int i, type, err; 683 684 if (MDOC_BLOCK != n->type) 685 return(1); 686 if (NULL == n->args) 687 return(mdoc_nerr(mdoc, n, EDISPTYPE)); 688 689 /* Make sure that only one type of display is specified. */ 690 691 /* LINTED */ 692 for (i = 0, err = type = 0; ! err && 693 i < (int)n->args->argc; i++) 694 switch (n->args->argv[i].arg) { 695 case (MDOC_Centred): 696 /* FALLTHROUGH */ 697 case (MDOC_Ragged): 698 /* FALLTHROUGH */ 699 case (MDOC_Unfilled): 700 /* FALLTHROUGH */ 701 case (MDOC_Filled): 702 /* FALLTHROUGH */ 703 case (MDOC_Literal): 704 if (0 == type++) 705 break; 706 return(mdoc_nerr(mdoc, n, EMULTIDISP)); 707 default: 708 break; 709 } 710 711 if (type) 712 return(1); 713 return(mdoc_nerr(mdoc, n, EDISPTYPE)); 714 } 715 716 717 static int 718 pre_ss(PRE_ARGS) 719 { 720 721 if (MDOC_BLOCK != n->type) 722 return(1); 723 return(check_parent(mdoc, n, MDOC_Sh, MDOC_BODY)); 724 } 725 726 727 static int 728 pre_sh(PRE_ARGS) 729 { 730 731 if (MDOC_BLOCK != n->type) 732 return(1); 733 return(check_parent(mdoc, n, -1, MDOC_ROOT)); 734 } 735 736 737 static int 738 pre_it(PRE_ARGS) 739 { 740 741 if (MDOC_BLOCK != n->type) 742 return(1); 743 return(check_parent(mdoc, n, MDOC_Bl, MDOC_BODY)); 744 } 745 746 747 static int 748 pre_an(PRE_ARGS) 749 { 750 751 if (NULL == n->args || 1 == n->args->argc) 752 return(1); 753 return(mdoc_verr(mdoc, n->line, n->pos, 754 "only one argument allowed")); 755 } 756 757 758 static int 759 pre_lb(PRE_ARGS) 760 { 761 762 return(check_sec(mdoc, n, SEC_LIBRARY, SEC_CUSTOM)); 763 } 764 765 766 static int 767 pre_rv(PRE_ARGS) 768 { 769 770 if ( ! check_msec(mdoc, n, 2, 3, 0)) 771 return(0); 772 return(check_stdarg(mdoc, n)); 773 } 774 775 776 static int 777 pre_ex(PRE_ARGS) 778 { 779 780 if ( ! check_msec(mdoc, n, 1, 6, 8, 0)) 781 return(0); 782 return(check_stdarg(mdoc, n)); 783 } 784 785 786 static int 787 pre_er(PRE_ARGS) 788 { 789 790 return(check_msec(mdoc, n, 2, 3, 9, 0)); 791 } 792 793 794 static int 795 pre_cd(PRE_ARGS) 796 { 797 798 return(check_msec(mdoc, n, 4, 0)); 799 } 800 801 802 static int 803 pre_dt(PRE_ARGS) 804 { 805 806 if (0 == mdoc->meta.date || mdoc->meta.os) 807 if ( ! mdoc_nwarn(mdoc, n, EPROLOOO)) 808 return(0); 809 if (mdoc->meta.title) 810 if ( ! mdoc_nwarn(mdoc, n, EPROLREP)) 811 return(0); 812 return(1); 813 } 814 815 816 static int 817 pre_os(PRE_ARGS) 818 { 819 820 if (NULL == mdoc->meta.title || 0 == mdoc->meta.date) 821 if ( ! mdoc_nwarn(mdoc, n, EPROLOOO)) 822 return(0); 823 if (mdoc->meta.os) 824 if ( ! mdoc_nwarn(mdoc, n, EPROLREP)) 825 return(0); 826 return(1); 827 } 828 829 830 static int 831 pre_dd(PRE_ARGS) 832 { 833 834 if (mdoc->meta.title || mdoc->meta.os) 835 if ( ! mdoc_nwarn(mdoc, n, EPROLOOO)) 836 return(0); 837 if (mdoc->meta.date) 838 if ( ! mdoc_nwarn(mdoc, n, EPROLREP)) 839 return(0); 840 return(1); 841 } 842 843 844 static int 845 post_bf(POST_ARGS) 846 { 847 char *p; 848 struct mdoc_node *head; 849 850 if (MDOC_BLOCK != mdoc->last->type) 851 return(1); 852 853 head = mdoc->last->head; 854 855 if (mdoc->last->args && head->child) 856 return(mdoc_nerr(mdoc, mdoc->last, ELINE)); 857 else if (mdoc->last->args) 858 return(1); 859 860 if (NULL == head->child || MDOC_TEXT != head->child->type) 861 return(mdoc_nerr(mdoc, mdoc->last, ELINE)); 862 863 p = head->child->string; 864 865 if (0 == strcmp(p, "Em")) 866 return(1); 867 else if (0 == strcmp(p, "Li")) 868 return(1); 869 else if (0 == strcmp(p, "Sy")) 870 return(1); 871 872 return(mdoc_nerr(mdoc, head, EFONT)); 873 } 874 875 876 static int 877 post_lb(POST_ARGS) 878 { 879 880 if (mdoc_a2lib(mdoc->last->child->string)) 881 return(1); 882 return(mdoc_nwarn(mdoc, mdoc->last, ELIB)); 883 } 884 885 886 static int 887 post_nm(POST_ARGS) 888 { 889 890 if (mdoc->last->child) 891 return(1); 892 if (mdoc->meta.name) 893 return(1); 894 return(mdoc_nerr(mdoc, mdoc->last, ENAME)); 895 } 896 897 898 static int 899 post_at(POST_ARGS) 900 { 901 902 if (NULL == mdoc->last->child) 903 return(1); 904 if (MDOC_TEXT != mdoc->last->child->type) 905 return(mdoc_nerr(mdoc, mdoc->last, EATT)); 906 if (mdoc_a2att(mdoc->last->child->string)) 907 return(1); 908 return(mdoc_nerr(mdoc, mdoc->last, EATT)); 909 } 910 911 912 static int 913 post_an(POST_ARGS) 914 { 915 916 if (mdoc->last->args) { 917 if (NULL == mdoc->last->child) 918 return(1); 919 return(mdoc_nerr(mdoc, mdoc->last, ENOLINE)); 920 } 921 922 if (mdoc->last->child) 923 return(1); 924 return(mdoc_nerr(mdoc, mdoc->last, ELINE)); 925 } 926 927 928 static int 929 post_it(POST_ARGS) 930 { 931 int type, i, cols; 932 struct mdoc_node *n, *c; 933 934 if (MDOC_BLOCK != mdoc->last->type) 935 return(1); 936 937 n = mdoc->last->parent->parent; 938 if (NULL == n->args) 939 return(mdoc_nerr(mdoc, mdoc->last, ELISTTYPE)); 940 941 /* Some types require block-head, some not. */ 942 943 /* LINTED */ 944 for (cols = type = -1, i = 0; -1 == type && 945 i < (int)n->args->argc; i++) 946 switch (n->args->argv[i].arg) { 947 case (MDOC_Tag): 948 /* FALLTHROUGH */ 949 case (MDOC_Diag): 950 /* FALLTHROUGH */ 951 case (MDOC_Hang): 952 /* FALLTHROUGH */ 953 case (MDOC_Ohang): 954 /* FALLTHROUGH */ 955 case (MDOC_Inset): 956 /* FALLTHROUGH */ 957 case (MDOC_Bullet): 958 /* FALLTHROUGH */ 959 case (MDOC_Dash): 960 /* FALLTHROUGH */ 961 case (MDOC_Enum): 962 /* FALLTHROUGH */ 963 case (MDOC_Hyphen): 964 /* FALLTHROUGH */ 965 case (MDOC_Item): 966 type = n->args->argv[i].arg; 967 break; 968 case (MDOC_Column): 969 type = n->args->argv[i].arg; 970 cols = (int)n->args->argv[i].sz; 971 break; 972 default: 973 break; 974 } 975 976 if (-1 == type) 977 return(mdoc_nerr(mdoc, mdoc->last, ELISTTYPE)); 978 979 switch (type) { 980 case (MDOC_Tag): 981 if (NULL == mdoc->last->head->child) 982 if ( ! mdoc_nwarn(mdoc, mdoc->last, ELINE)) 983 return(0); 984 break; 985 case (MDOC_Hang): 986 /* FALLTHROUGH */ 987 case (MDOC_Ohang): 988 /* FALLTHROUGH */ 989 case (MDOC_Inset): 990 /* FALLTHROUGH */ 991 case (MDOC_Diag): 992 if (NULL == mdoc->last->head->child) 993 if ( ! mdoc_nwarn(mdoc, mdoc->last, ELINE)) 994 return(0); 995 if (NULL == mdoc->last->body->child) 996 if ( ! mdoc_nwarn(mdoc, mdoc->last, EMULTILINE)) 997 return(0); 998 break; 999 case (MDOC_Bullet): 1000 /* FALLTHROUGH */ 1001 case (MDOC_Dash): 1002 /* FALLTHROUGH */ 1003 case (MDOC_Enum): 1004 /* FALLTHROUGH */ 1005 case (MDOC_Hyphen): 1006 /* FALLTHROUGH */ 1007 case (MDOC_Item): 1008 if (mdoc->last->head->child) 1009 if ( ! mdoc_nwarn(mdoc, mdoc->last, ENOLINE)) 1010 return(0); 1011 if (NULL == mdoc->last->body->child) 1012 if ( ! mdoc_nwarn(mdoc, mdoc->last, EMULTILINE)) 1013 return(0); 1014 break; 1015 case (MDOC_Column): 1016 if (NULL == mdoc->last->head->child) 1017 if ( ! mdoc_nwarn(mdoc, mdoc->last, ELINE)) 1018 return(0); 1019 if (mdoc->last->body->child) 1020 if ( ! mdoc_nwarn(mdoc, mdoc->last, ENOMULTILINE)) 1021 return(0); 1022 c = mdoc->last->child; 1023 for (i = 0; c && MDOC_HEAD == c->type; c = c->next) 1024 i++; 1025 1026 if (i < cols || i == (cols + 1)) { 1027 if ( ! mdoc_vwarn(mdoc, mdoc->last->line, 1028 mdoc->last->pos, "column " 1029 "mismatch: have %d, want %d", 1030 i, cols)) 1031 return(0); 1032 break; 1033 } else if (i == cols) 1034 break; 1035 1036 return(mdoc_verr(mdoc, mdoc->last->line, 1037 mdoc->last->pos, "column mismatch: " 1038 "have %d, want %d", i, cols)); 1039 default: 1040 break; 1041 } 1042 1043 return(1); 1044 } 1045 1046 1047 static int 1048 post_bl_head(POST_ARGS) 1049 { 1050 int i; 1051 const struct mdoc_node *n; 1052 1053 n = mdoc->last->parent; 1054 assert(n->args); 1055 1056 for (i = 0; i < (int)n->args->argc; i++) 1057 if (n->args->argv[i].arg == MDOC_Column) 1058 break; 1059 1060 if (i == (int)n->args->argc) 1061 return(1); 1062 1063 if (n->args->argv[i].sz && mdoc->last->child) 1064 return(mdoc_nerr(mdoc, n, ECOLMIS)); 1065 1066 return(1); 1067 } 1068 1069 1070 static int 1071 post_bl(POST_ARGS) 1072 { 1073 struct mdoc_node *n; 1074 1075 if (MDOC_HEAD == mdoc->last->type) 1076 return(post_bl_head(mdoc)); 1077 if (MDOC_BODY != mdoc->last->type) 1078 return(1); 1079 if (NULL == mdoc->last->child) 1080 return(1); 1081 1082 /* LINTED */ 1083 for (n = mdoc->last->child; n; n = n->next) { 1084 if (MDOC_BLOCK == n->type) 1085 if (MDOC_It == n->tok) 1086 continue; 1087 return(mdoc_nerr(mdoc, n, EBADCHILD)); 1088 } 1089 1090 return(1); 1091 } 1092 1093 1094 static int 1095 ebool(struct mdoc *mdoc) 1096 { 1097 struct mdoc_node *n; 1098 1099 /* LINTED */ 1100 for (n = mdoc->last->child; n; n = n->next) { 1101 if (MDOC_TEXT != n->type) 1102 break; 1103 if (0 == strcmp(n->string, "on")) 1104 continue; 1105 if (0 == strcmp(n->string, "off")) 1106 continue; 1107 break; 1108 } 1109 1110 if (NULL == n) 1111 return(1); 1112 return(mdoc_nerr(mdoc, n, EBOOL)); 1113 } 1114 1115 1116 static int 1117 post_root(POST_ARGS) 1118 { 1119 1120 if (NULL == mdoc->first->child) 1121 return(mdoc_nerr(mdoc, mdoc->first, ENODAT)); 1122 if ( ! (MDOC_PBODY & mdoc->flags)) 1123 return(mdoc_nerr(mdoc, mdoc->first, ENOPROLOGUE)); 1124 1125 if (MDOC_BLOCK != mdoc->first->child->type) 1126 return(mdoc_nerr(mdoc, mdoc->first, ENODAT)); 1127 if (MDOC_Sh != mdoc->first->child->tok) 1128 return(mdoc_nerr(mdoc, mdoc->first, ENODAT)); 1129 1130 return(1); 1131 } 1132 1133 1134 static int 1135 post_st(POST_ARGS) 1136 { 1137 1138 if (mdoc_a2st(mdoc->last->child->string)) 1139 return(1); 1140 return(mdoc_nerr(mdoc, mdoc->last, EBADSTAND)); 1141 } 1142 1143 1144 static int 1145 post_rs(POST_ARGS) 1146 { 1147 struct mdoc_node *nn; 1148 1149 if (MDOC_BODY != mdoc->last->type) 1150 return(1); 1151 1152 for (nn = mdoc->last->child; nn; nn = nn->next) 1153 switch (nn->tok) { 1154 case(MDOC__U): 1155 /* FALLTHROUGH */ 1156 case(MDOC__Q): 1157 /* FALLTHROUGH */ 1158 case(MDOC__C): 1159 /* FALLTHROUGH */ 1160 case(MDOC__A): 1161 /* FALLTHROUGH */ 1162 case(MDOC__B): 1163 /* FALLTHROUGH */ 1164 case(MDOC__D): 1165 /* FALLTHROUGH */ 1166 case(MDOC__I): 1167 /* FALLTHROUGH */ 1168 case(MDOC__J): 1169 /* FALLTHROUGH */ 1170 case(MDOC__N): 1171 /* FALLTHROUGH */ 1172 case(MDOC__O): 1173 /* FALLTHROUGH */ 1174 case(MDOC__P): 1175 /* FALLTHROUGH */ 1176 case(MDOC__R): 1177 /* FALLTHROUGH */ 1178 case(MDOC__T): 1179 /* FALLTHROUGH */ 1180 case(MDOC__V): 1181 break; 1182 default: 1183 return(mdoc_nerr(mdoc, nn, EBADCHILD)); 1184 } 1185 1186 return(1); 1187 } 1188 1189 1190 static int 1191 post_sh(POST_ARGS) 1192 { 1193 1194 if (MDOC_HEAD == mdoc->last->type) 1195 return(post_sh_head(mdoc)); 1196 if (MDOC_BODY == mdoc->last->type) 1197 return(post_sh_body(mdoc)); 1198 1199 return(1); 1200 } 1201 1202 1203 static int 1204 post_sh_body(POST_ARGS) 1205 { 1206 struct mdoc_node *n; 1207 1208 if (SEC_NAME != mdoc->lastsec) 1209 return(1); 1210 1211 /* 1212 * Warn if the NAME section doesn't contain the `Nm' and `Nd' 1213 * macros (can have multiple `Nm' and one `Nd'). Note that the 1214 * children of the BODY declaration can also be "text". 1215 */ 1216 1217 if (NULL == (n = mdoc->last->child)) 1218 return(mdoc_nwarn(mdoc, mdoc->last, ENAMESECINC)); 1219 1220 for ( ; n && n->next; n = n->next) { 1221 if (MDOC_ELEM == n->type && MDOC_Nm == n->tok) 1222 continue; 1223 if (MDOC_TEXT == n->type) 1224 continue; 1225 if ( ! mdoc_nwarn(mdoc, mdoc->last, ENAMESECINC)) 1226 return(0); 1227 } 1228 1229 assert(n); 1230 if (MDOC_BLOCK == n->type && MDOC_Nd == n->tok) 1231 return(1); 1232 return(mdoc_nwarn(mdoc, mdoc->last, ENAMESECINC)); 1233 } 1234 1235 1236 static int 1237 post_sh_head(POST_ARGS) 1238 { 1239 char buf[64]; 1240 enum mdoc_sec sec; 1241 const struct mdoc_node *n; 1242 1243 /* 1244 * Process a new section. Sections are either "named" or 1245 * "custom"; custom sections are user-defined, while named ones 1246 * usually follow a conventional order and may only appear in 1247 * certain manual sections. 1248 */ 1249 1250 buf[0] = 0; 1251 1252 for (n = mdoc->last->child; n; n = n->next) { 1253 /* XXX - copied from compact(). */ 1254 assert(MDOC_TEXT == n->type); 1255 1256 if (strlcat(buf, n->string, 64) >= 64) 1257 return(mdoc_nerr(mdoc, n, ETOOLONG)); 1258 if (NULL == n->next) 1259 continue; 1260 if (strlcat(buf, " ", 64) >= 64) 1261 return(mdoc_nerr(mdoc, n, ETOOLONG)); 1262 } 1263 1264 sec = mdoc_atosec(buf); 1265 1266 /* 1267 * Check: NAME should always be first, CUSTOM has no roles, 1268 * non-CUSTOM has a conventional order to be followed. 1269 */ 1270 1271 if (SEC_NAME != sec && SEC_NONE == mdoc->lastnamed) 1272 return(mdoc_nerr(mdoc, mdoc->last, ESECNAME)); 1273 if (SEC_CUSTOM == sec) 1274 return(1); 1275 if (sec == mdoc->lastnamed) 1276 if ( ! mdoc_nwarn(mdoc, mdoc->last, ESECREP)) 1277 return(0); 1278 if (sec < mdoc->lastnamed) 1279 if ( ! mdoc_nwarn(mdoc, mdoc->last, ESECOOO)) 1280 return(0); 1281 1282 /* 1283 * Check particular section/manual conventions. LIBRARY can 1284 * only occur in msec 2, 3 (TODO: are there more of these?). 1285 */ 1286 1287 switch (sec) { 1288 case (SEC_LIBRARY): 1289 switch (mdoc->meta.msec) { 1290 case (2): 1291 /* FALLTHROUGH */ 1292 case (3): 1293 break; 1294 default: 1295 return(mdoc_nwarn(mdoc, mdoc->last, EWRONGMSEC)); 1296 } 1297 break; 1298 default: 1299 break; 1300 } 1301 1302 return(1); 1303 } 1304 1305 1306 static int 1307 pre_fd(PRE_ARGS) 1308 { 1309 1310 return(check_sec(mdoc, n, SEC_SYNOPSIS, SEC_CUSTOM)); 1311 } 1312