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