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