mdoc_validate.c revision 1.74
1/* $Id: mdoc_validate.c,v 1.74 2010/10/24 18:15:43 schwarze Exp $ */ 2/* 3 * Copyright (c) 2008, 2009, 2010 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#include <sys/types.h> 18 19#include <assert.h> 20#include <ctype.h> 21#include <limits.h> 22#include <stdio.h> 23#include <stdlib.h> 24#include <string.h> 25 26#include "mandoc.h" 27#include "libmdoc.h" 28#include "libmandoc.h" 29 30/* FIXME: .Bl -diag can't have non-text children in HEAD. */ 31 32#define PRE_ARGS struct mdoc *mdoc, struct mdoc_node *n 33#define POST_ARGS struct mdoc *mdoc 34 35enum check_ineq { 36 CHECK_LT, 37 CHECK_GT, 38 CHECK_EQ 39}; 40 41enum check_lvl { 42 CHECK_WARN, 43 CHECK_ERROR, 44 CHECK_FATAL 45}; 46 47typedef int (*v_pre)(PRE_ARGS); 48typedef int (*v_post)(POST_ARGS); 49 50struct valids { 51 v_pre *pre; 52 v_post *post; 53}; 54 55static int check_count(struct mdoc *, enum mdoc_type, 56 enum check_lvl, enum check_ineq, int); 57static int check_parent(PRE_ARGS, enum mdoct, enum mdoc_type); 58static int check_stdarg(PRE_ARGS); 59static int check_text(struct mdoc *, int, int, char *); 60static int check_argv(struct mdoc *, 61 struct mdoc_node *, struct mdoc_argv *); 62static int check_args(struct mdoc *, struct mdoc_node *); 63 64static int ebool(POST_ARGS); 65static int berr_ge1(POST_ARGS); 66static int bwarn_ge1(POST_ARGS); 67static int eerr_eq0(POST_ARGS); 68static int eerr_eq1(POST_ARGS); 69static int eerr_ge1(POST_ARGS); 70static int eerr_le1(POST_ARGS); 71static int ewarn_eq0(POST_ARGS); 72static int ewarn_ge1(POST_ARGS); 73static int herr_eq0(POST_ARGS); 74static int herr_ge1(POST_ARGS); 75static int hwarn_eq0(POST_ARGS); 76static int hwarn_eq1(POST_ARGS); 77static int hwarn_le1(POST_ARGS); 78 79static int post_an(POST_ARGS); 80static int post_at(POST_ARGS); 81static int post_bf(POST_ARGS); 82static int post_bl(POST_ARGS); 83static int post_bl_head(POST_ARGS); 84static int post_dt(POST_ARGS); 85static int post_it(POST_ARGS); 86static int post_lb(POST_ARGS); 87static int post_nm(POST_ARGS); 88static int post_root(POST_ARGS); 89static int post_rs(POST_ARGS); 90static int post_sh(POST_ARGS); 91static int post_sh_body(POST_ARGS); 92static int post_sh_head(POST_ARGS); 93static int post_st(POST_ARGS); 94static int post_eoln(POST_ARGS); 95static int post_vt(POST_ARGS); 96static int pre_an(PRE_ARGS); 97static int pre_bd(PRE_ARGS); 98static int pre_bl(PRE_ARGS); 99static int pre_dd(PRE_ARGS); 100static int pre_display(PRE_ARGS); 101static int pre_dt(PRE_ARGS); 102static int pre_it(PRE_ARGS); 103static int pre_os(PRE_ARGS); 104static int pre_pp(PRE_ARGS); 105static int pre_rv(PRE_ARGS); 106static int pre_sh(PRE_ARGS); 107static int pre_ss(PRE_ARGS); 108 109static v_post posts_an[] = { post_an, NULL }; 110static v_post posts_at[] = { post_at, NULL }; 111static v_post posts_bd_bk[] = { hwarn_eq0, bwarn_ge1, NULL }; 112static v_post posts_bf[] = { hwarn_le1, post_bf, NULL }; 113static v_post posts_bl[] = { bwarn_ge1, post_bl, NULL }; 114static v_post posts_bool[] = { eerr_eq1, ebool, NULL }; 115static v_post posts_eoln[] = { post_eoln, NULL }; 116static v_post posts_dt[] = { post_dt, NULL }; 117static v_post posts_fo[] = { hwarn_eq1, bwarn_ge1, NULL }; 118static v_post posts_it[] = { post_it, NULL }; 119static v_post posts_lb[] = { eerr_eq1, post_lb, NULL }; 120static v_post posts_nd[] = { berr_ge1, NULL }; 121static v_post posts_nm[] = { post_nm, NULL }; 122static v_post posts_notext[] = { ewarn_eq0, NULL }; 123static v_post posts_rs[] = { berr_ge1, herr_eq0, post_rs, NULL }; 124static v_post posts_sh[] = { herr_ge1, bwarn_ge1, post_sh, NULL }; 125static v_post posts_sp[] = { eerr_le1, NULL }; 126static v_post posts_ss[] = { herr_ge1, NULL }; 127static v_post posts_st[] = { eerr_eq1, post_st, NULL }; 128static v_post posts_text[] = { eerr_ge1, NULL }; 129static v_post posts_text1[] = { eerr_eq1, NULL }; 130static v_post posts_vt[] = { post_vt, NULL }; 131static v_post posts_wline[] = { bwarn_ge1, herr_eq0, NULL }; 132static v_post posts_wtext[] = { ewarn_ge1, NULL }; 133static v_pre pres_an[] = { pre_an, NULL }; 134static v_pre pres_bd[] = { pre_display, pre_bd, pre_pp, NULL }; 135static v_pre pres_bl[] = { pre_bl, pre_pp, NULL }; 136static v_pre pres_d1[] = { pre_display, NULL }; 137static v_pre pres_dd[] = { pre_dd, NULL }; 138static v_pre pres_dt[] = { pre_dt, NULL }; 139static v_pre pres_er[] = { NULL, NULL }; 140static v_pre pres_ex[] = { NULL, NULL }; 141static v_pre pres_fd[] = { NULL, NULL }; 142static v_pre pres_it[] = { pre_it, NULL }; 143static v_pre pres_os[] = { pre_os, NULL }; 144static v_pre pres_pp[] = { pre_pp, NULL }; 145static v_pre pres_rv[] = { pre_rv, NULL }; 146static v_pre pres_sh[] = { pre_sh, NULL }; 147static v_pre pres_ss[] = { pre_ss, NULL }; 148 149const struct valids mdoc_valids[MDOC_MAX] = { 150 { NULL, NULL }, /* Ap */ 151 { pres_dd, posts_wtext }, /* 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 { pres_pp, posts_notext }, /* Pp */ 157 { pres_d1, posts_wline }, /* D1 */ 158 { pres_d1, posts_wline }, /* Dl */ 159 { pres_bd, posts_bd_bk }, /* 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_bd_bk }, /* 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 { pres_pp, posts_sp }, /* sp */ 270 { NULL, posts_text1 }, /* %U */ 271 { NULL, NULL }, /* Ta */ 272 { NULL, NULL }, /* TS */ 273 { NULL, NULL }, /* TE */ 274}; 275 276 277int 278mdoc_valid_pre(struct mdoc *mdoc, struct mdoc_node *n) 279{ 280 v_pre *p; 281 int line, pos; 282 char *tp; 283 284 if (MDOC_TEXT == n->type) { 285 tp = n->string; 286 line = n->line; 287 pos = n->pos; 288 return(check_text(mdoc, line, pos, tp)); 289 } 290 291 if ( ! check_args(mdoc, n)) 292 return(0); 293 if (NULL == mdoc_valids[n->tok].pre) 294 return(1); 295 for (p = mdoc_valids[n->tok].pre; *p; p++) 296 if ( ! (*p)(mdoc, n)) 297 return(0); 298 return(1); 299} 300 301 302int 303mdoc_valid_post(struct mdoc *mdoc) 304{ 305 v_post *p; 306 307 if (MDOC_VALID & mdoc->last->flags) 308 return(1); 309 mdoc->last->flags |= MDOC_VALID; 310 311 if (MDOC_TEXT == mdoc->last->type) 312 return(1); 313 if (MDOC_ROOT == mdoc->last->type) 314 return(post_root(mdoc)); 315 316 if (NULL == mdoc_valids[mdoc->last->tok].post) 317 return(1); 318 for (p = mdoc_valids[mdoc->last->tok].post; *p; p++) 319 if ( ! (*p)(mdoc)) 320 return(0); 321 322 return(1); 323} 324 325static int 326check_count(struct mdoc *m, enum mdoc_type type, 327 enum check_lvl lvl, enum check_ineq ineq, int val) 328{ 329 const char *p; 330 331 if (m->last->type != type) 332 return(1); 333 334 switch (ineq) { 335 case (CHECK_LT): 336 p = "less than "; 337 if (m->last->nchild < val) 338 return(1); 339 break; 340 case (CHECK_GT): 341 p = "greater than "; 342 if (m->last->nchild > val) 343 return(1); 344 break; 345 case (CHECK_EQ): 346 p = ""; 347 if (val == m->last->nchild) 348 return(1); 349 break; 350 } 351 352 if (CHECK_WARN == lvl) { 353 return(mdoc_vmsg(m, MANDOCERR_ARGCOUNT, 354 m->last->line, m->last->pos, 355 "want %s%d children (have %d)", 356 p, val, m->last->nchild)); 357 } 358 359 return(mdoc_vmsg(m, MANDOCERR_ARGCOUNT, 360 m->last->line, m->last->pos, 361 "require %s%d children (have %d)", 362 p, val, m->last->nchild)); 363} 364 365static int 366berr_ge1(POST_ARGS) 367{ 368 369 return(check_count(mdoc, MDOC_BODY, CHECK_FATAL, CHECK_GT, 0)); 370} 371 372static int 373bwarn_ge1(POST_ARGS) 374{ 375 return(check_count(mdoc, MDOC_BODY, CHECK_WARN, CHECK_GT, 0)); 376} 377 378static int 379eerr_eq0(POST_ARGS) 380{ 381 return(check_count(mdoc, MDOC_ELEM, CHECK_FATAL, CHECK_EQ, 0)); 382} 383 384static int 385eerr_eq1(POST_ARGS) 386{ 387 return(check_count(mdoc, MDOC_ELEM, CHECK_FATAL, CHECK_EQ, 1)); 388} 389 390static int 391eerr_ge1(POST_ARGS) 392{ 393 return(check_count(mdoc, MDOC_ELEM, CHECK_FATAL, CHECK_GT, 0)); 394} 395 396static int 397eerr_le1(POST_ARGS) 398{ 399 return(check_count(mdoc, MDOC_ELEM, CHECK_FATAL, CHECK_LT, 2)); 400} 401 402static int 403ewarn_eq0(POST_ARGS) 404{ 405 return(check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 0)); 406} 407 408static int 409ewarn_ge1(POST_ARGS) 410{ 411 return(check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_GT, 0)); 412} 413 414static int 415herr_eq0(POST_ARGS) 416{ 417 return(check_count(mdoc, MDOC_HEAD, CHECK_FATAL, CHECK_EQ, 0)); 418} 419 420static int 421herr_ge1(POST_ARGS) 422{ 423 return(check_count(mdoc, MDOC_HEAD, CHECK_FATAL, CHECK_GT, 0)); 424} 425 426static int 427hwarn_eq0(POST_ARGS) 428{ 429 return(check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_EQ, 0)); 430} 431 432static int 433hwarn_eq1(POST_ARGS) 434{ 435 return(check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_EQ, 1)); 436} 437 438static int 439hwarn_le1(POST_ARGS) 440{ 441 return(check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_LT, 2)); 442} 443 444 445static int 446check_stdarg(PRE_ARGS) 447{ 448 449 if (n->args && 1 == n->args->argc) 450 if (MDOC_Std == n->args->argv[0].arg) 451 return(1); 452 return(mdoc_nmsg(mdoc, n, MANDOCERR_NOARGV)); 453} 454 455 456static int 457check_args(struct mdoc *m, struct mdoc_node *n) 458{ 459 int i; 460 461 if (NULL == n->args) 462 return(1); 463 464 assert(n->args->argc); 465 for (i = 0; i < (int)n->args->argc; i++) 466 if ( ! check_argv(m, n, &n->args->argv[i])) 467 return(0); 468 469 return(1); 470} 471 472 473static int 474check_argv(struct mdoc *m, struct mdoc_node *n, struct mdoc_argv *v) 475{ 476 int i; 477 478 for (i = 0; i < (int)v->sz; i++) 479 if ( ! check_text(m, v->line, v->pos, v->value[i])) 480 return(0); 481 482 if (MDOC_Std == v->arg) { 483 if (v->sz || m->meta.name) 484 return(1); 485 if ( ! mdoc_nmsg(m, n, MANDOCERR_NONAME)) 486 return(0); 487 } 488 489 return(1); 490} 491 492 493static int 494check_text(struct mdoc *m, int ln, int pos, char *p) 495{ 496 int c; 497 size_t sz; 498 499 for ( ; *p; p++, pos++) { 500 sz = strcspn(p, "\t\\"); 501 p += (int)sz; 502 503 if ('\0' == *p) 504 break; 505 506 pos += (int)sz; 507 508 if ('\t' == *p) { 509 if (MDOC_LITERAL & m->flags) 510 continue; 511 if (mdoc_pmsg(m, ln, pos, MANDOCERR_BADTAB)) 512 continue; 513 return(0); 514 } 515 516 /* Check the special character. */ 517 518 c = mandoc_special(p); 519 if (c) { 520 p += c - 1; 521 pos += c - 1; 522 } else 523 mdoc_pmsg(m, ln, pos, MANDOCERR_BADESCAPE); 524 } 525 526 return(1); 527} 528 529 530static int 531check_parent(PRE_ARGS, enum mdoct tok, enum mdoc_type t) 532{ 533 534 assert(n->parent); 535 if ((MDOC_ROOT == t || tok == n->parent->tok) && 536 (t == n->parent->type)) 537 return(1); 538 539 mdoc_vmsg(mdoc, MANDOCERR_SYNTCHILD, 540 n->line, n->pos, "want parent %s", 541 MDOC_ROOT == t ? "<root>" : 542 mdoc_macronames[tok]); 543 return(0); 544} 545 546 547static int 548pre_display(PRE_ARGS) 549{ 550 struct mdoc_node *node; 551 552 if (MDOC_BLOCK != n->type) 553 return(1); 554 555 for (node = mdoc->last->parent; node; node = node->parent) 556 if (MDOC_BLOCK == node->type) 557 if (MDOC_Bd == node->tok) 558 break; 559 if (node) 560 mdoc_nmsg(mdoc, n, MANDOCERR_NESTEDDISP); 561 562 return(1); 563} 564 565 566static int 567pre_bl(PRE_ARGS) 568{ 569 int i, comp, dup; 570 const char *offs, *width; 571 enum mdoc_list lt; 572 struct mdoc_node *np; 573 574 if (MDOC_BLOCK != n->type) { 575 if (ENDBODY_NOT != n->end) { 576 assert(n->pending); 577 np = n->pending->parent; 578 } else 579 np = n->parent; 580 581 assert(np); 582 assert(MDOC_BLOCK == np->type); 583 assert(MDOC_Bl == np->tok); 584 assert(np->data.Bl); 585 n->data.Bl = np->data.Bl; 586 return(1); 587 } 588 589 /* 590 * First figure out which kind of list to use: bind ourselves to 591 * the first mentioned list type and warn about any remaining 592 * ones. If we find no list type, we default to LIST_item. 593 */ 594 595 assert(NULL == n->data.Bl); 596 n->data.Bl = mandoc_calloc(1, sizeof(struct mdoc_bl)); 597 598 /* LINTED */ 599 for (i = 0; n->args && i < (int)n->args->argc; i++) { 600 lt = LIST__NONE; 601 dup = comp = 0; 602 width = offs = NULL; 603 switch (n->args->argv[i].arg) { 604 /* Set list types. */ 605 case (MDOC_Bullet): 606 lt = LIST_bullet; 607 break; 608 case (MDOC_Dash): 609 lt = LIST_dash; 610 break; 611 case (MDOC_Enum): 612 lt = LIST_enum; 613 break; 614 case (MDOC_Hyphen): 615 lt = LIST_hyphen; 616 break; 617 case (MDOC_Item): 618 lt = LIST_item; 619 break; 620 case (MDOC_Tag): 621 lt = LIST_tag; 622 break; 623 case (MDOC_Diag): 624 lt = LIST_diag; 625 break; 626 case (MDOC_Hang): 627 lt = LIST_hang; 628 break; 629 case (MDOC_Ohang): 630 lt = LIST_ohang; 631 break; 632 case (MDOC_Inset): 633 lt = LIST_inset; 634 break; 635 case (MDOC_Column): 636 lt = LIST_column; 637 break; 638 /* Set list arguments. */ 639 case (MDOC_Compact): 640 dup = n->data.Bl->comp; 641 comp = 1; 642 break; 643 case (MDOC_Width): 644 dup = (NULL != n->data.Bl->width); 645 width = n->args->argv[i].value[0]; 646 break; 647 case (MDOC_Offset): 648 /* NB: this can be empty! */ 649 if (n->args->argv[i].sz) { 650 offs = n->args->argv[i].value[0]; 651 dup = (NULL != n->data.Bl->offs); 652 break; 653 } 654 if ( ! mdoc_nmsg(mdoc, n, MANDOCERR_IGNARGV)) 655 return(0); 656 break; 657 default: 658 continue; 659 } 660 661 /* Check: duplicate auxiliary arguments. */ 662 663 if (dup && ! mdoc_nmsg(mdoc, n, MANDOCERR_ARGVREP)) 664 return(0); 665 666 if (comp && ! dup) 667 n->data.Bl->comp = comp; 668 if (offs && ! dup) 669 n->data.Bl->offs = offs; 670 if (width && ! dup) 671 n->data.Bl->width = width; 672 673 /* Check: multiple list types. */ 674 675 if (LIST__NONE != lt && n->data.Bl->type != LIST__NONE) 676 if ( ! mdoc_nmsg(mdoc, n, MANDOCERR_LISTREP)) 677 return(0); 678 679 /* Assign list type. */ 680 681 if (LIST__NONE != lt && n->data.Bl->type == LIST__NONE) { 682 n->data.Bl->type = lt; 683 /* Set column information, too. */ 684 if (LIST_column == lt) { 685 n->data.Bl->ncols = 686 n->args->argv[i].sz; 687 n->data.Bl->cols = (const char **) 688 n->args->argv[i].value; 689 } 690 } 691 692 /* The list type should come first. */ 693 694 if (n->data.Bl->type == LIST__NONE) 695 if (n->data.Bl->width || 696 n->data.Bl->offs || 697 n->data.Bl->comp) 698 if ( ! mdoc_nmsg(mdoc, n, MANDOCERR_LISTFIRST)) 699 return(0); 700 701 continue; 702 } 703 704 /* Allow lists to default to LIST_item. */ 705 706 if (LIST__NONE == n->data.Bl->type) { 707 if ( ! mdoc_nmsg(mdoc, n, MANDOCERR_LISTTYPE)) 708 return(0); 709 n->data.Bl->type = LIST_item; 710 } 711 712 /* 713 * Validate the width field. Some list types don't need width 714 * types and should be warned about them. Others should have it 715 * and must also be warned. 716 */ 717 718 switch (n->data.Bl->type) { 719 case (LIST_tag): 720 if (n->data.Bl->width) 721 break; 722 if (mdoc_nmsg(mdoc, n, MANDOCERR_NOWIDTHARG)) 723 break; 724 return(0); 725 case (LIST_column): 726 /* FALLTHROUGH */ 727 case (LIST_diag): 728 /* FALLTHROUGH */ 729 case (LIST_ohang): 730 /* FALLTHROUGH */ 731 case (LIST_inset): 732 /* FALLTHROUGH */ 733 case (LIST_item): 734 if (NULL == n->data.Bl->width) 735 break; 736 if (mdoc_nmsg(mdoc, n, MANDOCERR_WIDTHARG)) 737 break; 738 return(0); 739 default: 740 break; 741 } 742 743 return(1); 744} 745 746 747static int 748pre_bd(PRE_ARGS) 749{ 750 int i, dup, comp; 751 enum mdoc_disp dt; 752 const char *offs; 753 struct mdoc_node *np; 754 755 if (MDOC_BLOCK != n->type) { 756 if (ENDBODY_NOT != n->end) { 757 assert(n->pending); 758 np = n->pending->parent; 759 } else 760 np = n->parent; 761 762 assert(np); 763 assert(MDOC_BLOCK == np->type); 764 assert(MDOC_Bd == np->tok); 765 assert(np->data.Bd); 766 n->data.Bd = np->data.Bd; 767 return(1); 768 } 769 770 assert(NULL == n->data.Bd); 771 n->data.Bd = mandoc_calloc(1, sizeof(struct mdoc_bd)); 772 773 /* LINTED */ 774 for (i = 0; n->args && i < (int)n->args->argc; i++) { 775 dt = DISP__NONE; 776 dup = comp = 0; 777 offs = NULL; 778 779 switch (n->args->argv[i].arg) { 780 case (MDOC_Centred): 781 dt = DISP_centred; 782 break; 783 case (MDOC_Ragged): 784 dt = DISP_ragged; 785 break; 786 case (MDOC_Unfilled): 787 dt = DISP_unfilled; 788 break; 789 case (MDOC_Filled): 790 dt = DISP_filled; 791 break; 792 case (MDOC_Literal): 793 dt = DISP_literal; 794 break; 795 case (MDOC_File): 796 mdoc_nmsg(mdoc, n, MANDOCERR_BADDISP); 797 return(0); 798 case (MDOC_Offset): 799 /* NB: this can be empty! */ 800 if (n->args->argv[i].sz) { 801 offs = n->args->argv[i].value[0]; 802 dup = (NULL != n->data.Bd->offs); 803 break; 804 } 805 if ( ! mdoc_nmsg(mdoc, n, MANDOCERR_IGNARGV)) 806 return(0); 807 break; 808 case (MDOC_Compact): 809 comp = 1; 810 dup = n->data.Bd->comp; 811 break; 812 default: 813 abort(); 814 /* NOTREACHED */ 815 } 816 817 /* Check whether we have duplicates. */ 818 819 if (dup && ! mdoc_nmsg(mdoc, n, MANDOCERR_ARGVREP)) 820 return(0); 821 822 /* Make our auxiliary assignments. */ 823 824 if (offs && ! dup) 825 n->data.Bd->offs = offs; 826 if (comp && ! dup) 827 n->data.Bd->comp = comp; 828 829 /* Check whether a type has already been assigned. */ 830 831 if (DISP__NONE != dt && n->data.Bd->type != DISP__NONE) 832 if ( ! mdoc_nmsg(mdoc, n, MANDOCERR_DISPREP)) 833 return(0); 834 835 /* Make our type assignment. */ 836 837 if (DISP__NONE != dt && n->data.Bd->type == DISP__NONE) 838 n->data.Bd->type = dt; 839 } 840 841 if (DISP__NONE == n->data.Bd->type) { 842 if ( ! mdoc_nmsg(mdoc, n, MANDOCERR_DISPTYPE)) 843 return(0); 844 n->data.Bd->type = DISP_ragged; 845 } 846 847 return(1); 848} 849 850 851static int 852pre_ss(PRE_ARGS) 853{ 854 855 if (MDOC_BLOCK != n->type) 856 return(1); 857 return(check_parent(mdoc, n, MDOC_Sh, MDOC_BODY)); 858} 859 860 861static int 862pre_sh(PRE_ARGS) 863{ 864 865 if (MDOC_BLOCK != n->type) 866 return(1); 867 868 mdoc->regs->regs[(int)REG_nS].set = 0; 869 return(check_parent(mdoc, n, MDOC_MAX, MDOC_ROOT)); 870} 871 872 873static int 874pre_it(PRE_ARGS) 875{ 876 877 if (MDOC_BLOCK != n->type) 878 return(1); 879 /* 880 * FIXME: this can probably be lifted if we make the It into 881 * something else on-the-fly? 882 */ 883 return(check_parent(mdoc, n, MDOC_Bl, MDOC_BODY)); 884} 885 886 887static int 888pre_an(PRE_ARGS) 889{ 890 int i; 891 892 if (NULL == n->args) 893 return(1); 894 895 for (i = 1; i < (int)n->args->argc; i++) 896 if ( ! mdoc_pmsg(mdoc, n->args->argv[i].line, 897 n->args->argv[i].pos, MANDOCERR_IGNARGV)) 898 return(0); 899 900 if (MDOC_Split == n->args->argv[0].arg) 901 n->data.An.auth = AUTH_split; 902 else if (MDOC_Nosplit == n->args->argv[0].arg) 903 n->data.An.auth = AUTH_nosplit; 904 else 905 abort(); 906 907 return(1); 908} 909 910 911static int 912pre_rv(PRE_ARGS) 913{ 914 915 return(check_stdarg(mdoc, n)); 916} 917 918 919static int 920post_dt(POST_ARGS) 921{ 922 const struct mdoc_node *nn; 923 const char *p; 924 925 if (NULL != (nn = mdoc->last->child)) 926 for (p = nn->string; *p; p++) { 927 if (toupper((u_char)*p) == *p) 928 continue; 929 if ( ! mdoc_nmsg(mdoc, nn, MANDOCERR_UPPERCASE)) 930 return(0); 931 break; 932 } 933 934 return(1); 935} 936 937 938static int 939pre_dt(PRE_ARGS) 940{ 941 942 if (0 == mdoc->meta.date || mdoc->meta.os) 943 if ( ! mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGOOO)) 944 return(0); 945 if (mdoc->meta.title) 946 if ( ! mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGREP)) 947 return(0); 948 return(1); 949} 950 951 952static int 953pre_os(PRE_ARGS) 954{ 955 956 if (NULL == mdoc->meta.title || 0 == mdoc->meta.date) 957 if ( ! mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGOOO)) 958 return(0); 959 if (mdoc->meta.os) 960 if ( ! mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGREP)) 961 return(0); 962 return(1); 963} 964 965 966static int 967pre_dd(PRE_ARGS) 968{ 969 970 if (mdoc->meta.title || mdoc->meta.os) 971 if ( ! mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGOOO)) 972 return(0); 973 if (mdoc->meta.date) 974 if ( ! mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGREP)) 975 return(0); 976 return(1); 977} 978 979 980static int 981post_bf(POST_ARGS) 982{ 983 struct mdoc_node *np; 984 enum mdocargt arg; 985 986 /* 987 * Unlike other data pointers, these are "housed" by the HEAD 988 * element, which contains the goods. 989 */ 990 991 if (MDOC_HEAD != mdoc->last->type) { 992 if (ENDBODY_NOT != mdoc->last->end) { 993 assert(mdoc->last->pending); 994 np = mdoc->last->pending->parent->head; 995 } else if (MDOC_BLOCK != mdoc->last->type) { 996 np = mdoc->last->parent->head; 997 } else 998 np = mdoc->last->head; 999 1000 assert(np); 1001 assert(MDOC_HEAD == np->type); 1002 assert(MDOC_Bf == np->tok); 1003 assert(np->data.Bf); 1004 mdoc->last->data.Bf = np->data.Bf; 1005 return(1); 1006 } 1007 1008 np = mdoc->last; 1009 assert(MDOC_BLOCK == np->parent->type); 1010 assert(MDOC_Bf == np->parent->tok); 1011 np->data.Bf = mandoc_calloc(1, sizeof(struct mdoc_bf)); 1012 1013 /* 1014 * Cannot have both argument and parameter. 1015 * If neither is specified, let it through with a warning. 1016 */ 1017 1018 if (np->parent->args && np->child) { 1019 mdoc_nmsg(mdoc, np, MANDOCERR_SYNTARGVCOUNT); 1020 return(0); 1021 } else if (NULL == np->parent->args && NULL == np->child) 1022 return(mdoc_nmsg(mdoc, np, MANDOCERR_FONTTYPE)); 1023 1024 /* Extract argument into data. */ 1025 1026 if (np->parent->args) { 1027 arg = np->parent->args->argv[0].arg; 1028 if (MDOC_Emphasis == arg) 1029 np->data.Bf->font = FONT_Em; 1030 else if (MDOC_Literal == arg) 1031 np->data.Bf->font = FONT_Li; 1032 else if (MDOC_Symbolic == arg) 1033 np->data.Bf->font = FONT_Sy; 1034 else 1035 abort(); 1036 return(1); 1037 } 1038 1039 /* Extract parameter into data. */ 1040 1041 if (0 == strcmp(np->child->string, "Em")) 1042 np->data.Bf->font = FONT_Em; 1043 else if (0 == strcmp(np->child->string, "Li")) 1044 np->data.Bf->font = FONT_Li; 1045 else if (0 == strcmp(np->child->string, "Sy")) 1046 np->data.Bf->font = FONT_Sy; 1047 else if ( ! mdoc_nmsg(mdoc, np, MANDOCERR_FONTTYPE)) 1048 return(0); 1049 1050 return(1); 1051} 1052 1053 1054static int 1055post_lb(POST_ARGS) 1056{ 1057 1058 if (mdoc_a2lib(mdoc->last->child->string)) 1059 return(1); 1060 return(mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADLIB)); 1061} 1062 1063 1064static int 1065post_eoln(POST_ARGS) 1066{ 1067 1068 if (NULL == mdoc->last->child) 1069 return(1); 1070 return(mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_ARGSLOST)); 1071} 1072 1073 1074static int 1075post_vt(POST_ARGS) 1076{ 1077 const struct mdoc_node *n; 1078 1079 /* 1080 * The Vt macro comes in both ELEM and BLOCK form, both of which 1081 * have different syntaxes (yet more context-sensitive 1082 * behaviour). ELEM types must have a child; BLOCK types, 1083 * specifically the BODY, should only have TEXT children. 1084 */ 1085 1086 if (MDOC_ELEM == mdoc->last->type) 1087 return(eerr_ge1(mdoc)); 1088 if (MDOC_BODY != mdoc->last->type) 1089 return(1); 1090 1091 for (n = mdoc->last->child; n; n = n->next) 1092 if (MDOC_TEXT != n->type) 1093 if ( ! mdoc_nmsg(mdoc, n, MANDOCERR_CHILD)) 1094 return(0); 1095 1096 return(1); 1097} 1098 1099 1100static int 1101post_nm(POST_ARGS) 1102{ 1103 1104 if (mdoc->last->child) 1105 return(1); 1106 if (mdoc->meta.name) 1107 return(1); 1108 return(mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NONAME)); 1109} 1110 1111 1112static int 1113post_at(POST_ARGS) 1114{ 1115 1116 if (NULL == mdoc->last->child) 1117 return(1); 1118 assert(MDOC_TEXT == mdoc->last->child->type); 1119 if (mdoc_a2att(mdoc->last->child->string)) 1120 return(1); 1121 return(mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADATT)); 1122} 1123 1124 1125static int 1126post_an(POST_ARGS) 1127{ 1128 struct mdoc_node *np; 1129 1130 np = mdoc->last; 1131 if (AUTH__NONE != np->data.An.auth && np->child) 1132 return(eerr_eq0(mdoc)); 1133 /* 1134 * FIXME: make this ewarn and make sure that the front-ends 1135 * don't print the arguments. 1136 */ 1137 if (AUTH__NONE != np->data.An.auth || np->child) 1138 return(1); 1139 return(mdoc_nmsg(mdoc, np, MANDOCERR_NOARGS)); 1140} 1141 1142 1143static int 1144post_it(POST_ARGS) 1145{ 1146 int i, cols, rc; 1147 enum mdoc_list lt; 1148 struct mdoc_node *n, *c; 1149 enum mandocerr er; 1150 1151 if (MDOC_BLOCK != mdoc->last->type) 1152 return(1); 1153 1154 n = mdoc->last->parent->parent; 1155 assert(n->data.Bl); 1156 lt = n->data.Bl->type; 1157 1158 if (LIST__NONE == lt) { 1159 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_LISTTYPE); 1160 return(0); 1161 } 1162 1163 switch (lt) { 1164 case (LIST_tag): 1165 if (mdoc->last->head->child) 1166 break; 1167 /* FIXME: give this a dummy value. */ 1168 if ( ! mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOARGS)) 1169 return(0); 1170 break; 1171 case (LIST_hang): 1172 /* FALLTHROUGH */ 1173 case (LIST_ohang): 1174 /* FALLTHROUGH */ 1175 case (LIST_inset): 1176 /* FALLTHROUGH */ 1177 case (LIST_diag): 1178 if (NULL == mdoc->last->head->child) 1179 if ( ! mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOARGS)) 1180 return(0); 1181 break; 1182 case (LIST_bullet): 1183 /* FALLTHROUGH */ 1184 case (LIST_dash): 1185 /* FALLTHROUGH */ 1186 case (LIST_enum): 1187 /* FALLTHROUGH */ 1188 case (LIST_hyphen): 1189 if (NULL == mdoc->last->body->child) 1190 if ( ! mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOBODY)) 1191 return(0); 1192 /* FALLTHROUGH */ 1193 case (LIST_item): 1194 if (mdoc->last->head->child) 1195 if ( ! mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_ARGSLOST)) 1196 return(0); 1197 break; 1198 case (LIST_column): 1199 cols = (int)n->data.Bl->ncols; 1200 1201 assert(NULL == mdoc->last->head->child); 1202 1203 if (NULL == mdoc->last->body->child) 1204 if ( ! mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOBODY)) 1205 return(0); 1206 1207 for (i = 0, c = mdoc->last->child; c; c = c->next) 1208 if (MDOC_BODY == c->type) 1209 i++; 1210 1211 if (i < cols) 1212 er = MANDOCERR_ARGCOUNT; 1213 else if (i == cols || i == cols + 1) 1214 break; 1215 else 1216 er = MANDOCERR_SYNTARGCOUNT; 1217 1218 rc = mdoc_vmsg(mdoc, er, 1219 mdoc->last->line, mdoc->last->pos, 1220 "columns == %d (have %d)", cols, i); 1221 return(rc); 1222 default: 1223 break; 1224 } 1225 1226 return(1); 1227} 1228 1229 1230static int 1231post_bl_head(POST_ARGS) 1232{ 1233 struct mdoc_node *n; 1234 1235 assert(mdoc->last->parent); 1236 n = mdoc->last->parent; 1237 1238 if (LIST_column == n->data.Bl->type) { 1239 if (n->data.Bl->ncols && mdoc->last->nchild) { 1240 mdoc_nmsg(mdoc, n, MANDOCERR_COLUMNS); 1241 return(0); 1242 } 1243 return(1); 1244 } 1245 1246 /* FIXME: should be ERROR class. */ 1247 return(hwarn_eq0(mdoc)); 1248} 1249 1250 1251static int 1252post_bl(POST_ARGS) 1253{ 1254 struct mdoc_node *n; 1255 1256 if (MDOC_HEAD == mdoc->last->type) 1257 return(post_bl_head(mdoc)); 1258 if (MDOC_BODY != mdoc->last->type) 1259 return(1); 1260 if (NULL == mdoc->last->child) 1261 return(1); 1262 1263 /* 1264 * We only allow certain children of `Bl'. This is usually on 1265 * `It', but apparently `Sm' occurs here and there, so we let 1266 * that one through, too. 1267 */ 1268 1269 /* LINTED */ 1270 for (n = mdoc->last->child; n; n = n->next) { 1271 if (MDOC_BLOCK == n->type && MDOC_It == n->tok) 1272 continue; 1273 if (MDOC_Sm == n->tok) 1274 continue; 1275 mdoc_nmsg(mdoc, n, MANDOCERR_SYNTCHILD); 1276 return(0); 1277 } 1278 1279 return(1); 1280} 1281 1282 1283static int 1284ebool(struct mdoc *mdoc) 1285{ 1286 struct mdoc_node *n; 1287 1288 /* LINTED */ 1289 for (n = mdoc->last->child; n; n = n->next) { 1290 if (MDOC_TEXT != n->type) 1291 break; 1292 if (0 == strcmp(n->string, "on")) 1293 continue; 1294 if (0 == strcmp(n->string, "off")) 1295 continue; 1296 break; 1297 } 1298 1299 if (NULL == n) 1300 return(1); 1301 return(mdoc_nmsg(mdoc, n, MANDOCERR_BADBOOL)); 1302} 1303 1304 1305static int 1306post_root(POST_ARGS) 1307{ 1308 1309 if (NULL == mdoc->first->child) 1310 mdoc_nmsg(mdoc, mdoc->first, MANDOCERR_NODOCBODY); 1311 else if ( ! (MDOC_PBODY & mdoc->flags)) 1312 mdoc_nmsg(mdoc, mdoc->first, MANDOCERR_NODOCPROLOG); 1313 else if (MDOC_BLOCK != mdoc->first->child->type) 1314 mdoc_nmsg(mdoc, mdoc->first, MANDOCERR_NODOCBODY); 1315 else if (MDOC_Sh != mdoc->first->child->tok) 1316 mdoc_nmsg(mdoc, mdoc->first, MANDOCERR_NODOCBODY); 1317 else 1318 return(1); 1319 1320 return(0); 1321} 1322 1323 1324static int 1325post_st(POST_ARGS) 1326{ 1327 1328 if (mdoc_a2st(mdoc->last->child->string)) 1329 return(1); 1330 return(mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADSTANDARD)); 1331} 1332 1333 1334static int 1335post_rs(POST_ARGS) 1336{ 1337 struct mdoc_node *nn; 1338 1339 if (MDOC_BODY != mdoc->last->type) 1340 return(1); 1341 1342 for (nn = mdoc->last->child; nn; nn = nn->next) 1343 switch (nn->tok) { 1344 case(MDOC__U): 1345 /* FALLTHROUGH */ 1346 case(MDOC__Q): 1347 /* FALLTHROUGH */ 1348 case(MDOC__C): 1349 /* FALLTHROUGH */ 1350 case(MDOC__A): 1351 /* FALLTHROUGH */ 1352 case(MDOC__B): 1353 /* FALLTHROUGH */ 1354 case(MDOC__D): 1355 /* FALLTHROUGH */ 1356 case(MDOC__I): 1357 /* FALLTHROUGH */ 1358 case(MDOC__J): 1359 /* FALLTHROUGH */ 1360 case(MDOC__N): 1361 /* FALLTHROUGH */ 1362 case(MDOC__O): 1363 /* FALLTHROUGH */ 1364 case(MDOC__P): 1365 /* FALLTHROUGH */ 1366 case(MDOC__R): 1367 /* FALLTHROUGH */ 1368 case(MDOC__T): 1369 /* FALLTHROUGH */ 1370 case(MDOC__V): 1371 break; 1372 default: 1373 mdoc_nmsg(mdoc, nn, MANDOCERR_SYNTCHILD); 1374 return(0); 1375 } 1376 1377 return(1); 1378} 1379 1380 1381static int 1382post_sh(POST_ARGS) 1383{ 1384 1385 if (MDOC_HEAD == mdoc->last->type) 1386 return(post_sh_head(mdoc)); 1387 if (MDOC_BODY == mdoc->last->type) 1388 return(post_sh_body(mdoc)); 1389 1390 return(1); 1391} 1392 1393 1394static int 1395post_sh_body(POST_ARGS) 1396{ 1397 struct mdoc_node *n; 1398 1399 if (SEC_NAME != mdoc->lastsec) 1400 return(1); 1401 1402 /* 1403 * Warn if the NAME section doesn't contain the `Nm' and `Nd' 1404 * macros (can have multiple `Nm' and one `Nd'). Note that the 1405 * children of the BODY declaration can also be "text". 1406 */ 1407 1408 if (NULL == (n = mdoc->last->child)) 1409 return(mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADNAMESEC)); 1410 1411 for ( ; n && n->next; n = n->next) { 1412 if (MDOC_ELEM == n->type && MDOC_Nm == n->tok) 1413 continue; 1414 if (MDOC_TEXT == n->type) 1415 continue; 1416 if ( ! mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADNAMESEC)) 1417 return(0); 1418 } 1419 1420 assert(n); 1421 if (MDOC_BLOCK == n->type && MDOC_Nd == n->tok) 1422 return(1); 1423 return(mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADNAMESEC)); 1424} 1425 1426 1427static int 1428post_sh_head(POST_ARGS) 1429{ 1430 char buf[BUFSIZ]; 1431 enum mdoc_sec sec; 1432 const struct mdoc_node *n; 1433 1434 /* 1435 * Process a new section. Sections are either "named" or 1436 * "custom"; custom sections are user-defined, while named ones 1437 * usually follow a conventional order and may only appear in 1438 * certain manual sections. 1439 */ 1440 1441 buf[0] = '\0'; 1442 1443 /* 1444 * FIXME: yes, these can use a dynamic buffer, but I don't do so 1445 * in the interests of simplicity. 1446 */ 1447 1448 for (n = mdoc->last->child; n; n = n->next) { 1449 /* XXX - copied from compact(). */ 1450 assert(MDOC_TEXT == n->type); 1451 1452 if (strlcat(buf, n->string, BUFSIZ) >= BUFSIZ) { 1453 mdoc_nmsg(mdoc, n, MANDOCERR_MEM); 1454 return(0); 1455 } 1456 if (NULL == n->next) 1457 continue; 1458 if (strlcat(buf, " ", BUFSIZ) >= BUFSIZ) { 1459 mdoc_nmsg(mdoc, n, MANDOCERR_MEM); 1460 return(0); 1461 } 1462 } 1463 1464 sec = mdoc_str2sec(buf); 1465 1466 /* 1467 * Check: NAME should always be first, CUSTOM has no roles, 1468 * non-CUSTOM has a conventional order to be followed. 1469 */ 1470 1471 if (SEC_NAME != sec && SEC_NONE == mdoc->lastnamed) 1472 if ( ! mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NAMESECFIRST)) 1473 return(0); 1474 1475 if (SEC_CUSTOM == sec) 1476 return(1); 1477 1478 if (sec == mdoc->lastnamed) 1479 if ( ! mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_SECREP)) 1480 return(0); 1481 1482 if (sec < mdoc->lastnamed) 1483 if ( ! mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_SECOOO)) 1484 return(0); 1485 1486 /* 1487 * Check particular section/manual conventions. LIBRARY can 1488 * only occur in manual section 2, 3, and 9. 1489 */ 1490 1491 switch (sec) { 1492 case (SEC_LIBRARY): 1493 assert(mdoc->meta.msec); 1494 if (*mdoc->meta.msec == '2') 1495 break; 1496 if (*mdoc->meta.msec == '3') 1497 break; 1498 if (*mdoc->meta.msec == '9') 1499 break; 1500 return(mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_SECMSEC)); 1501 default: 1502 break; 1503 } 1504 1505 return(1); 1506} 1507 1508 1509static int 1510pre_pp(PRE_ARGS) 1511{ 1512 1513 if (NULL == mdoc->last) 1514 return(1); 1515 1516 /* Don't allow prior `Lp' or `Pp'. */ 1517 1518 if (MDOC_Pp != mdoc->last->tok && MDOC_Lp != mdoc->last->tok) 1519 return(1); 1520 1521 if (MDOC_Bl == n->tok && n->data.Bl->comp) 1522 return(1); 1523 if (MDOC_Bd == n->tok && n->data.Bd->comp) 1524 return(1); 1525 1526 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_IGNPAR); 1527 mdoc_node_delete(mdoc, mdoc->last); 1528 return(1); 1529} 1530