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