1*b31af00dSschwarze /* $Id: mdoc_validate.c,v 1.59 2010/06/06 18:08:41 schwarze Exp $ */ 2f73abda9Skristaps /* 350e63e03Sschwarze * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@bsd.lv> 4f73abda9Skristaps * 5f73abda9Skristaps * Permission to use, copy, modify, and distribute this software for any 6a6464425Sschwarze * purpose with or without fee is hereby granted, provided that the above 7a6464425Sschwarze * copyright notice and this permission notice appear in all copies. 8f73abda9Skristaps * 9a6464425Sschwarze * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10a6464425Sschwarze * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11a6464425Sschwarze * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12a6464425Sschwarze * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13a6464425Sschwarze * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14a6464425Sschwarze * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15a6464425Sschwarze * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16f73abda9Skristaps */ 17f73abda9Skristaps #include <sys/types.h> 18f73abda9Skristaps 19f73abda9Skristaps #include <assert.h> 20f73abda9Skristaps #include <ctype.h> 21d92dc4efSschwarze #include <limits.h> 223216dddfSschwarze #include <stdio.h> 23f73abda9Skristaps #include <stdlib.h> 24f73abda9Skristaps #include <string.h> 25f73abda9Skristaps 266e03d529Sschwarze #include "mandoc.h" 27f73abda9Skristaps #include "libmdoc.h" 28f6854d5cSschwarze #include "libmandoc.h" 29f73abda9Skristaps 30f73abda9Skristaps /* FIXME: .Bl -diag can't have non-text children in HEAD. */ 31f73abda9Skristaps /* TODO: ignoring Pp (it's superfluous in some invocations). */ 32f73abda9Skristaps 33f73abda9Skristaps #define PRE_ARGS struct mdoc *mdoc, const struct mdoc_node *n 34f73abda9Skristaps #define POST_ARGS struct mdoc *mdoc 35f73abda9Skristaps 36f73abda9Skristaps typedef int (*v_pre)(PRE_ARGS); 37f73abda9Skristaps typedef int (*v_post)(POST_ARGS); 38f73abda9Skristaps 39f73abda9Skristaps struct valids { 40f73abda9Skristaps v_pre *pre; 41f73abda9Skristaps v_post *post; 42f73abda9Skristaps }; 43f73abda9Skristaps 44dd94fa3aSschwarze static int check_parent(PRE_ARGS, enum mdoct, enum mdoc_type); 45f73abda9Skristaps static int check_stdarg(PRE_ARGS); 46f73abda9Skristaps static int check_text(struct mdoc *, int, int, const char *); 47f73abda9Skristaps static int check_argv(struct mdoc *, 48f73abda9Skristaps const struct mdoc_node *, 49f73abda9Skristaps const struct mdoc_argv *); 50f73abda9Skristaps static int check_args(struct mdoc *, 51f73abda9Skristaps const struct mdoc_node *); 52f73abda9Skristaps static int err_child_lt(struct mdoc *, const char *, int); 53f73abda9Skristaps static int warn_child_lt(struct mdoc *, const char *, int); 54f73abda9Skristaps static int err_child_gt(struct mdoc *, const char *, int); 55f73abda9Skristaps static int warn_child_gt(struct mdoc *, const char *, int); 56f73abda9Skristaps static int err_child_eq(struct mdoc *, const char *, int); 57f73abda9Skristaps static int warn_child_eq(struct mdoc *, const char *, int); 58f73abda9Skristaps static int warn_count(struct mdoc *, const char *, 59f73abda9Skristaps int, const char *, int); 60f73abda9Skristaps static int err_count(struct mdoc *, const char *, 61f73abda9Skristaps int, const char *, int); 6267c719adSschwarze 6367c719adSschwarze static int berr_ge1(POST_ARGS); 6467c719adSschwarze static int bwarn_ge1(POST_ARGS); 6567c719adSschwarze static int ebool(POST_ARGS); 6667c719adSschwarze static int eerr_eq0(POST_ARGS); 6767c719adSschwarze static int eerr_eq1(POST_ARGS); 6867c719adSschwarze static int eerr_ge1(POST_ARGS); 694175bdabSschwarze static int eerr_le1(POST_ARGS); 7067c719adSschwarze static int ewarn_ge1(POST_ARGS); 7167c719adSschwarze static int herr_eq0(POST_ARGS); 7267c719adSschwarze static int herr_ge1(POST_ARGS); 7367c719adSschwarze static int hwarn_eq1(POST_ARGS); 74b16e7ddfSschwarze static int hwarn_eq0(POST_ARGS); 7567c719adSschwarze static int hwarn_le1(POST_ARGS); 7667c719adSschwarze 7767c719adSschwarze static int post_an(POST_ARGS); 7867c719adSschwarze static int post_at(POST_ARGS); 7967c719adSschwarze static int post_bf(POST_ARGS); 8067c719adSschwarze static int post_bl(POST_ARGS); 8167c719adSschwarze static int post_bl_head(POST_ARGS); 8267c719adSschwarze static int post_it(POST_ARGS); 8367c719adSschwarze static int post_lb(POST_ARGS); 8467c719adSschwarze static int post_nm(POST_ARGS); 8567c719adSschwarze static int post_root(POST_ARGS); 86011fe33bSschwarze static int post_rs(POST_ARGS); 8767c719adSschwarze static int post_sh(POST_ARGS); 8867c719adSschwarze static int post_sh_body(POST_ARGS); 8967c719adSschwarze static int post_sh_head(POST_ARGS); 9067c719adSschwarze static int post_st(POST_ARGS); 91*b31af00dSschwarze static int post_eoln(POST_ARGS); 928521b0bcSschwarze static int post_vt(POST_ARGS); 93f73abda9Skristaps static int pre_an(PRE_ARGS); 94f73abda9Skristaps static int pre_bd(PRE_ARGS); 95f73abda9Skristaps static int pre_bl(PRE_ARGS); 96f73abda9Skristaps static int pre_dd(PRE_ARGS); 97f73abda9Skristaps static int pre_display(PRE_ARGS); 98f73abda9Skristaps static int pre_dt(PRE_ARGS); 99f73abda9Skristaps static int pre_it(PRE_ARGS); 100f73abda9Skristaps static int pre_os(PRE_ARGS); 101f73abda9Skristaps static int pre_rv(PRE_ARGS); 102f73abda9Skristaps static int pre_sh(PRE_ARGS); 103f73abda9Skristaps static int pre_ss(PRE_ARGS); 104f73abda9Skristaps 10567c719adSschwarze static v_post posts_an[] = { post_an, NULL }; 10667c719adSschwarze static v_post posts_at[] = { post_at, NULL }; 107b16e7ddfSschwarze static v_post posts_bd[] = { hwarn_eq0, bwarn_ge1, NULL }; 10867c719adSschwarze static v_post posts_bf[] = { hwarn_le1, post_bf, NULL }; 10967c719adSschwarze static v_post posts_bl[] = { bwarn_ge1, post_bl, NULL }; 11067c719adSschwarze static v_post posts_bool[] = { eerr_eq1, ebool, NULL }; 111*b31af00dSschwarze static v_post posts_eoln[] = { post_eoln, NULL }; 11267c719adSschwarze static v_post posts_fo[] = { hwarn_eq1, bwarn_ge1, NULL }; 11367c719adSschwarze static v_post posts_it[] = { post_it, NULL }; 11467c719adSschwarze static v_post posts_lb[] = { eerr_eq1, post_lb, NULL }; 11567c719adSschwarze static v_post posts_nd[] = { berr_ge1, NULL }; 11667c719adSschwarze static v_post posts_nm[] = { post_nm, NULL }; 11767c719adSschwarze static v_post posts_notext[] = { eerr_eq0, NULL }; 118011fe33bSschwarze static v_post posts_rs[] = { berr_ge1, herr_eq0, post_rs, NULL }; 11967c719adSschwarze static v_post posts_sh[] = { herr_ge1, bwarn_ge1, post_sh, NULL }; 1204175bdabSschwarze static v_post posts_sp[] = { eerr_le1, NULL }; 12167c719adSschwarze static v_post posts_ss[] = { herr_ge1, NULL }; 12267c719adSschwarze static v_post posts_st[] = { eerr_eq1, post_st, NULL }; 12367c719adSschwarze static v_post posts_text[] = { eerr_ge1, NULL }; 124b822ca0dSschwarze static v_post posts_text1[] = { eerr_eq1, NULL }; 1258521b0bcSschwarze static v_post posts_vt[] = { post_vt, NULL }; 12667c719adSschwarze static v_post posts_wline[] = { bwarn_ge1, herr_eq0, NULL }; 12767c719adSschwarze static v_post posts_wtext[] = { ewarn_ge1, NULL }; 128f73abda9Skristaps static v_pre pres_an[] = { pre_an, NULL }; 129f73abda9Skristaps static v_pre pres_bd[] = { pre_display, pre_bd, NULL }; 130f73abda9Skristaps static v_pre pres_bl[] = { pre_bl, NULL }; 131f73abda9Skristaps static v_pre pres_d1[] = { pre_display, NULL }; 13267c719adSschwarze static v_pre pres_dd[] = { pre_dd, NULL }; 1336be99f77Sschwarze static v_pre pres_dt[] = { pre_dt, NULL }; 134b16e7ddfSschwarze static v_pre pres_er[] = { NULL, NULL }; 135974b5ecdSschwarze static v_pre pres_ex[] = { NULL, NULL }; 136974b5ecdSschwarze static v_pre pres_fd[] = { NULL, NULL }; 137f73abda9Skristaps static v_pre pres_it[] = { pre_it, NULL }; 1386be99f77Sschwarze static v_pre pres_os[] = { pre_os, NULL }; 139f73abda9Skristaps static v_pre pres_rv[] = { pre_rv, NULL }; 140f73abda9Skristaps static v_pre pres_sh[] = { pre_sh, NULL }; 141f73abda9Skristaps static v_pre pres_ss[] = { pre_ss, NULL }; 142f73abda9Skristaps 143f73abda9Skristaps const struct valids mdoc_valids[MDOC_MAX] = { 144099cfa7eSschwarze { NULL, NULL }, /* Ap */ 145f73abda9Skristaps { pres_dd, posts_text }, /* Dd */ 146f73abda9Skristaps { pres_dt, NULL }, /* Dt */ 147f73abda9Skristaps { pres_os, NULL }, /* Os */ 148f73abda9Skristaps { pres_sh, posts_sh }, /* Sh */ 149f73abda9Skristaps { pres_ss, posts_ss }, /* Ss */ 150d92dc4efSschwarze { NULL, posts_notext }, /* Pp */ 151f73abda9Skristaps { pres_d1, posts_wline }, /* D1 */ 152f73abda9Skristaps { pres_d1, posts_wline }, /* Dl */ 153f73abda9Skristaps { pres_bd, posts_bd }, /* Bd */ 154f73abda9Skristaps { NULL, NULL }, /* Ed */ 155f73abda9Skristaps { pres_bl, posts_bl }, /* Bl */ 156f73abda9Skristaps { NULL, NULL }, /* El */ 157f73abda9Skristaps { pres_it, posts_it }, /* It */ 158f73abda9Skristaps { NULL, posts_text }, /* Ad */ 159f73abda9Skristaps { pres_an, posts_an }, /* An */ 160f73abda9Skristaps { NULL, NULL }, /* Ar */ 161a4c002ecSschwarze { NULL, posts_text }, /* Cd */ 162f73abda9Skristaps { NULL, NULL }, /* Cm */ 163f73abda9Skristaps { NULL, NULL }, /* Dv */ 164f73abda9Skristaps { pres_er, posts_text }, /* Er */ 165f73abda9Skristaps { NULL, NULL }, /* Ev */ 16654263317Sschwarze { pres_ex, NULL }, /* Ex */ 167f73abda9Skristaps { NULL, NULL }, /* Fa */ 168f73abda9Skristaps { pres_fd, posts_wtext }, /* Fd */ 169f73abda9Skristaps { NULL, NULL }, /* Fl */ 170f73abda9Skristaps { NULL, posts_text }, /* Fn */ 171f73abda9Skristaps { NULL, posts_wtext }, /* Ft */ 172f73abda9Skristaps { NULL, posts_text }, /* Ic */ 173b822ca0dSschwarze { NULL, posts_text1 }, /* In */ 174f73abda9Skristaps { NULL, NULL }, /* Li */ 1754602e85cSschwarze { NULL, posts_nd }, /* Nd */ 176f73abda9Skristaps { NULL, posts_nm }, /* Nm */ 177f73abda9Skristaps { NULL, posts_wline }, /* Op */ 178f73abda9Skristaps { NULL, NULL }, /* Ot */ 179f73abda9Skristaps { NULL, NULL }, /* Pa */ 18054263317Sschwarze { pres_rv, NULL }, /* Rv */ 181f73abda9Skristaps { NULL, posts_st }, /* St */ 182f73abda9Skristaps { NULL, NULL }, /* Va */ 1838521b0bcSschwarze { NULL, posts_vt }, /* Vt */ 184*b31af00dSschwarze { NULL, posts_wtext }, /* Xr */ 185f73abda9Skristaps { NULL, posts_text }, /* %A */ 1864175bdabSschwarze { NULL, posts_text }, /* %B */ /* FIXME: can be used outside Rs/Re. */ 187aa2d850aSschwarze { NULL, posts_text }, /* %D */ /* FIXME: check date with mandoc_a2time(). */ 188f73abda9Skristaps { NULL, posts_text }, /* %I */ 189f73abda9Skristaps { NULL, posts_text }, /* %J */ 190f73abda9Skristaps { NULL, posts_text }, /* %N */ 191f73abda9Skristaps { NULL, posts_text }, /* %O */ 192f73abda9Skristaps { NULL, posts_text }, /* %P */ 193f73abda9Skristaps { NULL, posts_text }, /* %R */ 1944175bdabSschwarze { NULL, posts_text }, /* %T */ /* FIXME: can be used outside Rs/Re. */ 195f73abda9Skristaps { NULL, posts_text }, /* %V */ 196f73abda9Skristaps { NULL, NULL }, /* Ac */ 197f73abda9Skristaps { NULL, NULL }, /* Ao */ 198f73abda9Skristaps { NULL, posts_wline }, /* Aq */ 199f73abda9Skristaps { NULL, posts_at }, /* At */ 200f73abda9Skristaps { NULL, NULL }, /* Bc */ 201f73abda9Skristaps { NULL, posts_bf }, /* Bf */ 202f73abda9Skristaps { NULL, NULL }, /* Bo */ 203f73abda9Skristaps { NULL, posts_wline }, /* Bq */ 204f73abda9Skristaps { NULL, NULL }, /* Bsx */ 205f73abda9Skristaps { NULL, NULL }, /* Bx */ 206f73abda9Skristaps { NULL, posts_bool }, /* Db */ 207f73abda9Skristaps { NULL, NULL }, /* Dc */ 208f73abda9Skristaps { NULL, NULL }, /* Do */ 209f73abda9Skristaps { NULL, posts_wline }, /* Dq */ 210f73abda9Skristaps { NULL, NULL }, /* Ec */ 211f73abda9Skristaps { NULL, NULL }, /* Ef */ 212f73abda9Skristaps { NULL, NULL }, /* Em */ 213f73abda9Skristaps { NULL, NULL }, /* Eo */ 214f73abda9Skristaps { NULL, NULL }, /* Fx */ 215f73abda9Skristaps { NULL, posts_text }, /* Ms */ 216f73abda9Skristaps { NULL, posts_notext }, /* No */ 217f73abda9Skristaps { NULL, posts_notext }, /* Ns */ 218f73abda9Skristaps { NULL, NULL }, /* Nx */ 219f73abda9Skristaps { NULL, NULL }, /* Ox */ 220f73abda9Skristaps { NULL, NULL }, /* Pc */ 221b822ca0dSschwarze { NULL, posts_text1 }, /* Pf */ 222f73abda9Skristaps { NULL, NULL }, /* Po */ 223f73abda9Skristaps { NULL, posts_wline }, /* Pq */ 224f73abda9Skristaps { NULL, NULL }, /* Qc */ 225f73abda9Skristaps { NULL, posts_wline }, /* Ql */ 226f73abda9Skristaps { NULL, NULL }, /* Qo */ 227f73abda9Skristaps { NULL, posts_wline }, /* Qq */ 228f73abda9Skristaps { NULL, NULL }, /* Re */ 229011fe33bSschwarze { NULL, posts_rs }, /* Rs */ 230f73abda9Skristaps { NULL, NULL }, /* Sc */ 231f73abda9Skristaps { NULL, NULL }, /* So */ 232f73abda9Skristaps { NULL, posts_wline }, /* Sq */ 233f73abda9Skristaps { NULL, posts_bool }, /* Sm */ 234f73abda9Skristaps { NULL, posts_text }, /* Sx */ 235f73abda9Skristaps { NULL, posts_text }, /* Sy */ 236f73abda9Skristaps { NULL, posts_text }, /* Tn */ 237f73abda9Skristaps { NULL, NULL }, /* Ux */ 238f73abda9Skristaps { NULL, NULL }, /* Xc */ 239f73abda9Skristaps { NULL, NULL }, /* Xo */ 240f73abda9Skristaps { NULL, posts_fo }, /* Fo */ 241f73abda9Skristaps { NULL, NULL }, /* Fc */ 242f73abda9Skristaps { NULL, NULL }, /* Oo */ 243f73abda9Skristaps { NULL, NULL }, /* Oc */ 244f73abda9Skristaps { NULL, posts_wline }, /* Bk */ 245f73abda9Skristaps { NULL, NULL }, /* Ek */ 246*b31af00dSschwarze { NULL, posts_eoln }, /* Bt */ 247f73abda9Skristaps { NULL, NULL }, /* Hf */ 248f73abda9Skristaps { NULL, NULL }, /* Fr */ 249*b31af00dSschwarze { NULL, posts_eoln }, /* Ud */ 250*b31af00dSschwarze { NULL, posts_lb }, /* Lb */ 251d92dc4efSschwarze { NULL, posts_notext }, /* Lp */ 252b822ca0dSschwarze { NULL, posts_text }, /* Lk */ 253f73abda9Skristaps { NULL, posts_text }, /* Mt */ 254f73abda9Skristaps { NULL, posts_wline }, /* Brq */ 255f73abda9Skristaps { NULL, NULL }, /* Bro */ 256f73abda9Skristaps { NULL, NULL }, /* Brc */ 257f73abda9Skristaps { NULL, posts_text }, /* %C */ 258f73abda9Skristaps { NULL, NULL }, /* Es */ 259f73abda9Skristaps { NULL, NULL }, /* En */ 260f73abda9Skristaps { NULL, NULL }, /* Dx */ 261f73abda9Skristaps { NULL, posts_text }, /* %Q */ 262d92dc4efSschwarze { NULL, posts_notext }, /* br */ 263d92dc4efSschwarze { NULL, posts_sp }, /* sp */ 264b822ca0dSschwarze { NULL, posts_text1 }, /* %U */ 265f73abda9Skristaps }; 266f73abda9Skristaps 267f73abda9Skristaps 268f73abda9Skristaps int 26967c719adSschwarze mdoc_valid_pre(struct mdoc *mdoc, const struct mdoc_node *n) 270f73abda9Skristaps { 271f73abda9Skristaps v_pre *p; 272f73abda9Skristaps int line, pos; 273f73abda9Skristaps const char *tp; 274f73abda9Skristaps 275f73abda9Skristaps if (MDOC_TEXT == n->type) { 276f73abda9Skristaps tp = n->string; 277f73abda9Skristaps line = n->line; 278f73abda9Skristaps pos = n->pos; 279f73abda9Skristaps return(check_text(mdoc, line, pos, tp)); 280f73abda9Skristaps } 281f73abda9Skristaps 282f73abda9Skristaps if ( ! check_args(mdoc, n)) 283f73abda9Skristaps return(0); 284f73abda9Skristaps if (NULL == mdoc_valids[n->tok].pre) 285f73abda9Skristaps return(1); 286f73abda9Skristaps for (p = mdoc_valids[n->tok].pre; *p; p++) 287f73abda9Skristaps if ( ! (*p)(mdoc, n)) 288f73abda9Skristaps return(0); 289f73abda9Skristaps return(1); 290f73abda9Skristaps } 291f73abda9Skristaps 292f73abda9Skristaps 293f73abda9Skristaps int 294f73abda9Skristaps mdoc_valid_post(struct mdoc *mdoc) 295f73abda9Skristaps { 296f73abda9Skristaps v_post *p; 297f73abda9Skristaps 298f73abda9Skristaps if (MDOC_VALID & mdoc->last->flags) 299f73abda9Skristaps return(1); 300f73abda9Skristaps mdoc->last->flags |= MDOC_VALID; 301f73abda9Skristaps 302f73abda9Skristaps if (MDOC_TEXT == mdoc->last->type) 303f73abda9Skristaps return(1); 304f73abda9Skristaps if (MDOC_ROOT == mdoc->last->type) 305f73abda9Skristaps return(post_root(mdoc)); 306f73abda9Skristaps 307f73abda9Skristaps if (NULL == mdoc_valids[mdoc->last->tok].post) 308f73abda9Skristaps return(1); 309f73abda9Skristaps for (p = mdoc_valids[mdoc->last->tok].post; *p; p++) 310f73abda9Skristaps if ( ! (*p)(mdoc)) 311f73abda9Skristaps return(0); 312f73abda9Skristaps 313f73abda9Skristaps return(1); 314f73abda9Skristaps } 315f73abda9Skristaps 316f73abda9Skristaps 317f73abda9Skristaps static inline int 318f73abda9Skristaps warn_count(struct mdoc *m, const char *k, 319f73abda9Skristaps int want, const char *v, int has) 320f73abda9Skristaps { 321f73abda9Skristaps 3226e03d529Sschwarze return(mdoc_vmsg(m, MANDOCERR_ARGCOUNT, 3236e03d529Sschwarze m->last->line, m->last->pos, 3246e03d529Sschwarze "%s %s %d (have %d)", v, k, want, has)); 325f73abda9Skristaps } 326f73abda9Skristaps 327f73abda9Skristaps 328f73abda9Skristaps static inline int 329f73abda9Skristaps err_count(struct mdoc *m, const char *k, 330f73abda9Skristaps int want, const char *v, int has) 331f73abda9Skristaps { 332f73abda9Skristaps 3336e03d529Sschwarze mdoc_vmsg(m, MANDOCERR_SYNTARGCOUNT, 3346e03d529Sschwarze m->last->line, m->last->pos, 3356e03d529Sschwarze "%s %s %d (have %d)", 3366e03d529Sschwarze v, k, want, has); 3376e03d529Sschwarze return(0); 338f73abda9Skristaps } 339f73abda9Skristaps 340f73abda9Skristaps 341f73abda9Skristaps /* 342f73abda9Skristaps * Build these up with macros because they're basically the same check 343f73abda9Skristaps * for different inequalities. Yes, this could be done with functions, 344f73abda9Skristaps * but this is reasonable for now. 345f73abda9Skristaps */ 346f73abda9Skristaps 347f73abda9Skristaps #define CHECK_CHILD_DEFN(lvl, name, ineq) \ 348f73abda9Skristaps static int \ 349f73abda9Skristaps lvl##_child_##name(struct mdoc *mdoc, const char *p, int sz) \ 350f73abda9Skristaps { \ 351afdf0540Sschwarze if (mdoc->last->nchild ineq sz) \ 352f73abda9Skristaps return(1); \ 353afdf0540Sschwarze return(lvl##_count(mdoc, #ineq, sz, p, mdoc->last->nchild)); \ 354f73abda9Skristaps } 355f73abda9Skristaps 356f73abda9Skristaps #define CHECK_BODY_DEFN(name, lvl, func, num) \ 357f73abda9Skristaps static int \ 358f73abda9Skristaps b##lvl##_##name(POST_ARGS) \ 359f73abda9Skristaps { \ 360f73abda9Skristaps if (MDOC_BODY != mdoc->last->type) \ 361f73abda9Skristaps return(1); \ 362f73abda9Skristaps return(func(mdoc, "multi-line arguments", (num))); \ 363f73abda9Skristaps } 364f73abda9Skristaps 365f73abda9Skristaps #define CHECK_ELEM_DEFN(name, lvl, func, num) \ 366f73abda9Skristaps static int \ 367f73abda9Skristaps e##lvl##_##name(POST_ARGS) \ 368f73abda9Skristaps { \ 369f73abda9Skristaps assert(MDOC_ELEM == mdoc->last->type); \ 370f73abda9Skristaps return(func(mdoc, "line arguments", (num))); \ 371f73abda9Skristaps } 372f73abda9Skristaps 373f73abda9Skristaps #define CHECK_HEAD_DEFN(name, lvl, func, num) \ 374f73abda9Skristaps static int \ 375f73abda9Skristaps h##lvl##_##name(POST_ARGS) \ 376f73abda9Skristaps { \ 377f73abda9Skristaps if (MDOC_HEAD != mdoc->last->type) \ 378f73abda9Skristaps return(1); \ 379f73abda9Skristaps return(func(mdoc, "line arguments", (num))); \ 380f73abda9Skristaps } 381f73abda9Skristaps 382f73abda9Skristaps 383f73abda9Skristaps CHECK_CHILD_DEFN(warn, gt, >) /* warn_child_gt() */ 384f73abda9Skristaps CHECK_CHILD_DEFN(err, gt, >) /* err_child_gt() */ 385f73abda9Skristaps CHECK_CHILD_DEFN(warn, eq, ==) /* warn_child_eq() */ 386f73abda9Skristaps CHECK_CHILD_DEFN(err, eq, ==) /* err_child_eq() */ 387f73abda9Skristaps CHECK_CHILD_DEFN(err, lt, <) /* err_child_lt() */ 388f73abda9Skristaps CHECK_CHILD_DEFN(warn, lt, <) /* warn_child_lt() */ 389f73abda9Skristaps CHECK_BODY_DEFN(ge1, warn, warn_child_gt, 0) /* bwarn_ge1() */ 3904602e85cSschwarze CHECK_BODY_DEFN(ge1, err, err_child_gt, 0) /* berr_ge1() */ 391*b31af00dSschwarze CHECK_ELEM_DEFN(ge1, warn, warn_child_gt, 0) /* ewarn_ge1() */ 392f73abda9Skristaps CHECK_ELEM_DEFN(eq1, err, err_child_eq, 1) /* eerr_eq1() */ 3934175bdabSschwarze CHECK_ELEM_DEFN(le1, err, err_child_lt, 2) /* eerr_le1() */ 394f73abda9Skristaps CHECK_ELEM_DEFN(eq0, err, err_child_eq, 0) /* eerr_eq0() */ 395f73abda9Skristaps CHECK_ELEM_DEFN(ge1, err, err_child_gt, 0) /* eerr_ge1() */ 396f73abda9Skristaps CHECK_HEAD_DEFN(eq0, err, err_child_eq, 0) /* herr_eq0() */ 397f73abda9Skristaps CHECK_HEAD_DEFN(le1, warn, warn_child_lt, 2) /* hwarn_le1() */ 398f73abda9Skristaps CHECK_HEAD_DEFN(ge1, err, err_child_gt, 0) /* herr_ge1() */ 399f73abda9Skristaps CHECK_HEAD_DEFN(eq1, warn, warn_child_eq, 1) /* hwarn_eq1() */ 400b16e7ddfSschwarze CHECK_HEAD_DEFN(eq0, warn, warn_child_eq, 0) /* hwarn_eq0() */ 401f73abda9Skristaps 402f73abda9Skristaps 403f73abda9Skristaps static int 404f73abda9Skristaps check_stdarg(PRE_ARGS) 405f73abda9Skristaps { 406f73abda9Skristaps 407f73abda9Skristaps if (n->args && 1 == n->args->argc) 408f73abda9Skristaps if (MDOC_Std == n->args->argv[0].arg) 409f73abda9Skristaps return(1); 4106e03d529Sschwarze return(mdoc_nmsg(mdoc, n, MANDOCERR_NOARGV)); 411f73abda9Skristaps } 412f73abda9Skristaps 413f73abda9Skristaps 414f73abda9Skristaps static int 415f73abda9Skristaps check_args(struct mdoc *m, const struct mdoc_node *n) 416f73abda9Skristaps { 417f73abda9Skristaps int i; 418f73abda9Skristaps 419f73abda9Skristaps if (NULL == n->args) 420f73abda9Skristaps return(1); 421f73abda9Skristaps 422f73abda9Skristaps assert(n->args->argc); 423f73abda9Skristaps for (i = 0; i < (int)n->args->argc; i++) 424f73abda9Skristaps if ( ! check_argv(m, n, &n->args->argv[i])) 425f73abda9Skristaps return(0); 426f73abda9Skristaps 427f73abda9Skristaps return(1); 428f73abda9Skristaps } 429f73abda9Skristaps 430f73abda9Skristaps 431f73abda9Skristaps static int 432f73abda9Skristaps check_argv(struct mdoc *m, const struct mdoc_node *n, 433f73abda9Skristaps const struct mdoc_argv *v) 434f73abda9Skristaps { 435f73abda9Skristaps int i; 436f73abda9Skristaps 437f73abda9Skristaps for (i = 0; i < (int)v->sz; i++) 438f73abda9Skristaps if ( ! check_text(m, v->line, v->pos, v->value[i])) 439f73abda9Skristaps return(0); 440f73abda9Skristaps 441f73abda9Skristaps if (MDOC_Std == v->arg) { 442f73abda9Skristaps if (v->sz || m->meta.name) 443f73abda9Skristaps return(1); 4446e03d529Sschwarze if ( ! mdoc_nmsg(m, n, MANDOCERR_NONAME)) 4456e03d529Sschwarze return(0); 446f73abda9Skristaps } 447f73abda9Skristaps 448f73abda9Skristaps return(1); 449f73abda9Skristaps } 450f73abda9Skristaps 451f73abda9Skristaps 452f73abda9Skristaps static int 453f73abda9Skristaps check_text(struct mdoc *mdoc, int line, int pos, const char *p) 454f73abda9Skristaps { 455f6854d5cSschwarze int c; 456f73abda9Skristaps 457f6854d5cSschwarze for ( ; *p; p++, pos++) { 458f73abda9Skristaps if ('\t' == *p) { 459f73abda9Skristaps if ( ! (MDOC_LITERAL & mdoc->flags)) 4606e03d529Sschwarze if ( ! mdoc_pmsg(mdoc, line, pos, MANDOCERR_BADCHAR)) 461f73abda9Skristaps return(0); 4621068637fSschwarze } else if ( ! isprint((u_char)*p) && ASCII_HYPH != *p) 4636e03d529Sschwarze if ( ! mdoc_pmsg(mdoc, line, pos, MANDOCERR_BADCHAR)) 464f73abda9Skristaps return(0); 465f73abda9Skristaps 466f73abda9Skristaps if ('\\' != *p) 467f73abda9Skristaps continue; 468f73abda9Skristaps 469f6854d5cSschwarze c = mandoc_special(p); 470f73abda9Skristaps if (c) { 471f6854d5cSschwarze p += c - 1; 472f6854d5cSschwarze pos += c - 1; 473f73abda9Skristaps continue; 474f73abda9Skristaps } 4756e03d529Sschwarze 4766e03d529Sschwarze c = mdoc_pmsg(mdoc, line, pos, MANDOCERR_BADESCAPE); 4776e03d529Sschwarze if ( ! (MDOC_IGN_ESCAPE & mdoc->pflags) && ! c) 4786e03d529Sschwarze return(c); 479f73abda9Skristaps } 480f73abda9Skristaps 481f73abda9Skristaps return(1); 482f73abda9Skristaps } 483f73abda9Skristaps 484f73abda9Skristaps 485f73abda9Skristaps 486f73abda9Skristaps 487f73abda9Skristaps static int 488dd94fa3aSschwarze check_parent(PRE_ARGS, enum mdoct tok, enum mdoc_type t) 489f73abda9Skristaps { 490f73abda9Skristaps 491f73abda9Skristaps assert(n->parent); 492f73abda9Skristaps if ((MDOC_ROOT == t || tok == n->parent->tok) && 493f73abda9Skristaps (t == n->parent->type)) 494f73abda9Skristaps return(1); 495f73abda9Skristaps 4966e03d529Sschwarze mdoc_vmsg(mdoc, MANDOCERR_SYNTCHILD, 4976e03d529Sschwarze n->line, n->pos, "want parent %s", 4986e03d529Sschwarze MDOC_ROOT == t ? "<root>" : 4996e03d529Sschwarze mdoc_macronames[tok]); 5006e03d529Sschwarze return(0); 501f73abda9Skristaps } 502f73abda9Skristaps 503f73abda9Skristaps 504f73abda9Skristaps 505f73abda9Skristaps static int 506f73abda9Skristaps pre_display(PRE_ARGS) 507f73abda9Skristaps { 508f73abda9Skristaps struct mdoc_node *node; 509f73abda9Skristaps 510f73abda9Skristaps /* Display elements (`Bd', `D1'...) cannot be nested. */ 511f73abda9Skristaps 512f73abda9Skristaps if (MDOC_BLOCK != n->type) 513f73abda9Skristaps return(1); 514f73abda9Skristaps 515f73abda9Skristaps /* LINTED */ 516f73abda9Skristaps for (node = mdoc->last->parent; node; node = node->parent) 517f73abda9Skristaps if (MDOC_BLOCK == node->type) 518f73abda9Skristaps if (MDOC_Bd == node->tok) 519f73abda9Skristaps break; 520f73abda9Skristaps if (NULL == node) 521f73abda9Skristaps return(1); 522f73abda9Skristaps 5236e03d529Sschwarze mdoc_nmsg(mdoc, n, MANDOCERR_NESTEDDISP); 5246e03d529Sschwarze return(0); 525f73abda9Skristaps } 526f73abda9Skristaps 527f73abda9Skristaps 528f73abda9Skristaps static int 529f73abda9Skristaps pre_bl(PRE_ARGS) 530f73abda9Skristaps { 531395185ccSschwarze int pos, type, width, offset; 532f73abda9Skristaps 533f73abda9Skristaps if (MDOC_BLOCK != n->type) 534f73abda9Skristaps return(1); 5356e03d529Sschwarze if (NULL == n->args) { 5366e03d529Sschwarze mdoc_nmsg(mdoc, n, MANDOCERR_LISTTYPE); 5376e03d529Sschwarze return(0); 5386e03d529Sschwarze } 539f73abda9Skristaps 540f73abda9Skristaps /* Make sure that only one type of list is specified. */ 541f73abda9Skristaps 542395185ccSschwarze type = offset = width = -1; 543f73abda9Skristaps 544f73abda9Skristaps /* LINTED */ 54564d728e4Sschwarze for (pos = 0; pos < (int)n->args->argc; pos++) 54664d728e4Sschwarze switch (n->args->argv[pos].arg) { 547f73abda9Skristaps case (MDOC_Bullet): 548f73abda9Skristaps /* FALLTHROUGH */ 549f73abda9Skristaps case (MDOC_Dash): 550f73abda9Skristaps /* FALLTHROUGH */ 551f73abda9Skristaps case (MDOC_Enum): 552f73abda9Skristaps /* FALLTHROUGH */ 553f73abda9Skristaps case (MDOC_Hyphen): 554f73abda9Skristaps /* FALLTHROUGH */ 555f73abda9Skristaps case (MDOC_Item): 556f73abda9Skristaps /* FALLTHROUGH */ 557f73abda9Skristaps case (MDOC_Tag): 558f73abda9Skristaps /* FALLTHROUGH */ 559f73abda9Skristaps case (MDOC_Diag): 560f73abda9Skristaps /* FALLTHROUGH */ 561f73abda9Skristaps case (MDOC_Hang): 562f73abda9Skristaps /* FALLTHROUGH */ 563f73abda9Skristaps case (MDOC_Ohang): 564f73abda9Skristaps /* FALLTHROUGH */ 565f73abda9Skristaps case (MDOC_Inset): 566f73abda9Skristaps /* FALLTHROUGH */ 567f73abda9Skristaps case (MDOC_Column): 56850e63e03Sschwarze if (type < 0) { 56964d728e4Sschwarze type = n->args->argv[pos].arg; 57064d728e4Sschwarze break; 57150e63e03Sschwarze } 57250e63e03Sschwarze if (mdoc_nmsg(mdoc, n, MANDOCERR_LISTREP)) 5734175bdabSschwarze break; 57450e63e03Sschwarze return(0); 57550e63e03Sschwarze case (MDOC_Compact): 57650e63e03Sschwarze if (type >= 0) 57750e63e03Sschwarze break; 57850e63e03Sschwarze if (mdoc_nmsg(mdoc, n, MANDOCERR_LISTFIRST)) 57950e63e03Sschwarze break; 58050e63e03Sschwarze return(0); 581f73abda9Skristaps case (MDOC_Width): 5824175bdabSschwarze if (width >= 0) 5836e03d529Sschwarze if ( ! mdoc_nmsg(mdoc, n, MANDOCERR_ARGVREP)) 5846e03d529Sschwarze return(0); 5856e03d529Sschwarze if (type < 0 && ! mdoc_nmsg(mdoc, n, MANDOCERR_LISTFIRST)) 5864175bdabSschwarze return(0); 58764d728e4Sschwarze width = n->args->argv[pos].arg; 58864d728e4Sschwarze break; 589f73abda9Skristaps case (MDOC_Offset): 5904175bdabSschwarze if (offset >= 0) 5916e03d529Sschwarze if ( ! mdoc_nmsg(mdoc, n, MANDOCERR_ARGVREP)) 5926e03d529Sschwarze return(0); 5936e03d529Sschwarze if (type < 0 && ! mdoc_nmsg(mdoc, n, MANDOCERR_LISTFIRST)) 5944175bdabSschwarze return(0); 59564d728e4Sschwarze offset = n->args->argv[pos].arg; 59664d728e4Sschwarze break; 597f73abda9Skristaps default: 598f73abda9Skristaps break; 599f73abda9Skristaps } 600f73abda9Skristaps 6016e03d529Sschwarze if (type < 0) { 6026e03d529Sschwarze mdoc_nmsg(mdoc, n, MANDOCERR_LISTTYPE); 6036e03d529Sschwarze return(0); 6046e03d529Sschwarze } 605f73abda9Skristaps 60664d728e4Sschwarze /* 60764d728e4Sschwarze * Validate the width field. Some list types don't need width 60864d728e4Sschwarze * types and should be warned about them. Others should have it 60964d728e4Sschwarze * and must also be warned. 61064d728e4Sschwarze */ 61164d728e4Sschwarze 612f73abda9Skristaps switch (type) { 61364d728e4Sschwarze case (MDOC_Tag): 6146e03d529Sschwarze if (width < 0 && ! mdoc_nmsg(mdoc, n, MANDOCERR_NOWIDTHARG)) 61564d728e4Sschwarze return(0); 61664d728e4Sschwarze break; 617f73abda9Skristaps case (MDOC_Column): 618f73abda9Skristaps /* FALLTHROUGH */ 619f73abda9Skristaps case (MDOC_Diag): 620f73abda9Skristaps /* FALLTHROUGH */ 621aa2d850aSschwarze case (MDOC_Ohang): 622aa2d850aSschwarze /* FALLTHROUGH */ 623f73abda9Skristaps case (MDOC_Inset): 624f73abda9Skristaps /* FALLTHROUGH */ 625f73abda9Skristaps case (MDOC_Item): 6266e03d529Sschwarze if (width >= 0 && ! mdoc_nmsg(mdoc, n, MANDOCERR_WIDTHARG)) 62764d728e4Sschwarze return(0); 628f73abda9Skristaps break; 62964d728e4Sschwarze default: 630f73abda9Skristaps break; 63164d728e4Sschwarze } 63264d728e4Sschwarze 633f73abda9Skristaps return(1); 634f73abda9Skristaps } 635f73abda9Skristaps 636f73abda9Skristaps 637f73abda9Skristaps static int 638f73abda9Skristaps pre_bd(PRE_ARGS) 639f73abda9Skristaps { 640f73abda9Skristaps int i, type, err; 641f73abda9Skristaps 642f73abda9Skristaps if (MDOC_BLOCK != n->type) 643f73abda9Skristaps return(1); 6446e03d529Sschwarze if (NULL == n->args) { 6456e03d529Sschwarze mdoc_nmsg(mdoc, n, MANDOCERR_DISPTYPE); 6466e03d529Sschwarze return(0); 6476e03d529Sschwarze } 648f73abda9Skristaps 649f73abda9Skristaps /* Make sure that only one type of display is specified. */ 650f73abda9Skristaps 651f73abda9Skristaps /* LINTED */ 652f73abda9Skristaps for (i = 0, err = type = 0; ! err && 653f73abda9Skristaps i < (int)n->args->argc; i++) 654f73abda9Skristaps switch (n->args->argv[i].arg) { 655b822ca0dSschwarze case (MDOC_Centred): 656b822ca0dSschwarze /* FALLTHROUGH */ 657f73abda9Skristaps case (MDOC_Ragged): 658f73abda9Skristaps /* FALLTHROUGH */ 659f73abda9Skristaps case (MDOC_Unfilled): 660f73abda9Skristaps /* FALLTHROUGH */ 661f73abda9Skristaps case (MDOC_Filled): 662f73abda9Skristaps /* FALLTHROUGH */ 663f73abda9Skristaps case (MDOC_Literal): 664f73abda9Skristaps if (0 == type++) 665f73abda9Skristaps break; 6666e03d529Sschwarze if ( ! mdoc_nmsg(mdoc, n, MANDOCERR_DISPREP)) 6676e03d529Sschwarze return(0); 6686e03d529Sschwarze break; 669f73abda9Skristaps default: 670f73abda9Skristaps break; 671f73abda9Skristaps } 672f73abda9Skristaps 673f73abda9Skristaps if (type) 674f73abda9Skristaps return(1); 6756e03d529Sschwarze mdoc_nmsg(mdoc, n, MANDOCERR_DISPTYPE); 6766e03d529Sschwarze return(0); 677f73abda9Skristaps } 678f73abda9Skristaps 679f73abda9Skristaps 680f73abda9Skristaps static int 681f73abda9Skristaps pre_ss(PRE_ARGS) 682f73abda9Skristaps { 683f73abda9Skristaps 684f73abda9Skristaps if (MDOC_BLOCK != n->type) 685f73abda9Skristaps return(1); 686f73abda9Skristaps return(check_parent(mdoc, n, MDOC_Sh, MDOC_BODY)); 687f73abda9Skristaps } 688f73abda9Skristaps 689f73abda9Skristaps 690f73abda9Skristaps static int 691f73abda9Skristaps pre_sh(PRE_ARGS) 692f73abda9Skristaps { 693f73abda9Skristaps 694f73abda9Skristaps if (MDOC_BLOCK != n->type) 695f73abda9Skristaps return(1); 696a4c002ecSschwarze return(check_parent(mdoc, n, MDOC_MAX, MDOC_ROOT)); 697f73abda9Skristaps } 698f73abda9Skristaps 699f73abda9Skristaps 700f73abda9Skristaps static int 701f73abda9Skristaps pre_it(PRE_ARGS) 702f73abda9Skristaps { 703f73abda9Skristaps 704f73abda9Skristaps if (MDOC_BLOCK != n->type) 705f73abda9Skristaps return(1); 7066e03d529Sschwarze /* 7076e03d529Sschwarze * FIXME: this can probably be lifted if we make the It into 7086e03d529Sschwarze * something else on-the-fly? 7096e03d529Sschwarze */ 710f73abda9Skristaps return(check_parent(mdoc, n, MDOC_Bl, MDOC_BODY)); 711f73abda9Skristaps } 712f73abda9Skristaps 713f73abda9Skristaps 714f73abda9Skristaps static int 715f73abda9Skristaps pre_an(PRE_ARGS) 716f73abda9Skristaps { 717f73abda9Skristaps 718f73abda9Skristaps if (NULL == n->args || 1 == n->args->argc) 719f73abda9Skristaps return(1); 7206e03d529Sschwarze mdoc_vmsg(mdoc, MANDOCERR_SYNTARGCOUNT, 7216e03d529Sschwarze n->line, n->pos, 7226e03d529Sschwarze "line arguments == 1 (have %d)", 7236e03d529Sschwarze n->args->argc); 7246e03d529Sschwarze return(0); 725f73abda9Skristaps } 726f73abda9Skristaps 727f73abda9Skristaps 728f73abda9Skristaps static int 729f73abda9Skristaps pre_rv(PRE_ARGS) 730f73abda9Skristaps { 731f73abda9Skristaps 732f73abda9Skristaps return(check_stdarg(mdoc, n)); 733f73abda9Skristaps } 734f73abda9Skristaps 735f73abda9Skristaps 736f73abda9Skristaps static int 737f73abda9Skristaps pre_dt(PRE_ARGS) 738f73abda9Skristaps { 739f73abda9Skristaps 740aa2d850aSschwarze /* FIXME: make sure is capitalised. */ 741aa2d850aSschwarze 742f73abda9Skristaps if (0 == mdoc->meta.date || mdoc->meta.os) 7436e03d529Sschwarze if ( ! mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGOOO)) 744f73abda9Skristaps return(0); 745f73abda9Skristaps if (mdoc->meta.title) 7466e03d529Sschwarze if ( ! mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGREP)) 747f73abda9Skristaps return(0); 748f73abda9Skristaps return(1); 749f73abda9Skristaps } 750f73abda9Skristaps 751f73abda9Skristaps 752f73abda9Skristaps static int 753f73abda9Skristaps pre_os(PRE_ARGS) 754f73abda9Skristaps { 755f73abda9Skristaps 756f73abda9Skristaps if (NULL == mdoc->meta.title || 0 == mdoc->meta.date) 7576e03d529Sschwarze if ( ! mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGOOO)) 758f73abda9Skristaps return(0); 759f73abda9Skristaps if (mdoc->meta.os) 7606e03d529Sschwarze if ( ! mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGREP)) 761f73abda9Skristaps return(0); 762f73abda9Skristaps return(1); 763f73abda9Skristaps } 764f73abda9Skristaps 765f73abda9Skristaps 766f73abda9Skristaps static int 767f73abda9Skristaps pre_dd(PRE_ARGS) 768f73abda9Skristaps { 769f73abda9Skristaps 770f73abda9Skristaps if (mdoc->meta.title || mdoc->meta.os) 7716e03d529Sschwarze if ( ! mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGOOO)) 772f73abda9Skristaps return(0); 773f73abda9Skristaps if (mdoc->meta.date) 7746e03d529Sschwarze if ( ! mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGREP)) 775f73abda9Skristaps return(0); 776f73abda9Skristaps return(1); 777f73abda9Skristaps } 778f73abda9Skristaps 779f73abda9Skristaps 780f73abda9Skristaps static int 781f73abda9Skristaps post_bf(POST_ARGS) 782f73abda9Skristaps { 783f73abda9Skristaps char *p; 784f73abda9Skristaps struct mdoc_node *head; 785f73abda9Skristaps 786f73abda9Skristaps if (MDOC_BLOCK != mdoc->last->type) 787f73abda9Skristaps return(1); 788f73abda9Skristaps 789f73abda9Skristaps head = mdoc->last->head; 790f73abda9Skristaps 7916e03d529Sschwarze if (mdoc->last->args && head->child) { 7926e03d529Sschwarze /* FIXME: this should provide a default. */ 7936e03d529Sschwarze mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_SYNTARGVCOUNT); 7946e03d529Sschwarze return(0); 7956e03d529Sschwarze } else if (mdoc->last->args) 79650d41253Sschwarze return(1); 79750d41253Sschwarze 7986e03d529Sschwarze if (NULL == head->child || MDOC_TEXT != head->child->type) { 7996e03d529Sschwarze /* FIXME: this should provide a default. */ 8006e03d529Sschwarze mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_SYNTARGVCOUNT); 8016e03d529Sschwarze return(0); 8026e03d529Sschwarze } 803f73abda9Skristaps 804f73abda9Skristaps p = head->child->string; 80550d41253Sschwarze 806f73abda9Skristaps if (0 == strcmp(p, "Em")) 807f73abda9Skristaps return(1); 808f73abda9Skristaps else if (0 == strcmp(p, "Li")) 809f73abda9Skristaps return(1); 810597492bcSschwarze else if (0 == strcmp(p, "Sy")) 811f73abda9Skristaps return(1); 812f73abda9Skristaps 8136e03d529Sschwarze mdoc_nmsg(mdoc, head, MANDOCERR_FONTTYPE); 8146e03d529Sschwarze return(0); 815f73abda9Skristaps } 816f73abda9Skristaps 817f73abda9Skristaps 818f73abda9Skristaps static int 81971719887Sschwarze post_lb(POST_ARGS) 82071719887Sschwarze { 82171719887Sschwarze 82271719887Sschwarze if (mdoc_a2lib(mdoc->last->child->string)) 82371719887Sschwarze return(1); 8246e03d529Sschwarze return(mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADLIB)); 82571719887Sschwarze } 82671719887Sschwarze 82771719887Sschwarze 82871719887Sschwarze static int 829*b31af00dSschwarze post_eoln(POST_ARGS) 830*b31af00dSschwarze { 831*b31af00dSschwarze 832*b31af00dSschwarze if (NULL == mdoc->last->child) 833*b31af00dSschwarze return(1); 834*b31af00dSschwarze return(mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_ARGSLOST)); 835*b31af00dSschwarze } 836*b31af00dSschwarze 837*b31af00dSschwarze 838*b31af00dSschwarze static int 8398521b0bcSschwarze post_vt(POST_ARGS) 8408521b0bcSschwarze { 8418521b0bcSschwarze const struct mdoc_node *n; 8428521b0bcSschwarze 8438521b0bcSschwarze /* 8448521b0bcSschwarze * The Vt macro comes in both ELEM and BLOCK form, both of which 8458521b0bcSschwarze * have different syntaxes (yet more context-sensitive 8468521b0bcSschwarze * behaviour). ELEM types must have a child; BLOCK types, 8478521b0bcSschwarze * specifically the BODY, should only have TEXT children. 8488521b0bcSschwarze */ 8498521b0bcSschwarze 8508521b0bcSschwarze if (MDOC_ELEM == mdoc->last->type) 8518521b0bcSschwarze return(eerr_ge1(mdoc)); 8528521b0bcSschwarze if (MDOC_BODY != mdoc->last->type) 8538521b0bcSschwarze return(1); 8548521b0bcSschwarze 8558521b0bcSschwarze for (n = mdoc->last->child; n; n = n->next) 856bc49dbe1Sschwarze if (MDOC_TEXT != n->type) 8576e03d529Sschwarze if ( ! mdoc_nmsg(mdoc, n, MANDOCERR_CHILD)) 8588521b0bcSschwarze return(0); 8598521b0bcSschwarze 8608521b0bcSschwarze return(1); 8618521b0bcSschwarze } 8628521b0bcSschwarze 8638521b0bcSschwarze 8648521b0bcSschwarze static int 865f73abda9Skristaps post_nm(POST_ARGS) 866f73abda9Skristaps { 867f73abda9Skristaps 868f73abda9Skristaps if (mdoc->last->child) 869f73abda9Skristaps return(1); 870f73abda9Skristaps if (mdoc->meta.name) 871f73abda9Skristaps return(1); 8726e03d529Sschwarze return(mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NONAME)); 873f73abda9Skristaps } 874f73abda9Skristaps 875f73abda9Skristaps 876f73abda9Skristaps static int 877f73abda9Skristaps post_at(POST_ARGS) 878f73abda9Skristaps { 879f73abda9Skristaps 880f73abda9Skristaps if (NULL == mdoc->last->child) 881f73abda9Skristaps return(1); 8826e03d529Sschwarze assert(MDOC_TEXT == mdoc->last->child->type); 883f73abda9Skristaps if (mdoc_a2att(mdoc->last->child->string)) 884f73abda9Skristaps return(1); 8856e03d529Sschwarze return(mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADATT)); 886f73abda9Skristaps } 887f73abda9Skristaps 888f73abda9Skristaps 889f73abda9Skristaps static int 890f73abda9Skristaps post_an(POST_ARGS) 891f73abda9Skristaps { 892f73abda9Skristaps 893f73abda9Skristaps if (mdoc->last->args) { 894f73abda9Skristaps if (NULL == mdoc->last->child) 895f73abda9Skristaps return(1); 8966e03d529Sschwarze return(mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_ARGCOUNT)); 897f73abda9Skristaps } 898f73abda9Skristaps 899f73abda9Skristaps if (mdoc->last->child) 900f73abda9Skristaps return(1); 9016e03d529Sschwarze return(mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOARGS)); 902f73abda9Skristaps } 903f73abda9Skristaps 904f73abda9Skristaps 905f73abda9Skristaps static int 906f73abda9Skristaps post_it(POST_ARGS) 907f73abda9Skristaps { 908f73abda9Skristaps int type, i, cols; 909f73abda9Skristaps struct mdoc_node *n, *c; 910f73abda9Skristaps 911f73abda9Skristaps if (MDOC_BLOCK != mdoc->last->type) 912f73abda9Skristaps return(1); 913f73abda9Skristaps 914f73abda9Skristaps n = mdoc->last->parent->parent; 9156e03d529Sschwarze if (NULL == n->args) { 9166e03d529Sschwarze mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_LISTTYPE); 9176e03d529Sschwarze return(0); 9186e03d529Sschwarze } 919f73abda9Skristaps 920f73abda9Skristaps /* Some types require block-head, some not. */ 921f73abda9Skristaps 922f73abda9Skristaps /* LINTED */ 923f73abda9Skristaps for (cols = type = -1, i = 0; -1 == type && 924f73abda9Skristaps i < (int)n->args->argc; i++) 925f73abda9Skristaps switch (n->args->argv[i].arg) { 926f73abda9Skristaps case (MDOC_Tag): 927f73abda9Skristaps /* FALLTHROUGH */ 928f73abda9Skristaps case (MDOC_Diag): 929f73abda9Skristaps /* FALLTHROUGH */ 930f73abda9Skristaps case (MDOC_Hang): 931f73abda9Skristaps /* FALLTHROUGH */ 932f73abda9Skristaps case (MDOC_Ohang): 933f73abda9Skristaps /* FALLTHROUGH */ 934f73abda9Skristaps case (MDOC_Inset): 935f73abda9Skristaps /* FALLTHROUGH */ 936f73abda9Skristaps case (MDOC_Bullet): 937f73abda9Skristaps /* FALLTHROUGH */ 938f73abda9Skristaps case (MDOC_Dash): 939f73abda9Skristaps /* FALLTHROUGH */ 940f73abda9Skristaps case (MDOC_Enum): 941f73abda9Skristaps /* FALLTHROUGH */ 942f73abda9Skristaps case (MDOC_Hyphen): 943f73abda9Skristaps /* FALLTHROUGH */ 944f73abda9Skristaps case (MDOC_Item): 945f73abda9Skristaps type = n->args->argv[i].arg; 946f73abda9Skristaps break; 947f73abda9Skristaps case (MDOC_Column): 948f73abda9Skristaps type = n->args->argv[i].arg; 949f73abda9Skristaps cols = (int)n->args->argv[i].sz; 950f73abda9Skristaps break; 951f73abda9Skristaps default: 952f73abda9Skristaps break; 953f73abda9Skristaps } 954f73abda9Skristaps 9556e03d529Sschwarze if (-1 == type) { 9566e03d529Sschwarze mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_LISTTYPE); 9576e03d529Sschwarze return(0); 9586e03d529Sschwarze } 959f73abda9Skristaps 960f73abda9Skristaps switch (type) { 961f73abda9Skristaps case (MDOC_Tag): 962f73abda9Skristaps if (NULL == mdoc->last->head->child) 9636e03d529Sschwarze if ( ! mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOARGS)) 964f73abda9Skristaps return(0); 965f73abda9Skristaps break; 966f73abda9Skristaps case (MDOC_Hang): 967f73abda9Skristaps /* FALLTHROUGH */ 968f73abda9Skristaps case (MDOC_Ohang): 969f73abda9Skristaps /* FALLTHROUGH */ 970f73abda9Skristaps case (MDOC_Inset): 971f73abda9Skristaps /* FALLTHROUGH */ 972f73abda9Skristaps case (MDOC_Diag): 973f73abda9Skristaps if (NULL == mdoc->last->head->child) 9746e03d529Sschwarze if ( ! mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOARGS)) 975f73abda9Skristaps return(0); 976f73abda9Skristaps if (NULL == mdoc->last->body->child) 9776e03d529Sschwarze if ( ! mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOBODY)) 978f73abda9Skristaps return(0); 979f73abda9Skristaps break; 980f73abda9Skristaps case (MDOC_Bullet): 981f73abda9Skristaps /* FALLTHROUGH */ 982f73abda9Skristaps case (MDOC_Dash): 983f73abda9Skristaps /* FALLTHROUGH */ 984f73abda9Skristaps case (MDOC_Enum): 985f73abda9Skristaps /* FALLTHROUGH */ 986f73abda9Skristaps case (MDOC_Hyphen): 987f73abda9Skristaps /* FALLTHROUGH */ 988f73abda9Skristaps case (MDOC_Item): 989f73abda9Skristaps if (mdoc->last->head->child) 9906e03d529Sschwarze if ( ! mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_ARGSLOST)) 991f73abda9Skristaps return(0); 992f73abda9Skristaps if (NULL == mdoc->last->body->child) 9936e03d529Sschwarze if ( ! mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOBODY)) 994f73abda9Skristaps return(0); 995f73abda9Skristaps break; 996f73abda9Skristaps case (MDOC_Column): 997f73abda9Skristaps if (NULL == mdoc->last->head->child) 9986e03d529Sschwarze if ( ! mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOARGS)) 999f73abda9Skristaps return(0); 1000f73abda9Skristaps if (mdoc->last->body->child) 10016e03d529Sschwarze if ( ! mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BODYLOST)) 1002f73abda9Skristaps return(0); 1003f73abda9Skristaps c = mdoc->last->child; 1004f73abda9Skristaps for (i = 0; c && MDOC_HEAD == c->type; c = c->next) 1005f73abda9Skristaps i++; 100653292e81Sschwarze 1007974b5ecdSschwarze if (i < cols) { 10086e03d529Sschwarze if ( ! mdoc_vmsg(mdoc, MANDOCERR_ARGCOUNT, 10096e03d529Sschwarze mdoc->last->line, 10106e03d529Sschwarze mdoc->last->pos, 10116e03d529Sschwarze "columns == %d (have %d)", 10126e03d529Sschwarze cols, i)) 101353292e81Sschwarze return(0); 1014f73abda9Skristaps break; 1015974b5ecdSschwarze } else if (i == cols || i == cols + 1) 101653292e81Sschwarze break; 101753292e81Sschwarze 10186e03d529Sschwarze mdoc_vmsg(mdoc, MANDOCERR_SYNTARGCOUNT, 10196e03d529Sschwarze mdoc->last->line, mdoc->last->pos, 10206e03d529Sschwarze "columns == %d (have %d)", cols, i); 10216e03d529Sschwarze return(0); 1022f73abda9Skristaps default: 1023f73abda9Skristaps break; 1024f73abda9Skristaps } 1025f73abda9Skristaps 1026f73abda9Skristaps return(1); 1027f73abda9Skristaps } 1028f73abda9Skristaps 1029f73abda9Skristaps 1030f73abda9Skristaps static int 1031395185ccSschwarze post_bl_head(POST_ARGS) 1032395185ccSschwarze { 1033395185ccSschwarze int i; 1034395185ccSschwarze const struct mdoc_node *n; 1035b16e7ddfSschwarze const struct mdoc_argv *a; 1036395185ccSschwarze 1037395185ccSschwarze n = mdoc->last->parent; 1038395185ccSschwarze assert(n->args); 1039395185ccSschwarze 1040b16e7ddfSschwarze for (i = 0; i < (int)n->args->argc; i++) { 1041b16e7ddfSschwarze a = &n->args->argv[i]; 1042b16e7ddfSschwarze if (a->arg == MDOC_Column) { 1043b16e7ddfSschwarze if (a->sz && mdoc->last->nchild) 10446e03d529Sschwarze return(mdoc_nmsg(mdoc, n, MANDOCERR_COLUMNS)); 1045395185ccSschwarze return(1); 1046395185ccSschwarze } 1047b16e7ddfSschwarze } 1048b16e7ddfSschwarze 1049b16e7ddfSschwarze if (0 == (i = mdoc->last->nchild)) 1050b16e7ddfSschwarze return(1); 1051b16e7ddfSschwarze return(warn_count(mdoc, "==", 0, "line arguments", i)); 1052b16e7ddfSschwarze } 1053395185ccSschwarze 1054395185ccSschwarze 1055395185ccSschwarze static int 1056f73abda9Skristaps post_bl(POST_ARGS) 1057f73abda9Skristaps { 1058f73abda9Skristaps struct mdoc_node *n; 1059f73abda9Skristaps 1060395185ccSschwarze if (MDOC_HEAD == mdoc->last->type) 1061395185ccSschwarze return(post_bl_head(mdoc)); 1062f73abda9Skristaps if (MDOC_BODY != mdoc->last->type) 1063f73abda9Skristaps return(1); 1064f73abda9Skristaps if (NULL == mdoc->last->child) 1065f73abda9Skristaps return(1); 1066f73abda9Skristaps 106739bb0097Sschwarze /* 106839bb0097Sschwarze * We only allow certain children of `Bl'. This is usually on 106939bb0097Sschwarze * `It', but apparently `Sm' occurs here and there, so we let 107039bb0097Sschwarze * that one through, too. 107139bb0097Sschwarze */ 107239bb0097Sschwarze 1073f73abda9Skristaps /* LINTED */ 1074f73abda9Skristaps for (n = mdoc->last->child; n; n = n->next) { 107539bb0097Sschwarze if (MDOC_BLOCK == n->type && MDOC_It == n->tok) 107639bb0097Sschwarze continue; 107739bb0097Sschwarze if (MDOC_Sm == n->tok) 1078f73abda9Skristaps continue; 10796e03d529Sschwarze mdoc_nmsg(mdoc, n, MANDOCERR_SYNTCHILD); 10806e03d529Sschwarze return(0); 1081f73abda9Skristaps } 1082f73abda9Skristaps 1083f73abda9Skristaps return(1); 1084f73abda9Skristaps } 1085f73abda9Skristaps 1086f73abda9Skristaps 1087f73abda9Skristaps static int 1088f73abda9Skristaps ebool(struct mdoc *mdoc) 1089f73abda9Skristaps { 1090f73abda9Skristaps struct mdoc_node *n; 1091f73abda9Skristaps 1092f73abda9Skristaps /* LINTED */ 1093f73abda9Skristaps for (n = mdoc->last->child; n; n = n->next) { 1094f73abda9Skristaps if (MDOC_TEXT != n->type) 1095f73abda9Skristaps break; 1096f73abda9Skristaps if (0 == strcmp(n->string, "on")) 1097f73abda9Skristaps continue; 1098f73abda9Skristaps if (0 == strcmp(n->string, "off")) 1099f73abda9Skristaps continue; 1100f73abda9Skristaps break; 1101f73abda9Skristaps } 1102f73abda9Skristaps 1103f73abda9Skristaps if (NULL == n) 1104f73abda9Skristaps return(1); 11056e03d529Sschwarze return(mdoc_nmsg(mdoc, n, MANDOCERR_BADBOOL)); 1106f73abda9Skristaps } 1107f73abda9Skristaps 1108f73abda9Skristaps 1109f73abda9Skristaps static int 1110f73abda9Skristaps post_root(POST_ARGS) 1111f73abda9Skristaps { 1112f73abda9Skristaps 1113f73abda9Skristaps if (NULL == mdoc->first->child) 11146e03d529Sschwarze mdoc_nmsg(mdoc, mdoc->first, MANDOCERR_NODOCBODY); 11156e03d529Sschwarze else if ( ! (MDOC_PBODY & mdoc->flags)) 11166e03d529Sschwarze mdoc_nmsg(mdoc, mdoc->first, MANDOCERR_NODOCPROLOG); 11176e03d529Sschwarze else if (MDOC_BLOCK != mdoc->first->child->type) 11186e03d529Sschwarze mdoc_nmsg(mdoc, mdoc->first, MANDOCERR_NODOCBODY); 11196e03d529Sschwarze else if (MDOC_Sh != mdoc->first->child->tok) 11206e03d529Sschwarze mdoc_nmsg(mdoc, mdoc->first, MANDOCERR_NODOCBODY); 11216e03d529Sschwarze else 1122f73abda9Skristaps return(1); 11236e03d529Sschwarze 11246e03d529Sschwarze return(0); 1125f73abda9Skristaps } 1126f73abda9Skristaps 1127f73abda9Skristaps 1128f73abda9Skristaps static int 1129f73abda9Skristaps post_st(POST_ARGS) 1130f73abda9Skristaps { 1131f73abda9Skristaps 1132f73abda9Skristaps if (mdoc_a2st(mdoc->last->child->string)) 1133f73abda9Skristaps return(1); 11346e03d529Sschwarze return(mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADSTANDARD)); 1135f73abda9Skristaps } 1136f73abda9Skristaps 1137f73abda9Skristaps 1138f73abda9Skristaps static int 1139011fe33bSschwarze post_rs(POST_ARGS) 1140011fe33bSschwarze { 1141011fe33bSschwarze struct mdoc_node *nn; 1142011fe33bSschwarze 1143011fe33bSschwarze if (MDOC_BODY != mdoc->last->type) 1144011fe33bSschwarze return(1); 1145011fe33bSschwarze 1146011fe33bSschwarze for (nn = mdoc->last->child; nn; nn = nn->next) 1147011fe33bSschwarze switch (nn->tok) { 1148b822ca0dSschwarze case(MDOC__U): 1149b822ca0dSschwarze /* FALLTHROUGH */ 1150011fe33bSschwarze case(MDOC__Q): 1151011fe33bSschwarze /* FALLTHROUGH */ 1152011fe33bSschwarze case(MDOC__C): 1153011fe33bSschwarze /* FALLTHROUGH */ 1154011fe33bSschwarze case(MDOC__A): 1155011fe33bSschwarze /* FALLTHROUGH */ 1156011fe33bSschwarze case(MDOC__B): 1157011fe33bSschwarze /* FALLTHROUGH */ 1158011fe33bSschwarze case(MDOC__D): 1159011fe33bSschwarze /* FALLTHROUGH */ 1160011fe33bSschwarze case(MDOC__I): 1161011fe33bSschwarze /* FALLTHROUGH */ 1162011fe33bSschwarze case(MDOC__J): 1163011fe33bSschwarze /* FALLTHROUGH */ 1164011fe33bSschwarze case(MDOC__N): 1165011fe33bSschwarze /* FALLTHROUGH */ 1166011fe33bSschwarze case(MDOC__O): 1167011fe33bSschwarze /* FALLTHROUGH */ 1168011fe33bSschwarze case(MDOC__P): 1169011fe33bSschwarze /* FALLTHROUGH */ 1170011fe33bSschwarze case(MDOC__R): 1171011fe33bSschwarze /* FALLTHROUGH */ 1172011fe33bSschwarze case(MDOC__T): 1173011fe33bSschwarze /* FALLTHROUGH */ 1174011fe33bSschwarze case(MDOC__V): 1175011fe33bSschwarze break; 1176011fe33bSschwarze default: 11776e03d529Sschwarze mdoc_nmsg(mdoc, nn, MANDOCERR_SYNTCHILD); 11786e03d529Sschwarze return(0); 1179011fe33bSschwarze } 1180011fe33bSschwarze 1181011fe33bSschwarze return(1); 1182011fe33bSschwarze } 1183011fe33bSschwarze 1184011fe33bSschwarze 1185011fe33bSschwarze static int 1186f73abda9Skristaps post_sh(POST_ARGS) 1187f73abda9Skristaps { 1188f73abda9Skristaps 1189f73abda9Skristaps if (MDOC_HEAD == mdoc->last->type) 1190f73abda9Skristaps return(post_sh_head(mdoc)); 1191f73abda9Skristaps if (MDOC_BODY == mdoc->last->type) 1192f73abda9Skristaps return(post_sh_body(mdoc)); 1193f73abda9Skristaps 1194f73abda9Skristaps return(1); 1195f73abda9Skristaps } 1196f73abda9Skristaps 1197f73abda9Skristaps 1198f73abda9Skristaps static int 1199f73abda9Skristaps post_sh_body(POST_ARGS) 1200f73abda9Skristaps { 1201f73abda9Skristaps struct mdoc_node *n; 1202f73abda9Skristaps 1203f8c9d6f2Sschwarze if (SEC_NAME != mdoc->lastsec) 1204f73abda9Skristaps return(1); 1205f73abda9Skristaps 1206f73abda9Skristaps /* 1207f73abda9Skristaps * Warn if the NAME section doesn't contain the `Nm' and `Nd' 1208f73abda9Skristaps * macros (can have multiple `Nm' and one `Nd'). Note that the 1209f73abda9Skristaps * children of the BODY declaration can also be "text". 1210f73abda9Skristaps */ 1211f73abda9Skristaps 1212f73abda9Skristaps if (NULL == (n = mdoc->last->child)) 12136e03d529Sschwarze return(mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADNAMESEC)); 1214f73abda9Skristaps 1215f73abda9Skristaps for ( ; n && n->next; n = n->next) { 1216f73abda9Skristaps if (MDOC_ELEM == n->type && MDOC_Nm == n->tok) 1217f73abda9Skristaps continue; 1218f73abda9Skristaps if (MDOC_TEXT == n->type) 1219f73abda9Skristaps continue; 12206e03d529Sschwarze if ( ! mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADNAMESEC)) 1221f73abda9Skristaps return(0); 1222f73abda9Skristaps } 1223f73abda9Skristaps 122449d529b5Sschwarze assert(n); 12254602e85cSschwarze if (MDOC_BLOCK == n->type && MDOC_Nd == n->tok) 1226f73abda9Skristaps return(1); 12276e03d529Sschwarze return(mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADNAMESEC)); 1228f73abda9Skristaps } 1229f73abda9Skristaps 1230f73abda9Skristaps 1231f73abda9Skristaps static int 1232f73abda9Skristaps post_sh_head(POST_ARGS) 1233f73abda9Skristaps { 12343216dddfSschwarze char buf[BUFSIZ]; 1235f73abda9Skristaps enum mdoc_sec sec; 1236f73abda9Skristaps const struct mdoc_node *n; 1237f73abda9Skristaps 1238f73abda9Skristaps /* 1239f73abda9Skristaps * Process a new section. Sections are either "named" or 1240f73abda9Skristaps * "custom"; custom sections are user-defined, while named ones 1241f73abda9Skristaps * usually follow a conventional order and may only appear in 1242f73abda9Skristaps * certain manual sections. 1243f73abda9Skristaps */ 1244f73abda9Skristaps 12456e03d529Sschwarze buf[0] = '\0'; 12466e03d529Sschwarze 12476e03d529Sschwarze /* 12486e03d529Sschwarze * FIXME: yes, these can use a dynamic buffer, but I don't do so 12496e03d529Sschwarze * in the interests of simplicity. 12506e03d529Sschwarze */ 12516be99f77Sschwarze 1252f73abda9Skristaps for (n = mdoc->last->child; n; n = n->next) { 12536be99f77Sschwarze /* XXX - copied from compact(). */ 1254f73abda9Skristaps assert(MDOC_TEXT == n->type); 12556be99f77Sschwarze 12563216dddfSschwarze if (strlcat(buf, n->string, BUFSIZ) >= BUFSIZ) { 12576e03d529Sschwarze mdoc_nmsg(mdoc, n, MANDOCERR_MEM); 12586e03d529Sschwarze return(0); 12596e03d529Sschwarze } 1260f73abda9Skristaps if (NULL == n->next) 1261f73abda9Skristaps continue; 12623216dddfSschwarze if (strlcat(buf, " ", BUFSIZ) >= BUFSIZ) { 12636e03d529Sschwarze mdoc_nmsg(mdoc, n, MANDOCERR_MEM); 12646e03d529Sschwarze return(0); 12656e03d529Sschwarze } 1266f73abda9Skristaps } 1267f73abda9Skristaps 1268fccfce9dSschwarze sec = mdoc_str2sec(buf); 1269f73abda9Skristaps 12706be99f77Sschwarze /* 12716be99f77Sschwarze * Check: NAME should always be first, CUSTOM has no roles, 12726be99f77Sschwarze * non-CUSTOM has a conventional order to be followed. 12736be99f77Sschwarze */ 1274f73abda9Skristaps 1275fccfce9dSschwarze if (SEC_NAME != sec && SEC_NONE == mdoc->lastnamed) 12766e03d529Sschwarze if ( ! mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NAMESECFIRST)) 12771ef47510Sschwarze return(0); 1278fccfce9dSschwarze 1279f73abda9Skristaps if (SEC_CUSTOM == sec) 1280f73abda9Skristaps return(1); 1281fccfce9dSschwarze 1282f73abda9Skristaps if (sec == mdoc->lastnamed) 12836e03d529Sschwarze if ( ! mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_SECREP)) 12849717f369Sschwarze return(0); 1285fccfce9dSschwarze 1286f73abda9Skristaps if (sec < mdoc->lastnamed) 12876e03d529Sschwarze if ( ! mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_SECOOO)) 12889717f369Sschwarze return(0); 1289f73abda9Skristaps 12906be99f77Sschwarze /* 12916be99f77Sschwarze * Check particular section/manual conventions. LIBRARY can 129292c0ca7fSschwarze * only occur in manual section 2, 3, and 9. 12936be99f77Sschwarze */ 1294f73abda9Skristaps 1295f73abda9Skristaps switch (sec) { 1296f73abda9Skristaps case (SEC_LIBRARY): 129792c0ca7fSschwarze assert(mdoc->meta.msec); 129892c0ca7fSschwarze if (*mdoc->meta.msec == '2') 1299f73abda9Skristaps break; 130092c0ca7fSschwarze if (*mdoc->meta.msec == '3') 130192c0ca7fSschwarze break; 130292c0ca7fSschwarze if (*mdoc->meta.msec == '9') 130392c0ca7fSschwarze break; 13046e03d529Sschwarze return(mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_SECMSEC)); 1305f73abda9Skristaps default: 1306f73abda9Skristaps break; 1307f73abda9Skristaps } 1308f73abda9Skristaps 1309f73abda9Skristaps return(1); 1310f73abda9Skristaps } 1311