Print this page
5051 import mdocml-1.12.3
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Approved by: TBD
   1 /*      $Id: mdoc_validate.c,v 1.182 2012/03/23 05:50:25 kristaps Exp $ */
   2 /*
   3  * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
   4  * Copyright (c) 2010, 2011 Ingo Schwarze <schwarze@openbsd.org>
   5  *
   6  * Permission to use, copy, modify, and distribute this software for any
   7  * purpose with or without fee is hereby granted, provided that the above
   8  * copyright notice and this permission notice appear in all copies.
   9  *
  10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  17  */
  18 #ifdef HAVE_CONFIG_H
  19 #include "config.h"
  20 #endif
  21 
  22 #ifndef OSNAME
  23 #include <sys/utsname.h>
  24 #endif


  80 static  int      berr_ge1(POST_ARGS);
  81 static  int      bwarn_ge1(POST_ARGS);
  82 static  int      ewarn_eq0(POST_ARGS);
  83 static  int      ewarn_eq1(POST_ARGS);
  84 static  int      ewarn_ge1(POST_ARGS);
  85 static  int      ewarn_le1(POST_ARGS);
  86 static  int      hwarn_eq0(POST_ARGS);
  87 static  int      hwarn_eq1(POST_ARGS);
  88 static  int      hwarn_ge1(POST_ARGS);
  89 static  int      hwarn_le1(POST_ARGS);
  90 
  91 static  int      post_an(POST_ARGS);
  92 static  int      post_at(POST_ARGS);
  93 static  int      post_bf(POST_ARGS);
  94 static  int      post_bl(POST_ARGS);
  95 static  int      post_bl_block(POST_ARGS);
  96 static  int      post_bl_block_width(POST_ARGS);
  97 static  int      post_bl_block_tag(POST_ARGS);
  98 static  int      post_bl_head(POST_ARGS);
  99 static  int      post_bx(POST_ARGS);

 100 static  int      post_dd(POST_ARGS);
 101 static  int      post_dt(POST_ARGS);
 102 static  int      post_defaults(POST_ARGS);
 103 static  int      post_literal(POST_ARGS);
 104 static  int      post_eoln(POST_ARGS);


 105 static  int      post_it(POST_ARGS);
 106 static  int      post_lb(POST_ARGS);

 107 static  int      post_nm(POST_ARGS);
 108 static  int      post_ns(POST_ARGS);
 109 static  int      post_os(POST_ARGS);
 110 static  int      post_ignpar(POST_ARGS);
 111 static  int      post_prol(POST_ARGS);
 112 static  int      post_root(POST_ARGS);
 113 static  int      post_rs(POST_ARGS);
 114 static  int      post_sh(POST_ARGS);
 115 static  int      post_sh_body(POST_ARGS);
 116 static  int      post_sh_head(POST_ARGS);
 117 static  int      post_st(POST_ARGS);
 118 static  int      post_std(POST_ARGS);
 119 static  int      post_vt(POST_ARGS);
 120 static  int      pre_an(PRE_ARGS);
 121 static  int      pre_bd(PRE_ARGS);
 122 static  int      pre_bl(PRE_ARGS);
 123 static  int      pre_dd(PRE_ARGS);
 124 static  int      pre_display(PRE_ARGS);
 125 static  int      pre_dt(PRE_ARGS);
 126 static  int      pre_it(PRE_ARGS);
 127 static  int      pre_literal(PRE_ARGS);
 128 static  int      pre_os(PRE_ARGS);
 129 static  int      pre_par(PRE_ARGS);
 130 static  int      pre_sh(PRE_ARGS);
 131 static  int      pre_ss(PRE_ARGS);
 132 static  int      pre_std(PRE_ARGS);
 133 
 134 static  v_post   posts_an[] = { post_an, NULL };
 135 static  v_post   posts_at[] = { post_at, post_defaults, NULL };
 136 static  v_post   posts_bd[] = { post_literal, hwarn_eq0, bwarn_ge1, NULL };
 137 static  v_post   posts_bf[] = { hwarn_le1, post_bf, NULL };
 138 static  v_post   posts_bk[] = { hwarn_eq0, bwarn_ge1, NULL };
 139 static  v_post   posts_bl[] = { bwarn_ge1, post_bl, NULL };
 140 static  v_post   posts_bx[] = { post_bx, NULL };
 141 static  v_post   posts_bool[] = { ebool, NULL };
 142 static  v_post   posts_eoln[] = { post_eoln, NULL };
 143 static  v_post   posts_defaults[] = { post_defaults, NULL };

 144 static  v_post   posts_dd[] = { post_dd, post_prol, NULL };
 145 static  v_post   posts_dl[] = { post_literal, bwarn_ge1, NULL };
 146 static  v_post   posts_dt[] = { post_dt, post_prol, NULL };
 147 static  v_post   posts_fo[] = { hwarn_eq1, bwarn_ge1, NULL };


 148 static  v_post   posts_it[] = { post_it, NULL };
 149 static  v_post   posts_lb[] = { post_lb, NULL };
 150 static  v_post   posts_nd[] = { berr_ge1, NULL };
 151 static  v_post   posts_nm[] = { post_nm, NULL };
 152 static  v_post   posts_notext[] = { ewarn_eq0, NULL };
 153 static  v_post   posts_ns[] = { post_ns, NULL };
 154 static  v_post   posts_os[] = { post_os, post_prol, NULL };

 155 static  v_post   posts_rs[] = { post_rs, NULL };
 156 static  v_post   posts_sh[] = { post_ignpar, hwarn_ge1, post_sh, NULL };
 157 static  v_post   posts_sp[] = { ewarn_le1, NULL };
 158 static  v_post   posts_ss[] = { post_ignpar, hwarn_ge1, NULL };
 159 static  v_post   posts_st[] = { post_st, NULL };
 160 static  v_post   posts_std[] = { post_std, NULL };
 161 static  v_post   posts_text[] = { ewarn_ge1, NULL };
 162 static  v_post   posts_text1[] = { ewarn_eq1, NULL };
 163 static  v_post   posts_vt[] = { post_vt, NULL };
 164 static  v_post   posts_wline[] = { bwarn_ge1, NULL };
 165 static  v_pre    pres_an[] = { pre_an, NULL };
 166 static  v_pre    pres_bd[] = { pre_display, pre_bd, pre_literal, pre_par, NULL };
 167 static  v_pre    pres_bl[] = { pre_bl, pre_par, NULL };
 168 static  v_pre    pres_d1[] = { pre_display, NULL };
 169 static  v_pre    pres_dl[] = { pre_literal, pre_display, NULL };
 170 static  v_pre    pres_dd[] = { pre_dd, NULL };
 171 static  v_pre    pres_dt[] = { pre_dt, NULL };
 172 static  v_pre    pres_er[] = { NULL, NULL };
 173 static  v_pre    pres_fd[] = { NULL, NULL };
 174 static  v_pre    pres_it[] = { pre_it, pre_par, NULL };
 175 static  v_pre    pres_os[] = { pre_os, NULL };
 176 static  v_pre    pres_pp[] = { pre_par, NULL };
 177 static  v_pre    pres_sh[] = { pre_sh, NULL };
 178 static  v_pre    pres_ss[] = { pre_ss, NULL };
 179 static  v_pre    pres_std[] = { pre_std, NULL };
 180 
 181 static  const struct valids mdoc_valids[MDOC_MAX] = {
 182         { NULL, NULL },                         /* Ap */
 183         { pres_dd, posts_dd },                  /* Dd */
 184         { pres_dt, posts_dt },                  /* Dt */
 185         { pres_os, posts_os },                  /* Os */
 186         { pres_sh, posts_sh },                  /* Sh */ 
 187         { pres_ss, posts_ss },                  /* Ss */ 
 188         { pres_pp, posts_notext },              /* Pp */ 
 189         { pres_d1, posts_wline },               /* D1 */
 190         { pres_dl, posts_dl },                  /* Dl */
 191         { pres_bd, posts_bd },                  /* Bd */
 192         { NULL, NULL },                         /* Ed */
 193         { pres_bl, posts_bl },                  /* Bl */ 
 194         { NULL, NULL },                         /* El */
 195         { pres_it, posts_it },                  /* It */
 196         { NULL, NULL },                         /* Ad */ 
 197         { pres_an, posts_an },                  /* An */ 
 198         { NULL, posts_defaults },               /* Ar */
 199         { NULL, NULL },                         /* Cd */ 
 200         { NULL, NULL },                         /* Cm */
 201         { NULL, NULL },                         /* Dv */ 
 202         { pres_er, NULL },                      /* Er */ 
 203         { NULL, NULL },                         /* Ev */ 
 204         { pres_std, posts_std },                /* Ex */ 
 205         { NULL, NULL },                         /* Fa */ 
 206         { pres_fd, posts_text },                /* Fd */
 207         { NULL, NULL },                         /* Fl */
 208         { NULL, NULL },                         /* Fn */ 
 209         { NULL, NULL },                         /* Ft */ 
 210         { NULL, NULL },                         /* Ic */ 
 211         { NULL, posts_text1 },                  /* In */ 
 212         { NULL, posts_defaults },               /* Li */
 213         { NULL, posts_nd },                     /* Nd */
 214         { NULL, posts_nm },                     /* Nm */
 215         { NULL, NULL },                         /* Op */
 216         { NULL, NULL },                         /* Ot */
 217         { NULL, posts_defaults },               /* Pa */
 218         { pres_std, posts_std },                /* Rv */
 219         { NULL, posts_st },                     /* St */ 
 220         { NULL, NULL },                         /* Va */
 221         { NULL, posts_vt },                     /* Vt */ 
 222         { NULL, posts_text },                   /* Xr */ 
 223         { NULL, posts_text },                   /* %A */
 224         { NULL, posts_text },                   /* %B */ /* FIXME: can be used outside Rs/Re. */
 225         { NULL, posts_text },                   /* %D */
 226         { NULL, posts_text },                   /* %I */
 227         { NULL, posts_text },                   /* %J */
 228         { NULL, posts_text },                   /* %N */
 229         { NULL, posts_text },                   /* %O */
 230         { NULL, posts_text },                   /* %P */
 231         { NULL, posts_text },                   /* %R */
 232         { NULL, posts_text },                   /* %T */ /* FIXME: can be used outside Rs/Re. */
 233         { NULL, posts_text },                   /* %V */
 234         { NULL, NULL },                         /* Ac */
 235         { NULL, NULL },                         /* Ao */
 236         { NULL, NULL },                         /* Aq */
 237         { NULL, posts_at },                     /* At */ 
 238         { NULL, NULL },                         /* Bc */
 239         { NULL, posts_bf },                     /* Bf */
 240         { NULL, NULL },                         /* Bo */
 241         { NULL, NULL },                         /* Bq */
 242         { NULL, NULL },                         /* Bsx */
 243         { NULL, posts_bx },                     /* Bx */
 244         { NULL, posts_bool },                   /* Db */
 245         { NULL, NULL },                         /* Dc */
 246         { NULL, NULL },                         /* Do */
 247         { NULL, NULL },                         /* Dq */
 248         { NULL, NULL },                         /* Ec */
 249         { NULL, NULL },                         /* Ef */ 
 250         { NULL, NULL },                         /* Em */ 
 251         { NULL, NULL },                         /* Eo */
 252         { NULL, NULL },                         /* Fx */
 253         { NULL, NULL },                         /* Ms */ 
 254         { NULL, posts_notext },                 /* No */
 255         { NULL, posts_ns },                     /* Ns */
 256         { NULL, NULL },                         /* Nx */
 257         { NULL, NULL },                         /* Ox */
 258         { NULL, NULL },                         /* Pc */
 259         { NULL, posts_text1 },                  /* Pf */
 260         { NULL, NULL },                         /* Po */
 261         { NULL, NULL },                         /* Pq */
 262         { NULL, NULL },                         /* Qc */
 263         { NULL, NULL },                         /* Ql */
 264         { NULL, NULL },                         /* Qo */
 265         { NULL, NULL },                         /* Qq */
 266         { NULL, NULL },                         /* Re */
 267         { NULL, posts_rs },                     /* Rs */
 268         { NULL, NULL },                         /* Sc */
 269         { NULL, NULL },                         /* So */
 270         { NULL, NULL },                         /* Sq */
 271         { NULL, posts_bool },                   /* Sm */ 
 272         { NULL, NULL },                         /* Sx */
 273         { NULL, NULL },                         /* Sy */
 274         { NULL, NULL },                         /* Tn */
 275         { NULL, NULL },                         /* Ux */
 276         { NULL, NULL },                         /* Xc */
 277         { NULL, NULL },                         /* Xo */
 278         { NULL, posts_fo },                     /* Fo */ 
 279         { NULL, NULL },                         /* Fc */ 
 280         { NULL, NULL },                         /* Oo */
 281         { NULL, NULL },                         /* Oc */
 282         { NULL, posts_bk },                     /* Bk */
 283         { NULL, NULL },                         /* Ek */
 284         { NULL, posts_eoln },                   /* Bt */
 285         { NULL, NULL },                         /* Hf */
 286         { NULL, NULL },                         /* Fr */
 287         { NULL, posts_eoln },                   /* Ud */
 288         { NULL, posts_lb },                     /* Lb */
 289         { NULL, posts_notext },                 /* Lp */ 
 290         { NULL, NULL },                         /* Lk */ 
 291         { NULL, posts_defaults },               /* Mt */ 
 292         { NULL, NULL },                         /* Brq */ 
 293         { NULL, NULL },                         /* Bro */ 
 294         { NULL, NULL },                         /* Brc */ 
 295         { NULL, posts_text },                   /* %C */
 296         { NULL, NULL },                         /* Es */
 297         { NULL, NULL },                         /* En */
 298         { NULL, NULL },                         /* Dx */
 299         { NULL, posts_text },                   /* %Q */
 300         { NULL, posts_notext },                 /* br */
 301         { pres_pp, posts_sp },                  /* sp */
 302         { NULL, posts_text1 },                  /* %U */
 303         { NULL, NULL },                         /* Ta */
 304 };
 305 
 306 #define RSORD_MAX 14 /* Number of `Rs' blocks. */
 307 
 308 static  const enum mdoct rsord[RSORD_MAX] = {
 309         MDOC__A,
 310         MDOC__T,
 311         MDOC__B,
 312         MDOC__I,
 313         MDOC__J,
 314         MDOC__R,
 315         MDOC__N,
 316         MDOC__V,

 317         MDOC__P,
 318         MDOC__Q,
 319         MDOC__D,
 320         MDOC__O,
 321         MDOC__C,
 322         MDOC__U

 323 };
 324 
 325 static  const char * const secnames[SEC__MAX] = {
 326         NULL,
 327         "NAME",
 328         "LIBRARY",
 329         "SYNOPSIS",
 330         "DESCRIPTION",
 331         "IMPLEMENTATION NOTES",
 332         "RETURN VALUES",
 333         "ENVIRONMENT",
 334         "FILES",
 335         "EXIT STATUS",
 336         "EXAMPLES",
 337         "DIAGNOSTICS",
 338         "COMPATIBILITY",
 339         "ERRORS",
 340         "SEE ALSO",
 341         "STANDARDS",
 342         "HISTORY",


 397         case (MDOC_EQN):
 398                 /* FALLTHROUGH */
 399         case (MDOC_TBL):
 400                 return(1);
 401         case (MDOC_ROOT):
 402                 return(post_root(mdoc));
 403         default:
 404                 break;
 405         }
 406 
 407         if (NULL == mdoc_valids[mdoc->last->tok].post)
 408                 return(1);
 409         for (p = mdoc_valids[mdoc->last->tok].post; *p; p++)
 410                 if ( ! (*p)(mdoc)) 
 411                         return(0);
 412 
 413         return(1);
 414 }
 415 
 416 static int
 417 check_count(struct mdoc *m, enum mdoc_type type, 
 418                 enum check_lvl lvl, enum check_ineq ineq, int val)
 419 {
 420         const char      *p;
 421         enum mandocerr   t;
 422 
 423         if (m->last->type != type)
 424                 return(1);
 425         
 426         switch (ineq) {
 427         case (CHECK_LT):
 428                 p = "less than ";
 429                 if (m->last->nchild < val)
 430                         return(1);
 431                 break;
 432         case (CHECK_GT):
 433                 p = "more than ";
 434                 if (m->last->nchild > val)
 435                         return(1);
 436                 break;
 437         case (CHECK_EQ):
 438                 p = "";
 439                 if (val == m->last->nchild)
 440                         return(1);
 441                 break;
 442         default:
 443                 abort();
 444                 /* NOTREACHED */
 445         }
 446 
 447         t = lvl == CHECK_WARN ? MANDOCERR_ARGCWARN : MANDOCERR_ARGCOUNT;
 448         mandoc_vmsg(t, m->parse, m->last->line, m->last->pos,
 449                         "want %s%d children (have %d)",
 450                         p, val, m->last->nchild);
 451         return(1);
 452 }
 453 
 454 static int
 455 berr_ge1(POST_ARGS)
 456 {
 457 
 458         return(check_count(mdoc, MDOC_BODY, CHECK_ERROR, CHECK_GT, 0));
 459 }
 460 
 461 static int
 462 bwarn_ge1(POST_ARGS)
 463 {
 464         return(check_count(mdoc, MDOC_BODY, CHECK_WARN, CHECK_GT, 0));
 465 }
 466 
 467 static int
 468 ewarn_eq0(POST_ARGS)
 469 {
 470         return(check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 0));


 496 
 497 static int
 498 hwarn_eq1(POST_ARGS)
 499 {
 500         return(check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_EQ, 1));
 501 }
 502 
 503 static int
 504 hwarn_ge1(POST_ARGS)
 505 {
 506         return(check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_GT, 0));
 507 }
 508 
 509 static int
 510 hwarn_le1(POST_ARGS)
 511 {
 512         return(check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_LT, 2));
 513 }
 514 
 515 static void
 516 check_args(struct mdoc *m, struct mdoc_node *n)
 517 {
 518         int              i;
 519 
 520         if (NULL == n->args)
 521                 return;
 522 
 523         assert(n->args->argc);
 524         for (i = 0; i < (int)n->args->argc; i++)
 525                 check_argv(m, n, &n->args->argv[i]);
 526 }
 527 
 528 static void
 529 check_argv(struct mdoc *m, struct mdoc_node *n, struct mdoc_argv *v)
 530 {
 531         int              i;
 532 
 533         for (i = 0; i < (int)v->sz; i++)
 534                 check_text(m, v->line, v->pos, v->value[i]);
 535 
 536         /* FIXME: move to post_std(). */
 537 
 538         if (MDOC_Std == v->arg)
 539                 if ( ! (v->sz || m->meta.name))
 540                         mdoc_nmsg(m, n, MANDOCERR_NONAME);
 541 }
 542 
 543 static void
 544 check_text(struct mdoc *m, int ln, int pos, char *p)
 545 {
 546         char            *cp;
 547 
 548         if (MDOC_LITERAL & m->flags)
 549                 return;
 550 
 551         for (cp = p; NULL != (p = strchr(p, '\t')); p++)
 552                 mdoc_pmsg(m, ln, pos + (int)(p - cp), MANDOCERR_BADTAB);
 553 }
 554 
 555 static int
 556 check_parent(PRE_ARGS, enum mdoct tok, enum mdoc_type t)
 557 {
 558 
 559         assert(n->parent);
 560         if ((MDOC_ROOT == t || tok == n->parent->tok) &&
 561                         (t == n->parent->type))
 562                 return(1);
 563 
 564         mandoc_vmsg(MANDOCERR_SYNTCHILD, mdoc->parse, n->line, 
 565                         n->pos, "want parent %s", MDOC_ROOT == t ? 
 566                         "<root>" : mdoc_macronames[tok]);
 567         return(0);
 568 }
 569 
 570 
 571 static int
 572 pre_display(PRE_ARGS)


 716 
 717                 if (n->norm->Bl.type == LIST__NONE)
 718                         if (n->norm->Bl.width || 
 719                                         n->norm->Bl.offs || 
 720                                         n->norm->Bl.comp)
 721                                 mdoc_nmsg(mdoc, n, MANDOCERR_LISTFIRST);
 722 
 723                 continue;
 724         }
 725 
 726         /* Allow lists to default to LIST_item. */
 727 
 728         if (LIST__NONE == n->norm->Bl.type) {
 729                 mdoc_nmsg(mdoc, n, MANDOCERR_LISTTYPE);
 730                 n->norm->Bl.type = LIST_item;
 731         }
 732 
 733         /* 
 734          * Validate the width field.  Some list types don't need width
 735          * types and should be warned about them.  Others should have it
 736          * and must also be warned.

 737          */
 738 
 739         switch (n->norm->Bl.type) {
 740         case (LIST_tag):
 741                 if (n->norm->Bl.width)
 742                         break;
 743                 mdoc_nmsg(mdoc, n, MANDOCERR_NOWIDTHARG);
 744                 break;
 745         case (LIST_column):
 746                 /* FALLTHROUGH */
 747         case (LIST_diag):
 748                 /* FALLTHROUGH */
 749         case (LIST_ohang):
 750                 /* FALLTHROUGH */
 751         case (LIST_inset):
 752                 /* FALLTHROUGH */
 753         case (LIST_item):
 754                 if (n->norm->Bl.width)
 755                         mdoc_nmsg(mdoc, n, MANDOCERR_IGNARGV);
 756                 break;












 757         default:
 758                 break;
 759         }
 760 
 761         return(1);
 762 }
 763 
 764 
 765 static int
 766 pre_bd(PRE_ARGS)
 767 {
 768         int               i, dup, comp;
 769         enum mdoc_disp    dt;
 770         const char       *offs;
 771         struct mdoc_node *np;
 772 
 773         if (MDOC_BLOCK != n->type) {
 774                 if (ENDBODY_NOT != n->end) {
 775                         assert(n->pending);
 776                         np = n->pending->parent;


 857         return(1);
 858 }
 859 
 860 
 861 static int
 862 pre_ss(PRE_ARGS)
 863 {
 864 
 865         if (MDOC_BLOCK != n->type)
 866                 return(1);
 867         return(check_parent(mdoc, n, MDOC_Sh, MDOC_BODY));
 868 }
 869 
 870 
 871 static int
 872 pre_sh(PRE_ARGS)
 873 {
 874 
 875         if (MDOC_BLOCK != n->type)
 876                 return(1);
 877 
 878         roff_regunset(mdoc->roff, REG_nS);
 879         return(check_parent(mdoc, n, MDOC_MAX, MDOC_ROOT));
 880 }
 881 
 882 
 883 static int
 884 pre_it(PRE_ARGS)
 885 {
 886 
 887         if (MDOC_BLOCK != n->type)
 888                 return(1);
 889 
 890         return(check_parent(mdoc, n, MDOC_Bl, MDOC_BODY));
 891 }
 892 
 893 
 894 static int
 895 pre_an(PRE_ARGS)
 896 {
 897         int              i;
 898 


1094          * specifically the BODY, should only have TEXT children.
1095          */
1096 
1097         if (MDOC_BODY != mdoc->last->type)
1098                 return(1);
1099         
1100         for (n = mdoc->last->child; n; n = n->next)
1101                 if (MDOC_TEXT != n->type) 
1102                         mdoc_nmsg(mdoc, n, MANDOCERR_CHILD);
1103 
1104         return(1);
1105 }
1106 
1107 
1108 static int
1109 post_nm(POST_ARGS)
1110 {
1111         char             buf[BUFSIZ];
1112         int              c;
1113 
1114         /* If no child specified, make sure we have the meta name. */
1115 
1116         if (NULL == mdoc->last->child && NULL == mdoc->meta.name) {
1117                 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NONAME);
1118                 return(1);
1119         } else if (mdoc->meta.name)
1120                 return(1);
1121 
1122         /* If no meta name, set it from the child. */
1123 

1124         buf[0] = '\0';
1125         if (-1 == (c = concat(buf, mdoc->last->child, BUFSIZ))) {





1126                 mdoc_nmsg(mdoc, mdoc->last->child, MANDOCERR_MEM);
1127                 return(0);
1128         }
1129 
1130         assert(c);


1131         mdoc->meta.name = mandoc_strdup(buf);


1132         return(1);
1133 }
1134 
1135 static int
1136 post_literal(POST_ARGS)
1137 {
1138         
1139         /*
1140          * The `Dl' (note "el" not "one") and `Bd' macros unset the
1141          * MDOC_LITERAL flag as they leave.  Note that `Bd' only sets
1142          * this in literal mode, but it doesn't hurt to just switch it
1143          * off in general since displays can't be nested.
1144          */
1145 
1146         if (MDOC_BODY == mdoc->last->type)
1147                 mdoc->flags &= ~MDOC_LITERAL;
1148 
1149         return(1);
1150 }
1151 


1317                         er = MANDOCERR_ARGCOUNT;
1318                 else if (i == cols || i == cols + 1)
1319                         break;
1320                 else
1321                         er = MANDOCERR_SYNTARGCOUNT;
1322 
1323                 mandoc_vmsg(er, mdoc->parse, mdoc->last->line, 
1324                                 mdoc->last->pos, 
1325                                 "columns == %d (have %d)", cols, i);
1326                 return(MANDOCERR_ARGCOUNT == er);
1327         default:
1328                 break;
1329         }
1330 
1331         return(1);
1332 }
1333 
1334 static int
1335 post_bl_block(POST_ARGS) 
1336 {
1337         struct mdoc_node *n;
1338 
1339         /*
1340          * These are fairly complicated, so we've broken them into two
1341          * functions.  post_bl_block_tag() is called when a -tag is
1342          * specified, but no -width (it must be guessed).  The second
1343          * when a -width is specified (macro indicators must be
1344          * rewritten into real lengths).
1345          */
1346 
1347         n = mdoc->last;
1348 
1349         if (LIST_tag == n->norm->Bl.type && 
1350                         NULL == n->norm->Bl.width) {
1351                 if ( ! post_bl_block_tag(mdoc))
1352                         return(0);

1353         } else if (NULL != n->norm->Bl.width) {
1354                 if ( ! post_bl_block_width(mdoc))
1355                         return(0);



























1356         } else 




1357                 return(1);
1358 
1359         assert(n->norm->Bl.width);
1360         return(1);
1361 }
1362 
1363 static int
1364 post_bl_block_width(POST_ARGS)
1365 {
1366         size_t            width;
1367         int               i;
1368         enum mdoct        tok;
1369         struct mdoc_node *n;
1370         char              buf[NUMSIZ];
1371 
1372         n = mdoc->last;
1373 
1374         /*
1375          * Calculate the real width of a list from the -width string,
1376          * which may contain a macro (with a known default width), a
1377          * literal string, or a scaling width.
1378          *
1379          * If the value to -width is a macro, then we re-write it to be
1380          * the macro's width as set in share/tmac/mdoc/doc-common.


1527         mdoc->last->norm->Bl.ncols = np->args->argv[j].sz;
1528         mdoc->last->norm->Bl.cols = (void *)np->args->argv[j].value;
1529 
1530         for (i = 0, nn = mdoc->last->child; nn; i++) {
1531                 np->args->argv[j].value[i] = nn->string;
1532                 nn->string = NULL;
1533                 nnp = nn;
1534                 nn = nn->next;
1535                 mdoc_node_delete(NULL, nnp);
1536         }
1537 
1538         mdoc->last->nchild = 0;
1539         mdoc->last->child = NULL;
1540 
1541         return(1);
1542 }
1543 
1544 static int
1545 post_bl(POST_ARGS)
1546 {
1547         struct mdoc_node        *n;


1548 
1549         if (MDOC_HEAD == mdoc->last->type) 
1550                 return(post_bl_head(mdoc));
1551         if (MDOC_BLOCK == mdoc->last->type)
1552                 return(post_bl_block(mdoc));
1553         if (MDOC_BODY != mdoc->last->type)




1554                 return(1);

1555 
1556         for (n = mdoc->last->child; n; n = n->next) {
1557                 switch (n->tok) {
1558                 case (MDOC_Lp):
1559                         /* FALLTHROUGH */
1560                 case (MDOC_Pp):
1561                         mdoc_nmsg(mdoc, n, MANDOCERR_CHILD);
1562                         /* FALLTHROUGH */
1563                 case (MDOC_It):
1564                         /* FALLTHROUGH */
1565                 case (MDOC_Sm):
1566                         continue;
1567                 default:
1568                         break;
1569                 }
1570 
1571                 mdoc_nmsg(mdoc, n, MANDOCERR_SYNTCHILD);
1572                 return(0);






















1573         }
1574 


















1575         return(1);
1576 }
1577 
1578 static int
1579 ebool(struct mdoc *mdoc)
1580 {
1581 
1582         if (NULL == mdoc->last->child) {
1583                 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_MACROEMPTY);
1584                 mdoc_node_delete(mdoc, mdoc->last);
1585                 return(1);
1586         }
1587         check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 1);
1588 
1589         assert(MDOC_TEXT == mdoc->last->child->type);
1590 
1591         if (0 == strcmp(mdoc->last->child->string, "on"))


1592                 return(1);
1593         if (0 == strcmp(mdoc->last->child->string, "off"))



1594                 return(1);

1595 
1596         mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADBOOL);
1597         return(1);
1598 }
1599 
1600 static int
1601 post_root(POST_ARGS)
1602 {
1603         int               erc;
1604         struct mdoc_node *n;
1605 
1606         erc = 0;
1607 
1608         /* Check that we have a finished prologue. */
1609 
1610         if ( ! (MDOC_PBODY & mdoc->flags)) {
1611                 erc++;
1612                 mdoc_nmsg(mdoc, mdoc->first, MANDOCERR_NODOCPROLOG);
1613         }
1614 


1754                  * of the `prev' node.
1755                  */
1756 
1757                 nn->prev = prev;
1758 
1759                 if (prev) {
1760                         if (prev->next)
1761                                 prev->next->prev = nn;
1762                         nn->next = prev->next;
1763                         prev->next = nn;
1764                 } else {
1765                         mdoc->last->child->prev = nn;
1766                         nn->next = mdoc->last->child;
1767                         mdoc->last->child = nn;
1768                 }
1769         }
1770 
1771         return(1);
1772 }
1773 




1774 static int





































1775 post_ns(POST_ARGS)
1776 {
1777 
1778         if (MDOC_LINE & mdoc->last->flags)
1779                 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_IGNNS);
1780         return(1);
1781 }
1782 
1783 static int
1784 post_sh(POST_ARGS)
1785 {
1786 
1787         if (MDOC_HEAD == mdoc->last->type)
1788                 return(post_sh_head(mdoc));
1789         if (MDOC_BODY == mdoc->last->type)
1790                 return(post_sh_body(mdoc));
1791 
1792         return(1);
1793 }
1794 


1840          * "custom".  Custom sections are user-defined, while named ones
1841          * follow a conventional order and may only appear in certain
1842          * manual sections.
1843          */
1844 
1845         sec = SEC_CUSTOM;
1846         buf[0] = '\0';
1847         if (-1 == (c = concat(buf, mdoc->last->child, BUFSIZ))) {
1848                 mdoc_nmsg(mdoc, mdoc->last->child, MANDOCERR_MEM);
1849                 return(0);
1850         } else if (1 == c)
1851                 sec = a2sec(buf);
1852 
1853         /* The NAME should be first. */
1854 
1855         if (SEC_NAME != sec && SEC_NONE == mdoc->lastnamed)
1856                 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NAMESECFIRST);
1857 
1858         /* The SYNOPSIS gets special attention in other areas. */
1859 
1860         if (SEC_SYNOPSIS == sec)

1861                 mdoc->flags |= MDOC_SYNOPSIS;
1862         else

1863                 mdoc->flags &= ~MDOC_SYNOPSIS;

1864 
1865         /* Mark our last section. */
1866 
1867         mdoc->lastsec = sec;
1868 
1869         /*
1870          * Set the section attribute for the current HEAD, for its
1871          * parent BLOCK, and for the HEAD children; the latter can
1872          * only be TEXT nodes, so no recursion is needed.
1873          * For other blocks and elements, including .Sh BODY, this is
1874          * done when allocating the node data structures, but for .Sh
1875          * BLOCK and HEAD, the section is still unknown at that time.
1876          */
1877 
1878         mdoc->last->parent->sec = sec;
1879         mdoc->last->sec = sec;
1880         for (n = mdoc->last->child; n; n = n->next)
1881                 n->sec = sec;
1882 
1883         /* We don't care about custom sections after this. */


1899         /* Mark the last named section. */
1900 
1901         mdoc->lastnamed = sec;
1902 
1903         /* Check particular section/manual conventions. */
1904 
1905         assert(mdoc->meta.msec);
1906 
1907         switch (sec) {
1908         case (SEC_RETURN_VALUES):
1909                 /* FALLTHROUGH */
1910         case (SEC_ERRORS):
1911                 /* FALLTHROUGH */
1912         case (SEC_LIBRARY):
1913                 if (*mdoc->meta.msec == '2')
1914                         break;
1915                 if (*mdoc->meta.msec == '3')
1916                         break;
1917                 if (*mdoc->meta.msec == '9')
1918                         break;
1919                 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_SECMSEC);

1920                 break;
1921         default:
1922                 break;
1923         }
1924 
1925         return(1);
1926 }
1927 
1928 static int
1929 post_ignpar(POST_ARGS)
1930 {
1931         struct mdoc_node *np;
1932 
1933         if (MDOC_BODY != mdoc->last->type)
1934                 return(1);
1935 
1936         if (NULL != (np = mdoc->last->child))
1937                 if (MDOC_Pp == np->tok || MDOC_Lp == np->tok) {
1938                         mdoc_nmsg(mdoc, np, MANDOCERR_IGNPAR);
1939                         mdoc_node_delete(mdoc, np);


1945                         mdoc_node_delete(mdoc, np);
1946                 }
1947 
1948         return(1);
1949 }
1950 
1951 static int
1952 pre_par(PRE_ARGS)
1953 {
1954 
1955         if (NULL == mdoc->last)
1956                 return(1);
1957         if (MDOC_ELEM != n->type && MDOC_BLOCK != n->type)
1958                 return(1);
1959 
1960         /* 
1961          * Don't allow prior `Lp' or `Pp' prior to a paragraph-type
1962          * block:  `Lp', `Pp', or non-compact `Bd' or `Bl'.
1963          */
1964 
1965         if (MDOC_Pp != mdoc->last->tok && MDOC_Lp != mdoc->last->tok)


1966                 return(1);
1967         if (MDOC_Bl == n->tok && n->norm->Bl.comp)
1968                 return(1);
1969         if (MDOC_Bd == n->tok && n->norm->Bd.comp)
1970                 return(1);
1971         if (MDOC_It == n->tok && n->parent->norm->Bl.comp)
1972                 return(1);
1973 
1974         mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_IGNPAR);
1975         mdoc_node_delete(mdoc, mdoc->last);
1976         return(1);
1977 }
1978 
1979 static int


























1980 pre_literal(PRE_ARGS)
1981 {
1982 
1983         if (MDOC_BODY != n->type)
1984                 return(1);
1985 
1986         /*
1987          * The `Dl' (note "el" not "one") and `Bd -literal' and `Bd
1988          * -unfilled' macros set MDOC_LITERAL on entrance to the body.
1989          */
1990 
1991         switch (n->tok) {
1992         case (MDOC_Dl):
1993                 mdoc->flags |= MDOC_LITERAL;
1994                 break;
1995         case (MDOC_Bd):
1996                 if (DISP_literal == n->norm->Bd.type)
1997                         mdoc->flags |= MDOC_LITERAL;
1998                 if (DISP_unfilled == n->norm->Bd.type)
1999                         mdoc->flags |= MDOC_LITERAL;


2112                 mdoc_nmsg(mdoc, n, MANDOCERR_BADMSEC);
2113                 mdoc->meta.vol = mandoc_strdup(nn->string);
2114                 mdoc->meta.msec = mandoc_strdup(nn->string);
2115         } 
2116 
2117         if (NULL == (nn = nn->next))
2118                 return(1);
2119 
2120         /* Handles: `.Dt TITLE SEC VOL'
2121          *   --> title = TITLE, volume = VOL is vol ?
2122          *       format(VOL) : 
2123          *           VOL is arch ? format(arch) : 
2124          *               VOL
2125          */
2126 
2127         cp = mdoc_a2vol(nn->string);
2128         if (cp) {
2129                 free(mdoc->meta.vol);
2130                 mdoc->meta.vol = mandoc_strdup(cp);
2131         } else {
2132                 /* FIXME: warn about bad arch. */
2133                 cp = mdoc_a2arch(nn->string);
2134                 if (NULL == cp) {

2135                         free(mdoc->meta.vol);
2136                         mdoc->meta.vol = mandoc_strdup(nn->string);
2137                 } else 
2138                         mdoc->meta.arch = mandoc_strdup(cp);
2139         }       
2140 
2141         /* Ignore any subsequent parameters... */
2142         /* FIXME: warn about subsequent parameters. */
2143 
2144         return(1);
2145 }
2146 
2147 static int
2148 post_prol(POST_ARGS)
2149 {
2150         /*
2151          * Remove prologue macros from the document after they're
2152          * processed.  The final document uses mdoc_meta for these
2153          * values and discards the originals.
2154          */


2175         if (n && NULL != (n = n->next))
2176                 *n->string = (char)toupper
2177                         ((unsigned char)*n->string);
2178 
2179         return(1);
2180 }
2181 
2182 static int
2183 post_os(POST_ARGS)
2184 {
2185         struct mdoc_node *n;
2186         char              buf[BUFSIZ];
2187         int               c;
2188 #ifndef OSNAME
2189         struct utsname    utsname;
2190 #endif
2191 
2192         n = mdoc->last;
2193 
2194         /*
2195          * Set the operating system by way of the `Os' macro.  Note that
2196          * if an argument isn't provided and -DOSNAME="\"foo\"" is
2197          * provided during compilation, this value will be used instead
2198          * of filling in "sysname release" from uname().


2199          */
2200 
2201         if (mdoc->meta.os)
2202                 free(mdoc->meta.os);
2203 
2204         buf[0] = '\0';
2205         if (-1 == (c = concat(buf, n->child, BUFSIZ))) {
2206                 mdoc_nmsg(mdoc, n->child, MANDOCERR_MEM);
2207                 return(0);
2208         }
2209 
2210         assert(c);
2211 
2212         /* XXX: yes, these can all be dynamically-adjusted buffers, but
2213          * it's really not worth the extra hackery.
2214          */
2215 
2216         if ('\0' == buf[0]) {




2217 #ifdef OSNAME
2218                 if (strlcat(buf, OSNAME, BUFSIZ) >= BUFSIZ) {
2219                         mdoc_nmsg(mdoc, n, MANDOCERR_MEM);
2220                         return(0);
2221                 }
2222 #else /*!OSNAME */
2223                 if (-1 == uname(&utsname)) {
2224                         mdoc_nmsg(mdoc, n, MANDOCERR_UNAME);
2225                         mdoc->meta.os = mandoc_strdup("UNKNOWN");
2226                         return(post_prol(mdoc));
2227                 }
2228 
2229                 if (strlcat(buf, utsname.sysname, BUFSIZ) >= BUFSIZ) {
2230                         mdoc_nmsg(mdoc, n, MANDOCERR_MEM);
2231                         return(0);
2232                 }
2233                 if (strlcat(buf, " ", BUFSIZ) >= BUFSIZ) {
2234                         mdoc_nmsg(mdoc, n, MANDOCERR_MEM);
2235                         return(0);
2236                 }


   1 /*      $Id: mdoc_validate.c,v 1.198 2013/12/15 21:23:52 schwarze Exp $ */
   2 /*
   3  * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
   4  * Copyright (c) 2010, 2011, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org>
   5  *
   6  * Permission to use, copy, modify, and distribute this software for any
   7  * purpose with or without fee is hereby granted, provided that the above
   8  * copyright notice and this permission notice appear in all copies.
   9  *
  10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  17  */
  18 #ifdef HAVE_CONFIG_H
  19 #include "config.h"
  20 #endif
  21 
  22 #ifndef OSNAME
  23 #include <sys/utsname.h>
  24 #endif


  80 static  int      berr_ge1(POST_ARGS);
  81 static  int      bwarn_ge1(POST_ARGS);
  82 static  int      ewarn_eq0(POST_ARGS);
  83 static  int      ewarn_eq1(POST_ARGS);
  84 static  int      ewarn_ge1(POST_ARGS);
  85 static  int      ewarn_le1(POST_ARGS);
  86 static  int      hwarn_eq0(POST_ARGS);
  87 static  int      hwarn_eq1(POST_ARGS);
  88 static  int      hwarn_ge1(POST_ARGS);
  89 static  int      hwarn_le1(POST_ARGS);
  90 
  91 static  int      post_an(POST_ARGS);
  92 static  int      post_at(POST_ARGS);
  93 static  int      post_bf(POST_ARGS);
  94 static  int      post_bl(POST_ARGS);
  95 static  int      post_bl_block(POST_ARGS);
  96 static  int      post_bl_block_width(POST_ARGS);
  97 static  int      post_bl_block_tag(POST_ARGS);
  98 static  int      post_bl_head(POST_ARGS);
  99 static  int      post_bx(POST_ARGS);
 100 static  int      post_defaults(POST_ARGS);
 101 static  int      post_dd(POST_ARGS);
 102 static  int      post_dt(POST_ARGS);


 103 static  int      post_eoln(POST_ARGS);
 104 static  int      post_hyph(POST_ARGS);
 105 static  int      post_ignpar(POST_ARGS);
 106 static  int      post_it(POST_ARGS);
 107 static  int      post_lb(POST_ARGS);
 108 static  int      post_literal(POST_ARGS);
 109 static  int      post_nm(POST_ARGS);
 110 static  int      post_ns(POST_ARGS);
 111 static  int      post_os(POST_ARGS);
 112 static  int      post_par(POST_ARGS);
 113 static  int      post_prol(POST_ARGS);
 114 static  int      post_root(POST_ARGS);
 115 static  int      post_rs(POST_ARGS);
 116 static  int      post_sh(POST_ARGS);
 117 static  int      post_sh_body(POST_ARGS);
 118 static  int      post_sh_head(POST_ARGS);
 119 static  int      post_st(POST_ARGS);
 120 static  int      post_std(POST_ARGS);
 121 static  int      post_vt(POST_ARGS);
 122 static  int      pre_an(PRE_ARGS);
 123 static  int      pre_bd(PRE_ARGS);
 124 static  int      pre_bl(PRE_ARGS);
 125 static  int      pre_dd(PRE_ARGS);
 126 static  int      pre_display(PRE_ARGS);
 127 static  int      pre_dt(PRE_ARGS);
 128 static  int      pre_it(PRE_ARGS);
 129 static  int      pre_literal(PRE_ARGS);
 130 static  int      pre_os(PRE_ARGS);
 131 static  int      pre_par(PRE_ARGS);
 132 static  int      pre_sh(PRE_ARGS);
 133 static  int      pre_ss(PRE_ARGS);
 134 static  int      pre_std(PRE_ARGS);
 135 
 136 static  v_post   posts_an[] = { post_an, NULL };
 137 static  v_post   posts_at[] = { post_at, post_defaults, NULL };
 138 static  v_post   posts_bd[] = { post_literal, hwarn_eq0, bwarn_ge1, NULL };
 139 static  v_post   posts_bf[] = { hwarn_le1, post_bf, NULL };
 140 static  v_post   posts_bk[] = { hwarn_eq0, bwarn_ge1, NULL };
 141 static  v_post   posts_bl[] = { bwarn_ge1, post_bl, NULL };
 142 static  v_post   posts_bx[] = { post_bx, NULL };
 143 static  v_post   posts_bool[] = { ebool, NULL };
 144 static  v_post   posts_eoln[] = { post_eoln, NULL };
 145 static  v_post   posts_defaults[] = { post_defaults, NULL };
 146 static  v_post   posts_d1[] = { bwarn_ge1, post_hyph, NULL };
 147 static  v_post   posts_dd[] = { post_dd, post_prol, NULL };
 148 static  v_post   posts_dl[] = { post_literal, bwarn_ge1, NULL };
 149 static  v_post   posts_dt[] = { post_dt, post_prol, NULL };
 150 static  v_post   posts_fo[] = { hwarn_eq1, bwarn_ge1, NULL };
 151 static  v_post   posts_hyph[] = { post_hyph, NULL };
 152 static  v_post   posts_hyphtext[] = { ewarn_ge1, post_hyph, NULL };
 153 static  v_post   posts_it[] = { post_it, NULL };
 154 static  v_post   posts_lb[] = { post_lb, NULL };
 155 static  v_post   posts_nd[] = { berr_ge1, post_hyph, NULL };
 156 static  v_post   posts_nm[] = { post_nm, NULL };
 157 static  v_post   posts_notext[] = { ewarn_eq0, NULL };
 158 static  v_post   posts_ns[] = { post_ns, NULL };
 159 static  v_post   posts_os[] = { post_os, post_prol, NULL };
 160 static  v_post   posts_pp[] = { post_par, ewarn_eq0, NULL };
 161 static  v_post   posts_rs[] = { post_rs, NULL };
 162 static  v_post   posts_sh[] = { post_ignpar,hwarn_ge1,post_sh,post_hyph,NULL };
 163 static  v_post   posts_sp[] = { post_par, ewarn_le1, NULL };
 164 static  v_post   posts_ss[] = { post_ignpar, hwarn_ge1, post_hyph, NULL };
 165 static  v_post   posts_st[] = { post_st, NULL };
 166 static  v_post   posts_std[] = { post_std, NULL };
 167 static  v_post   posts_text[] = { ewarn_ge1, NULL };
 168 static  v_post   posts_text1[] = { ewarn_eq1, NULL };
 169 static  v_post   posts_vt[] = { post_vt, NULL };

 170 static  v_pre    pres_an[] = { pre_an, NULL };
 171 static  v_pre    pres_bd[] = { pre_display, pre_bd, pre_literal, pre_par, NULL };
 172 static  v_pre    pres_bl[] = { pre_bl, pre_par, NULL };
 173 static  v_pre    pres_d1[] = { pre_display, NULL };
 174 static  v_pre    pres_dl[] = { pre_literal, pre_display, NULL };
 175 static  v_pre    pres_dd[] = { pre_dd, NULL };
 176 static  v_pre    pres_dt[] = { pre_dt, NULL };


 177 static  v_pre    pres_it[] = { pre_it, pre_par, NULL };
 178 static  v_pre    pres_os[] = { pre_os, NULL };
 179 static  v_pre    pres_pp[] = { pre_par, NULL };
 180 static  v_pre    pres_sh[] = { pre_sh, NULL };
 181 static  v_pre    pres_ss[] = { pre_ss, NULL };
 182 static  v_pre    pres_std[] = { pre_std, NULL };
 183 
 184 static  const struct valids mdoc_valids[MDOC_MAX] = {
 185         { NULL, NULL },                         /* Ap */
 186         { pres_dd, posts_dd },                  /* Dd */
 187         { pres_dt, posts_dt },                  /* Dt */
 188         { pres_os, posts_os },                  /* Os */
 189         { pres_sh, posts_sh },                  /* Sh */ 
 190         { pres_ss, posts_ss },                  /* Ss */ 
 191         { pres_pp, posts_pp },                  /* Pp */ 
 192         { pres_d1, posts_d1 },                  /* D1 */
 193         { pres_dl, posts_dl },                  /* Dl */
 194         { pres_bd, posts_bd },                  /* Bd */
 195         { NULL, NULL },                         /* Ed */
 196         { pres_bl, posts_bl },                  /* Bl */ 
 197         { NULL, NULL },                         /* El */
 198         { pres_it, posts_it },                  /* It */
 199         { NULL, NULL },                         /* Ad */ 
 200         { pres_an, posts_an },                  /* An */ 
 201         { NULL, posts_defaults },               /* Ar */
 202         { NULL, NULL },                         /* Cd */ 
 203         { NULL, NULL },                         /* Cm */
 204         { NULL, NULL },                         /* Dv */ 
 205         { NULL, NULL },                         /* Er */ 
 206         { NULL, NULL },                         /* Ev */ 
 207         { pres_std, posts_std },                /* Ex */ 
 208         { NULL, NULL },                         /* Fa */ 
 209         { NULL, posts_text },                   /* Fd */
 210         { NULL, NULL },                         /* Fl */
 211         { NULL, NULL },                         /* Fn */ 
 212         { NULL, NULL },                         /* Ft */ 
 213         { NULL, NULL },                         /* Ic */ 
 214         { NULL, posts_text1 },                  /* In */ 
 215         { NULL, posts_defaults },               /* Li */
 216         { NULL, posts_nd },                     /* Nd */
 217         { NULL, posts_nm },                     /* Nm */
 218         { NULL, NULL },                         /* Op */
 219         { NULL, NULL },                         /* Ot */
 220         { NULL, posts_defaults },               /* Pa */
 221         { pres_std, posts_std },                /* Rv */
 222         { NULL, posts_st },                     /* St */ 
 223         { NULL, NULL },                         /* Va */
 224         { NULL, posts_vt },                     /* Vt */ 
 225         { NULL, posts_text },                   /* Xr */ 
 226         { NULL, posts_text },                   /* %A */
 227         { NULL, posts_hyphtext },               /* %B */ /* FIXME: can be used outside Rs/Re. */
 228         { NULL, posts_text },                   /* %D */
 229         { NULL, posts_text },                   /* %I */
 230         { NULL, posts_text },                   /* %J */
 231         { NULL, posts_hyphtext },               /* %N */
 232         { NULL, posts_hyphtext },               /* %O */
 233         { NULL, posts_text },                   /* %P */
 234         { NULL, posts_hyphtext },               /* %R */
 235         { NULL, posts_hyphtext },               /* %T */ /* FIXME: can be used outside Rs/Re. */
 236         { NULL, posts_text },                   /* %V */
 237         { NULL, NULL },                         /* Ac */
 238         { NULL, NULL },                         /* Ao */
 239         { NULL, NULL },                         /* Aq */
 240         { NULL, posts_at },                     /* At */ 
 241         { NULL, NULL },                         /* Bc */
 242         { NULL, posts_bf },                     /* Bf */
 243         { NULL, NULL },                         /* Bo */
 244         { NULL, NULL },                         /* Bq */
 245         { NULL, NULL },                         /* Bsx */
 246         { NULL, posts_bx },                     /* Bx */
 247         { NULL, posts_bool },                   /* Db */
 248         { NULL, NULL },                         /* Dc */
 249         { NULL, NULL },                         /* Do */
 250         { NULL, NULL },                         /* Dq */
 251         { NULL, NULL },                         /* Ec */
 252         { NULL, NULL },                         /* Ef */ 
 253         { NULL, NULL },                         /* Em */ 
 254         { NULL, NULL },                         /* Eo */
 255         { NULL, NULL },                         /* Fx */
 256         { NULL, NULL },                         /* Ms */ 
 257         { NULL, posts_notext },                 /* No */
 258         { NULL, posts_ns },                     /* Ns */
 259         { NULL, NULL },                         /* Nx */
 260         { NULL, NULL },                         /* Ox */
 261         { NULL, NULL },                         /* Pc */
 262         { NULL, posts_text1 },                  /* Pf */
 263         { NULL, NULL },                         /* Po */
 264         { NULL, NULL },                         /* Pq */
 265         { NULL, NULL },                         /* Qc */
 266         { NULL, NULL },                         /* Ql */
 267         { NULL, NULL },                         /* Qo */
 268         { NULL, NULL },                         /* Qq */
 269         { NULL, NULL },                         /* Re */
 270         { NULL, posts_rs },                     /* Rs */
 271         { NULL, NULL },                         /* Sc */
 272         { NULL, NULL },                         /* So */
 273         { NULL, NULL },                         /* Sq */
 274         { NULL, posts_bool },                   /* Sm */ 
 275         { NULL, posts_hyph },                   /* Sx */
 276         { NULL, NULL },                         /* Sy */
 277         { NULL, NULL },                         /* Tn */
 278         { NULL, NULL },                         /* Ux */
 279         { NULL, NULL },                         /* Xc */
 280         { NULL, NULL },                         /* Xo */
 281         { NULL, posts_fo },                     /* Fo */ 
 282         { NULL, NULL },                         /* Fc */ 
 283         { NULL, NULL },                         /* Oo */
 284         { NULL, NULL },                         /* Oc */
 285         { NULL, posts_bk },                     /* Bk */
 286         { NULL, NULL },                         /* Ek */
 287         { NULL, posts_eoln },                   /* Bt */
 288         { NULL, NULL },                         /* Hf */
 289         { NULL, NULL },                         /* Fr */
 290         { NULL, posts_eoln },                   /* Ud */
 291         { NULL, posts_lb },                     /* Lb */
 292         { pres_pp, posts_pp },                  /* Lp */ 
 293         { NULL, NULL },                         /* Lk */ 
 294         { NULL, posts_defaults },               /* Mt */ 
 295         { NULL, NULL },                         /* Brq */ 
 296         { NULL, NULL },                         /* Bro */ 
 297         { NULL, NULL },                         /* Brc */ 
 298         { NULL, posts_text },                   /* %C */
 299         { NULL, NULL },                         /* Es */
 300         { NULL, NULL },                         /* En */
 301         { NULL, NULL },                         /* Dx */
 302         { NULL, posts_text },                   /* %Q */
 303         { NULL, posts_pp },                     /* br */
 304         { NULL, posts_sp },                     /* sp */
 305         { NULL, posts_text1 },                  /* %U */
 306         { NULL, NULL },                         /* Ta */
 307 };
 308 
 309 #define RSORD_MAX 14 /* Number of `Rs' blocks. */
 310 
 311 static  const enum mdoct rsord[RSORD_MAX] = {
 312         MDOC__A,
 313         MDOC__T,
 314         MDOC__B,
 315         MDOC__I,
 316         MDOC__J,
 317         MDOC__R,
 318         MDOC__N,
 319         MDOC__V,
 320         MDOC__U,
 321         MDOC__P,
 322         MDOC__Q,


 323         MDOC__C,
 324         MDOC__D,
 325         MDOC__O
 326 };
 327 
 328 static  const char * const secnames[SEC__MAX] = {
 329         NULL,
 330         "NAME",
 331         "LIBRARY",
 332         "SYNOPSIS",
 333         "DESCRIPTION",
 334         "IMPLEMENTATION NOTES",
 335         "RETURN VALUES",
 336         "ENVIRONMENT",
 337         "FILES",
 338         "EXIT STATUS",
 339         "EXAMPLES",
 340         "DIAGNOSTICS",
 341         "COMPATIBILITY",
 342         "ERRORS",
 343         "SEE ALSO",
 344         "STANDARDS",
 345         "HISTORY",


 400         case (MDOC_EQN):
 401                 /* FALLTHROUGH */
 402         case (MDOC_TBL):
 403                 return(1);
 404         case (MDOC_ROOT):
 405                 return(post_root(mdoc));
 406         default:
 407                 break;
 408         }
 409 
 410         if (NULL == mdoc_valids[mdoc->last->tok].post)
 411                 return(1);
 412         for (p = mdoc_valids[mdoc->last->tok].post; *p; p++)
 413                 if ( ! (*p)(mdoc)) 
 414                         return(0);
 415 
 416         return(1);
 417 }
 418 
 419 static int
 420 check_count(struct mdoc *mdoc, enum mdoc_type type, 
 421                 enum check_lvl lvl, enum check_ineq ineq, int val)
 422 {
 423         const char      *p;
 424         enum mandocerr   t;
 425 
 426         if (mdoc->last->type != type)
 427                 return(1);
 428         
 429         switch (ineq) {
 430         case (CHECK_LT):
 431                 p = "less than ";
 432                 if (mdoc->last->nchild < val)
 433                         return(1);
 434                 break;
 435         case (CHECK_GT):
 436                 p = "more than ";
 437                 if (mdoc->last->nchild > val)
 438                         return(1);
 439                 break;
 440         case (CHECK_EQ):
 441                 p = "";
 442                 if (val == mdoc->last->nchild)
 443                         return(1);
 444                 break;
 445         default:
 446                 abort();
 447                 /* NOTREACHED */
 448         }
 449 
 450         t = lvl == CHECK_WARN ? MANDOCERR_ARGCWARN : MANDOCERR_ARGCOUNT;
 451         mandoc_vmsg(t, mdoc->parse, mdoc->last->line, mdoc->last->pos,
 452                         "want %s%d children (have %d)",
 453                         p, val, mdoc->last->nchild);
 454         return(1);
 455 }
 456 
 457 static int
 458 berr_ge1(POST_ARGS)
 459 {
 460 
 461         return(check_count(mdoc, MDOC_BODY, CHECK_ERROR, CHECK_GT, 0));
 462 }
 463 
 464 static int
 465 bwarn_ge1(POST_ARGS)
 466 {
 467         return(check_count(mdoc, MDOC_BODY, CHECK_WARN, CHECK_GT, 0));
 468 }
 469 
 470 static int
 471 ewarn_eq0(POST_ARGS)
 472 {
 473         return(check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 0));


 499 
 500 static int
 501 hwarn_eq1(POST_ARGS)
 502 {
 503         return(check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_EQ, 1));
 504 }
 505 
 506 static int
 507 hwarn_ge1(POST_ARGS)
 508 {
 509         return(check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_GT, 0));
 510 }
 511 
 512 static int
 513 hwarn_le1(POST_ARGS)
 514 {
 515         return(check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_LT, 2));
 516 }
 517 
 518 static void
 519 check_args(struct mdoc *mdoc, struct mdoc_node *n)
 520 {
 521         int              i;
 522 
 523         if (NULL == n->args)
 524                 return;
 525 
 526         assert(n->args->argc);
 527         for (i = 0; i < (int)n->args->argc; i++)
 528                 check_argv(mdoc, n, &n->args->argv[i]);
 529 }
 530 
 531 static void
 532 check_argv(struct mdoc *mdoc, struct mdoc_node *n, struct mdoc_argv *v)
 533 {
 534         int              i;
 535 
 536         for (i = 0; i < (int)v->sz; i++)
 537                 check_text(mdoc, v->line, v->pos, v->value[i]);
 538 
 539         /* FIXME: move to post_std(). */
 540 
 541         if (MDOC_Std == v->arg)
 542                 if ( ! (v->sz || mdoc->meta.name))
 543                         mdoc_nmsg(mdoc, n, MANDOCERR_NONAME);
 544 }
 545 
 546 static void
 547 check_text(struct mdoc *mdoc, int ln, int pos, char *p)
 548 {
 549         char            *cp;
 550 
 551         if (MDOC_LITERAL & mdoc->flags)
 552                 return;
 553 
 554         for (cp = p; NULL != (p = strchr(p, '\t')); p++)
 555                 mdoc_pmsg(mdoc, ln, pos + (int)(p - cp), MANDOCERR_BADTAB);
 556 }
 557 
 558 static int
 559 check_parent(PRE_ARGS, enum mdoct tok, enum mdoc_type t)
 560 {
 561 
 562         assert(n->parent);
 563         if ((MDOC_ROOT == t || tok == n->parent->tok) &&
 564                         (t == n->parent->type))
 565                 return(1);
 566 
 567         mandoc_vmsg(MANDOCERR_SYNTCHILD, mdoc->parse, n->line, 
 568                         n->pos, "want parent %s", MDOC_ROOT == t ? 
 569                         "<root>" : mdoc_macronames[tok]);
 570         return(0);
 571 }
 572 
 573 
 574 static int
 575 pre_display(PRE_ARGS)


 719 
 720                 if (n->norm->Bl.type == LIST__NONE)
 721                         if (n->norm->Bl.width || 
 722                                         n->norm->Bl.offs || 
 723                                         n->norm->Bl.comp)
 724                                 mdoc_nmsg(mdoc, n, MANDOCERR_LISTFIRST);
 725 
 726                 continue;
 727         }
 728 
 729         /* Allow lists to default to LIST_item. */
 730 
 731         if (LIST__NONE == n->norm->Bl.type) {
 732                 mdoc_nmsg(mdoc, n, MANDOCERR_LISTTYPE);
 733                 n->norm->Bl.type = LIST_item;
 734         }
 735 
 736         /* 
 737          * Validate the width field.  Some list types don't need width
 738          * types and should be warned about them.  Others should have it
 739          * and must also be warned.  Yet others have a default and need
 740          * no warning.
 741          */
 742 
 743         switch (n->norm->Bl.type) {
 744         case (LIST_tag):
 745                 if (NULL == n->norm->Bl.width)

 746                         mdoc_nmsg(mdoc, n, MANDOCERR_NOWIDTHARG);
 747                 break;
 748         case (LIST_column):
 749                 /* FALLTHROUGH */
 750         case (LIST_diag):
 751                 /* FALLTHROUGH */
 752         case (LIST_ohang):
 753                 /* FALLTHROUGH */
 754         case (LIST_inset):
 755                 /* FALLTHROUGH */
 756         case (LIST_item):
 757                 if (n->norm->Bl.width)
 758                         mdoc_nmsg(mdoc, n, MANDOCERR_IGNARGV);
 759                 break;
 760         case (LIST_bullet):
 761                 /* FALLTHROUGH */
 762         case (LIST_dash):
 763                 /* FALLTHROUGH */
 764         case (LIST_hyphen):
 765                 if (NULL == n->norm->Bl.width)
 766                         n->norm->Bl.width = "2n";
 767                 break;
 768         case (LIST_enum):
 769                 if (NULL == n->norm->Bl.width)
 770                         n->norm->Bl.width = "3n";
 771                 break;
 772         default:
 773                 break;
 774         }
 775 
 776         return(1);
 777 }
 778 
 779 
 780 static int
 781 pre_bd(PRE_ARGS)
 782 {
 783         int               i, dup, comp;
 784         enum mdoc_disp    dt;
 785         const char       *offs;
 786         struct mdoc_node *np;
 787 
 788         if (MDOC_BLOCK != n->type) {
 789                 if (ENDBODY_NOT != n->end) {
 790                         assert(n->pending);
 791                         np = n->pending->parent;


 872         return(1);
 873 }
 874 
 875 
 876 static int
 877 pre_ss(PRE_ARGS)
 878 {
 879 
 880         if (MDOC_BLOCK != n->type)
 881                 return(1);
 882         return(check_parent(mdoc, n, MDOC_Sh, MDOC_BODY));
 883 }
 884 
 885 
 886 static int
 887 pre_sh(PRE_ARGS)
 888 {
 889 
 890         if (MDOC_BLOCK != n->type)
 891                 return(1);


 892         return(check_parent(mdoc, n, MDOC_MAX, MDOC_ROOT));
 893 }
 894 
 895 
 896 static int
 897 pre_it(PRE_ARGS)
 898 {
 899 
 900         if (MDOC_BLOCK != n->type)
 901                 return(1);
 902 
 903         return(check_parent(mdoc, n, MDOC_Bl, MDOC_BODY));
 904 }
 905 
 906 
 907 static int
 908 pre_an(PRE_ARGS)
 909 {
 910         int              i;
 911 


1107          * specifically the BODY, should only have TEXT children.
1108          */
1109 
1110         if (MDOC_BODY != mdoc->last->type)
1111                 return(1);
1112         
1113         for (n = mdoc->last->child; n; n = n->next)
1114                 if (MDOC_TEXT != n->type) 
1115                         mdoc_nmsg(mdoc, n, MANDOCERR_CHILD);
1116 
1117         return(1);
1118 }
1119 
1120 
1121 static int
1122 post_nm(POST_ARGS)
1123 {
1124         char             buf[BUFSIZ];
1125         int              c;
1126 
1127         if (NULL != mdoc->meta.name)



1128                 return(1);


1129 
1130         /* Try to use our children for setting the meta name. */
1131 
1132         if (NULL != mdoc->last->child) {
1133                 buf[0] = '\0';
1134                 c = concat(buf, mdoc->last->child, BUFSIZ);
1135         } else
1136                 c = 0;
1137 
1138         switch (c) {
1139         case (-1):
1140                 mdoc_nmsg(mdoc, mdoc->last->child, MANDOCERR_MEM);
1141                 return(0);
1142         case (0):
1143                 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NONAME);
1144                 mdoc->meta.name = mandoc_strdup("UNKNOWN");
1145                 break;
1146         default:
1147                 mdoc->meta.name = mandoc_strdup(buf);
1148                 break;
1149         }
1150         return(1);
1151 }
1152 
1153 static int
1154 post_literal(POST_ARGS)
1155 {
1156         
1157         /*
1158          * The `Dl' (note "el" not "one") and `Bd' macros unset the
1159          * MDOC_LITERAL flag as they leave.  Note that `Bd' only sets
1160          * this in literal mode, but it doesn't hurt to just switch it
1161          * off in general since displays can't be nested.
1162          */
1163 
1164         if (MDOC_BODY == mdoc->last->type)
1165                 mdoc->flags &= ~MDOC_LITERAL;
1166 
1167         return(1);
1168 }
1169 


1335                         er = MANDOCERR_ARGCOUNT;
1336                 else if (i == cols || i == cols + 1)
1337                         break;
1338                 else
1339                         er = MANDOCERR_SYNTARGCOUNT;
1340 
1341                 mandoc_vmsg(er, mdoc->parse, mdoc->last->line, 
1342                                 mdoc->last->pos, 
1343                                 "columns == %d (have %d)", cols, i);
1344                 return(MANDOCERR_ARGCOUNT == er);
1345         default:
1346                 break;
1347         }
1348 
1349         return(1);
1350 }
1351 
1352 static int
1353 post_bl_block(POST_ARGS) 
1354 {
1355         struct mdoc_node *n, *ni, *nc;
1356 
1357         /*
1358          * These are fairly complicated, so we've broken them into two
1359          * functions.  post_bl_block_tag() is called when a -tag is
1360          * specified, but no -width (it must be guessed).  The second
1361          * when a -width is specified (macro indicators must be
1362          * rewritten into real lengths).
1363          */
1364 
1365         n = mdoc->last;
1366 
1367         if (LIST_tag == n->norm->Bl.type && 
1368                         NULL == n->norm->Bl.width) {
1369                 if ( ! post_bl_block_tag(mdoc))
1370                         return(0);
1371                 assert(n->norm->Bl.width);
1372         } else if (NULL != n->norm->Bl.width) {
1373                 if ( ! post_bl_block_width(mdoc))
1374                         return(0);
1375                 assert(n->norm->Bl.width);
1376         }
1377 
1378         for (ni = n->body->child; ni; ni = ni->next) {
1379                 if (NULL == ni->body)
1380                         continue;
1381                 nc = ni->body->last;
1382                 while (NULL != nc) {
1383                         switch (nc->tok) {
1384                         case (MDOC_Pp):
1385                                 /* FALLTHROUGH */
1386                         case (MDOC_Lp):
1387                                 /* FALLTHROUGH */
1388                         case (MDOC_br):
1389                                 break;
1390                         default:
1391                                 nc = NULL;
1392                                 continue;
1393                         }
1394                         if (NULL == ni->next) {
1395                                 mdoc_nmsg(mdoc, nc, MANDOCERR_MOVEPAR);
1396                                 if ( ! mdoc_node_relink(mdoc, nc))
1397                                         return(0);
1398                         } else if (0 == n->norm->Bl.comp &&
1399                             LIST_column != n->norm->Bl.type) {
1400                                 mdoc_nmsg(mdoc, nc, MANDOCERR_IGNPAR);
1401                                 mdoc_node_delete(mdoc, nc);
1402                         } else
1403                                 break;
1404                         nc = ni->body->last;
1405                 }
1406         }
1407         return(1);



1408 }
1409 
1410 static int
1411 post_bl_block_width(POST_ARGS)
1412 {
1413         size_t            width;
1414         int               i;
1415         enum mdoct        tok;
1416         struct mdoc_node *n;
1417         char              buf[NUMSIZ];
1418 
1419         n = mdoc->last;
1420 
1421         /*
1422          * Calculate the real width of a list from the -width string,
1423          * which may contain a macro (with a known default width), a
1424          * literal string, or a scaling width.
1425          *
1426          * If the value to -width is a macro, then we re-write it to be
1427          * the macro's width as set in share/tmac/mdoc/doc-common.


1574         mdoc->last->norm->Bl.ncols = np->args->argv[j].sz;
1575         mdoc->last->norm->Bl.cols = (void *)np->args->argv[j].value;
1576 
1577         for (i = 0, nn = mdoc->last->child; nn; i++) {
1578                 np->args->argv[j].value[i] = nn->string;
1579                 nn->string = NULL;
1580                 nnp = nn;
1581                 nn = nn->next;
1582                 mdoc_node_delete(NULL, nnp);
1583         }
1584 
1585         mdoc->last->nchild = 0;
1586         mdoc->last->child = NULL;
1587 
1588         return(1);
1589 }
1590 
1591 static int
1592 post_bl(POST_ARGS)
1593 {
1594         struct mdoc_node        *nparent, *nprev; /* of the Bl block */
1595         struct mdoc_node        *nblock, *nbody;  /* of the Bl */
1596         struct mdoc_node        *nchild, *nnext;  /* of the Bl body */
1597 
1598         nbody = mdoc->last;
1599         switch (nbody->type) {
1600         case (MDOC_BLOCK):
1601                 return(post_bl_block(mdoc));
1602         case (MDOC_HEAD):
1603                 return(post_bl_head(mdoc));
1604         case (MDOC_BODY):
1605                 break;
1606         default:
1607                 return(1);
1608         }
1609 
1610         nchild = nbody->child;
1611         while (NULL != nchild) {
1612                 if (MDOC_It == nchild->tok || MDOC_Sm == nchild->tok) {
1613                         nchild = nchild->next;






1614                         continue;


1615                 }
1616 
1617                 mdoc_nmsg(mdoc, nchild, MANDOCERR_CHILD);
1618 
1619                 /*
1620                  * Move the node out of the Bl block.
1621                  * First, collect all required node pointers.
1622                  */
1623 
1624                 nblock  = nbody->parent;
1625                 nprev   = nblock->prev;
1626                 nparent = nblock->parent;
1627                 nnext   = nchild->next;
1628 
1629                 /*
1630                  * Unlink this child.
1631                  */
1632 
1633                 assert(NULL == nchild->prev);
1634                 if (0 == --nbody->nchild) {
1635                         nbody->child = NULL;
1636                         nbody->last  = NULL;
1637                         assert(NULL == nnext);
1638                 } else {
1639                         nbody->child = nnext;
1640                         nnext->prev = NULL;
1641                 }
1642 
1643                 /*
1644                  * Relink this child.
1645                  */
1646 
1647                 nchild->parent = nparent;
1648                 nchild->prev   = nprev;
1649                 nchild->next   = nblock;
1650 
1651                 nblock->prev = nchild;
1652                 nparent->nchild++;
1653                 if (NULL == nprev)
1654                         nparent->child = nchild;
1655                 else
1656                         nprev->next = nchild;
1657 
1658                 nchild = nnext;
1659         }
1660 
1661         return(1);
1662 }
1663 
1664 static int
1665 ebool(struct mdoc *mdoc)
1666 {
1667 
1668         if (NULL == mdoc->last->child) {
1669                 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_MACROEMPTY);
1670                 mdoc_node_delete(mdoc, mdoc->last);
1671                 return(1);
1672         }
1673         check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 1);
1674 
1675         assert(MDOC_TEXT == mdoc->last->child->type);
1676 
1677         if (0 == strcmp(mdoc->last->child->string, "on")) {
1678                 if (MDOC_Sm == mdoc->last->tok)
1679                         mdoc->flags &= ~MDOC_SMOFF;
1680                 return(1);
1681         }
1682         if (0 == strcmp(mdoc->last->child->string, "off")) {
1683                 if (MDOC_Sm == mdoc->last->tok)
1684                         mdoc->flags |= MDOC_SMOFF;
1685                 return(1);
1686         }
1687 
1688         mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADBOOL);
1689         return(1);
1690 }
1691 
1692 static int
1693 post_root(POST_ARGS)
1694 {
1695         int               erc;
1696         struct mdoc_node *n;
1697 
1698         erc = 0;
1699 
1700         /* Check that we have a finished prologue. */
1701 
1702         if ( ! (MDOC_PBODY & mdoc->flags)) {
1703                 erc++;
1704                 mdoc_nmsg(mdoc, mdoc->first, MANDOCERR_NODOCPROLOG);
1705         }
1706 


1846                  * of the `prev' node.
1847                  */
1848 
1849                 nn->prev = prev;
1850 
1851                 if (prev) {
1852                         if (prev->next)
1853                                 prev->next->prev = nn;
1854                         nn->next = prev->next;
1855                         prev->next = nn;
1856                 } else {
1857                         mdoc->last->child->prev = nn;
1858                         nn->next = mdoc->last->child;
1859                         mdoc->last->child = nn;
1860                 }
1861         }
1862 
1863         return(1);
1864 }
1865 
1866 /*
1867  * For some arguments of some macros,
1868  * convert all breakable hyphens into ASCII_HYPH.
1869  */
1870 static int
1871 post_hyph(POST_ARGS)
1872 {
1873         struct mdoc_node        *n, *nch;
1874         char                    *cp;
1875 
1876         n = mdoc->last;
1877         switch (n->type) {
1878         case (MDOC_HEAD):
1879                 if (MDOC_Sh == n->tok || MDOC_Ss == n->tok)
1880                         break;
1881                 return(1);
1882         case (MDOC_BODY):
1883                 if (MDOC_D1 == n->tok || MDOC_Nd == n->tok)
1884                         break;
1885                 return(1);
1886         case (MDOC_ELEM):
1887                 break;
1888         default:
1889                 return(1);
1890         }
1891 
1892         for (nch = n->child; nch; nch = nch->next) {
1893                 if (MDOC_TEXT != nch->type)
1894                         continue;
1895                 cp = nch->string;
1896                 if (3 > strnlen(cp, 3))
1897                         continue;
1898                 while ('\0' != *(++cp))
1899                         if ('-' == *cp &&
1900                             isalpha((unsigned char)cp[-1]) &&
1901                             isalpha((unsigned char)cp[1]))
1902                                 *cp = ASCII_HYPH;
1903         }
1904         return(1);
1905 }
1906 
1907 static int
1908 post_ns(POST_ARGS)
1909 {
1910 
1911         if (MDOC_LINE & mdoc->last->flags)
1912                 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_IGNNS);
1913         return(1);
1914 }
1915 
1916 static int
1917 post_sh(POST_ARGS)
1918 {
1919 
1920         if (MDOC_HEAD == mdoc->last->type)
1921                 return(post_sh_head(mdoc));
1922         if (MDOC_BODY == mdoc->last->type)
1923                 return(post_sh_body(mdoc));
1924 
1925         return(1);
1926 }
1927 


1973          * "custom".  Custom sections are user-defined, while named ones
1974          * follow a conventional order and may only appear in certain
1975          * manual sections.
1976          */
1977 
1978         sec = SEC_CUSTOM;
1979         buf[0] = '\0';
1980         if (-1 == (c = concat(buf, mdoc->last->child, BUFSIZ))) {
1981                 mdoc_nmsg(mdoc, mdoc->last->child, MANDOCERR_MEM);
1982                 return(0);
1983         } else if (1 == c)
1984                 sec = a2sec(buf);
1985 
1986         /* The NAME should be first. */
1987 
1988         if (SEC_NAME != sec && SEC_NONE == mdoc->lastnamed)
1989                 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NAMESECFIRST);
1990 
1991         /* The SYNOPSIS gets special attention in other areas. */
1992 
1993         if (SEC_SYNOPSIS == sec) {
1994                 roff_setreg(mdoc->roff, "nS", 1, '=');
1995                 mdoc->flags |= MDOC_SYNOPSIS;
1996         } else {
1997                 roff_setreg(mdoc->roff, "nS", 0, '=');
1998                 mdoc->flags &= ~MDOC_SYNOPSIS;
1999         }
2000 
2001         /* Mark our last section. */
2002 
2003         mdoc->lastsec = sec;
2004 
2005         /*
2006          * Set the section attribute for the current HEAD, for its
2007          * parent BLOCK, and for the HEAD children; the latter can
2008          * only be TEXT nodes, so no recursion is needed.
2009          * For other blocks and elements, including .Sh BODY, this is
2010          * done when allocating the node data structures, but for .Sh
2011          * BLOCK and HEAD, the section is still unknown at that time.
2012          */
2013 
2014         mdoc->last->parent->sec = sec;
2015         mdoc->last->sec = sec;
2016         for (n = mdoc->last->child; n; n = n->next)
2017                 n->sec = sec;
2018 
2019         /* We don't care about custom sections after this. */


2035         /* Mark the last named section. */
2036 
2037         mdoc->lastnamed = sec;
2038 
2039         /* Check particular section/manual conventions. */
2040 
2041         assert(mdoc->meta.msec);
2042 
2043         switch (sec) {
2044         case (SEC_RETURN_VALUES):
2045                 /* FALLTHROUGH */
2046         case (SEC_ERRORS):
2047                 /* FALLTHROUGH */
2048         case (SEC_LIBRARY):
2049                 if (*mdoc->meta.msec == '2')
2050                         break;
2051                 if (*mdoc->meta.msec == '3')
2052                         break;
2053                 if (*mdoc->meta.msec == '9')
2054                         break;
2055                 mandoc_msg(MANDOCERR_SECMSEC, mdoc->parse,
2056                                 mdoc->last->line, mdoc->last->pos, buf);
2057                 break;
2058         default:
2059                 break;
2060         }
2061 
2062         return(1);
2063 }
2064 
2065 static int
2066 post_ignpar(POST_ARGS)
2067 {
2068         struct mdoc_node *np;
2069 
2070         if (MDOC_BODY != mdoc->last->type)
2071                 return(1);
2072 
2073         if (NULL != (np = mdoc->last->child))
2074                 if (MDOC_Pp == np->tok || MDOC_Lp == np->tok) {
2075                         mdoc_nmsg(mdoc, np, MANDOCERR_IGNPAR);
2076                         mdoc_node_delete(mdoc, np);


2082                         mdoc_node_delete(mdoc, np);
2083                 }
2084 
2085         return(1);
2086 }
2087 
2088 static int
2089 pre_par(PRE_ARGS)
2090 {
2091 
2092         if (NULL == mdoc->last)
2093                 return(1);
2094         if (MDOC_ELEM != n->type && MDOC_BLOCK != n->type)
2095                 return(1);
2096 
2097         /* 
2098          * Don't allow prior `Lp' or `Pp' prior to a paragraph-type
2099          * block:  `Lp', `Pp', or non-compact `Bd' or `Bl'.
2100          */
2101 
2102         if (MDOC_Pp != mdoc->last->tok &&
2103             MDOC_Lp != mdoc->last->tok &&
2104             MDOC_br != mdoc->last->tok)
2105                 return(1);
2106         if (MDOC_Bl == n->tok && n->norm->Bl.comp)
2107                 return(1);
2108         if (MDOC_Bd == n->tok && n->norm->Bd.comp)
2109                 return(1);
2110         if (MDOC_It == n->tok && n->parent->norm->Bl.comp)
2111                 return(1);
2112 
2113         mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_IGNPAR);
2114         mdoc_node_delete(mdoc, mdoc->last);
2115         return(1);
2116 }
2117 
2118 static int
2119 post_par(POST_ARGS)
2120 {
2121 
2122         if (MDOC_ELEM != mdoc->last->type &&
2123             MDOC_BLOCK != mdoc->last->type)
2124                 return(1);
2125 
2126         if (NULL == mdoc->last->prev) {
2127                 if (MDOC_Sh != mdoc->last->parent->tok &&
2128                     MDOC_Ss != mdoc->last->parent->tok)
2129                         return(1);
2130         } else {
2131                 if (MDOC_Pp != mdoc->last->prev->tok &&
2132                     MDOC_Lp != mdoc->last->prev->tok &&
2133                     (MDOC_br != mdoc->last->tok ||
2134                      (MDOC_sp != mdoc->last->prev->tok &&
2135                       MDOC_br != mdoc->last->prev->tok)))
2136                         return(1);
2137         }
2138 
2139         mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_IGNPAR);
2140         mdoc_node_delete(mdoc, mdoc->last);
2141         return(1);
2142 }
2143 
2144 static int
2145 pre_literal(PRE_ARGS)
2146 {
2147 
2148         if (MDOC_BODY != n->type)
2149                 return(1);
2150 
2151         /*
2152          * The `Dl' (note "el" not "one") and `Bd -literal' and `Bd
2153          * -unfilled' macros set MDOC_LITERAL on entrance to the body.
2154          */
2155 
2156         switch (n->tok) {
2157         case (MDOC_Dl):
2158                 mdoc->flags |= MDOC_LITERAL;
2159                 break;
2160         case (MDOC_Bd):
2161                 if (DISP_literal == n->norm->Bd.type)
2162                         mdoc->flags |= MDOC_LITERAL;
2163                 if (DISP_unfilled == n->norm->Bd.type)
2164                         mdoc->flags |= MDOC_LITERAL;


2277                 mdoc_nmsg(mdoc, n, MANDOCERR_BADMSEC);
2278                 mdoc->meta.vol = mandoc_strdup(nn->string);
2279                 mdoc->meta.msec = mandoc_strdup(nn->string);
2280         } 
2281 
2282         if (NULL == (nn = nn->next))
2283                 return(1);
2284 
2285         /* Handles: `.Dt TITLE SEC VOL'
2286          *   --> title = TITLE, volume = VOL is vol ?
2287          *       format(VOL) : 
2288          *           VOL is arch ? format(arch) : 
2289          *               VOL
2290          */
2291 
2292         cp = mdoc_a2vol(nn->string);
2293         if (cp) {
2294                 free(mdoc->meta.vol);
2295                 mdoc->meta.vol = mandoc_strdup(cp);
2296         } else {

2297                 cp = mdoc_a2arch(nn->string);
2298                 if (NULL == cp) {
2299                         mdoc_nmsg(mdoc, nn, MANDOCERR_BADVOLARCH);
2300                         free(mdoc->meta.vol);
2301                         mdoc->meta.vol = mandoc_strdup(nn->string);
2302                 } else 
2303                         mdoc->meta.arch = mandoc_strdup(cp);
2304         }       
2305 
2306         /* Ignore any subsequent parameters... */
2307         /* FIXME: warn about subsequent parameters. */
2308 
2309         return(1);
2310 }
2311 
2312 static int
2313 post_prol(POST_ARGS)
2314 {
2315         /*
2316          * Remove prologue macros from the document after they're
2317          * processed.  The final document uses mdoc_meta for these
2318          * values and discards the originals.
2319          */


2340         if (n && NULL != (n = n->next))
2341                 *n->string = (char)toupper
2342                         ((unsigned char)*n->string);
2343 
2344         return(1);
2345 }
2346 
2347 static int
2348 post_os(POST_ARGS)
2349 {
2350         struct mdoc_node *n;
2351         char              buf[BUFSIZ];
2352         int               c;
2353 #ifndef OSNAME
2354         struct utsname    utsname;
2355 #endif
2356 
2357         n = mdoc->last;
2358 
2359         /*
2360          * Set the operating system by way of the `Os' macro.
2361          * The order of precedence is:
2362          * 1. the argument of the `Os' macro, unless empty
2363          * 2. the -Ios=foo command line argument, if provided
2364          * 3. -DOSNAME="\"foo\"", if provided during compilation
2365          * 4. "sysname release" from uname(3)
2366          */
2367 

2368         free(mdoc->meta.os);
2369 
2370         buf[0] = '\0';
2371         if (-1 == (c = concat(buf, n->child, BUFSIZ))) {
2372                 mdoc_nmsg(mdoc, n->child, MANDOCERR_MEM);
2373                 return(0);
2374         }
2375 
2376         assert(c);
2377 




2378         if ('\0' == buf[0]) {
2379                 if (mdoc->defos) {
2380                         mdoc->meta.os = mandoc_strdup(mdoc->defos);
2381                         return(1);
2382                 }
2383 #ifdef OSNAME
2384                 if (strlcat(buf, OSNAME, BUFSIZ) >= BUFSIZ) {
2385                         mdoc_nmsg(mdoc, n, MANDOCERR_MEM);
2386                         return(0);
2387                 }
2388 #else /*!OSNAME */
2389                 if (-1 == uname(&utsname)) {
2390                         mdoc_nmsg(mdoc, n, MANDOCERR_UNAME);
2391                         mdoc->meta.os = mandoc_strdup("UNKNOWN");
2392                         return(post_prol(mdoc));
2393                 }
2394 
2395                 if (strlcat(buf, utsname.sysname, BUFSIZ) >= BUFSIZ) {
2396                         mdoc_nmsg(mdoc, n, MANDOCERR_MEM);
2397                         return(0);
2398                 }
2399                 if (strlcat(buf, " ", BUFSIZ) >= BUFSIZ) {
2400                         mdoc_nmsg(mdoc, n, MANDOCERR_MEM);
2401                         return(0);
2402                 }