1*0ff14c71Sschwarze /* $OpenBSD: mdoc_validate.c,v 1.169 2014/10/13 14:01:03 schwarze Exp $ */ 2f73abda9Skristaps /* 322972b14Sschwarze * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv> 4231c7061Sschwarze * Copyright (c) 2010-2014 Ingo Schwarze <schwarze@openbsd.org> 539c2a57eSschwarze * Copyright (c) 2010 Joerg Sonnenberger <joerg@netbsd.org> 6f73abda9Skristaps * 7f73abda9Skristaps * Permission to use, copy, modify, and distribute this software for any 8a6464425Sschwarze * purpose with or without fee is hereby granted, provided that the above 9a6464425Sschwarze * copyright notice and this permission notice appear in all copies. 10f73abda9Skristaps * 11a6464425Sschwarze * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12a6464425Sschwarze * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13a6464425Sschwarze * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14a6464425Sschwarze * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15a6464425Sschwarze * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16a6464425Sschwarze * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17a6464425Sschwarze * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18f73abda9Skristaps */ 19dadc3a61Sschwarze 20dadc3a61Sschwarze #include <sys/types.h> 2120fa2881Sschwarze #ifndef OSNAME 2220fa2881Sschwarze #include <sys/utsname.h> 2320fa2881Sschwarze #endif 2420fa2881Sschwarze 25f73abda9Skristaps #include <assert.h> 26f73abda9Skristaps #include <ctype.h> 27d92dc4efSschwarze #include <limits.h> 283216dddfSschwarze #include <stdio.h> 29f73abda9Skristaps #include <stdlib.h> 30f73abda9Skristaps #include <string.h> 3120fa2881Sschwarze #include <time.h> 32f73abda9Skristaps 33a35fc07aSschwarze #include "mdoc.h" 346e03d529Sschwarze #include "mandoc.h" 354f4f7972Sschwarze #include "mandoc_aux.h" 36f73abda9Skristaps #include "libmdoc.h" 37f6854d5cSschwarze #include "libmandoc.h" 38f73abda9Skristaps 39f73abda9Skristaps /* FIXME: .Bl -diag can't have non-text children in HEAD. */ 40f73abda9Skristaps 416093755cSschwarze #define PRE_ARGS struct mdoc *mdoc, struct mdoc_node *n 42f73abda9Skristaps #define POST_ARGS struct mdoc *mdoc 43f73abda9Skristaps 447c2be9f8Sschwarze enum check_ineq { 457c2be9f8Sschwarze CHECK_LT, 467c2be9f8Sschwarze CHECK_GT, 477c2be9f8Sschwarze CHECK_EQ 487c2be9f8Sschwarze }; 497c2be9f8Sschwarze 507c2be9f8Sschwarze enum check_lvl { 517c2be9f8Sschwarze CHECK_WARN, 527c2be9f8Sschwarze CHECK_ERROR, 537c2be9f8Sschwarze }; 547c2be9f8Sschwarze 55f73abda9Skristaps typedef int (*v_pre)(PRE_ARGS); 56f73abda9Skristaps typedef int (*v_post)(POST_ARGS); 57f73abda9Skristaps 58f73abda9Skristaps struct valids { 59d52d1586Sschwarze v_pre pre; 60753701eeSschwarze v_post post; 61f73abda9Skristaps }; 62f73abda9Skristaps 637c2be9f8Sschwarze static int check_count(struct mdoc *, enum mdoc_type, 647c2be9f8Sschwarze enum check_lvl, enum check_ineq, int); 6520fa2881Sschwarze static void check_text(struct mdoc *, int, int, char *); 6620fa2881Sschwarze static void check_argv(struct mdoc *, 6731e23753Sschwarze struct mdoc_node *, struct mdoc_argv *); 6820fa2881Sschwarze static void check_args(struct mdoc *, struct mdoc_node *); 69cd6c268fSschwarze static int child_an(const struct mdoc_node *); 7019a69263Sschwarze static enum mdoc_sec a2sec(const char *); 7119a69263Sschwarze static size_t macro2len(enum mdoct); 7267c719adSschwarze 737c2be9f8Sschwarze static int ebool(POST_ARGS); 7467c719adSschwarze static int berr_ge1(POST_ARGS); 7567c719adSschwarze static int bwarn_ge1(POST_ARGS); 76da272f5eSschwarze static int ewarn_eq0(POST_ARGS); 77bb648afaSschwarze static int ewarn_eq1(POST_ARGS); 7867c719adSschwarze static int ewarn_ge1(POST_ARGS); 79bb648afaSschwarze static int ewarn_le1(POST_ARGS); 80b16e7ddfSschwarze static int hwarn_eq0(POST_ARGS); 817c2be9f8Sschwarze static int hwarn_eq1(POST_ARGS); 82bb648afaSschwarze static int hwarn_ge1(POST_ARGS); 8367c719adSschwarze 8467c719adSschwarze static int post_an(POST_ARGS); 8567c719adSschwarze static int post_at(POST_ARGS); 8667c719adSschwarze static int post_bf(POST_ARGS); 87753701eeSschwarze static int post_bk(POST_ARGS); 8867c719adSschwarze static int post_bl(POST_ARGS); 8920fa2881Sschwarze static int post_bl_block(POST_ARGS); 9020fa2881Sschwarze static int post_bl_block_width(POST_ARGS); 9120fa2881Sschwarze static int post_bl_block_tag(POST_ARGS); 9267c719adSschwarze static int post_bl_head(POST_ARGS); 93992063deSschwarze static int post_bx(POST_ARGS); 94753701eeSschwarze static int post_d1(POST_ARGS); 954039b21cSschwarze static int post_defaults(POST_ARGS); 9620fa2881Sschwarze static int post_dd(POST_ARGS); 976093755cSschwarze static int post_dt(POST_ARGS); 98551cd4a8Sschwarze static int post_en(POST_ARGS); 99551cd4a8Sschwarze static int post_es(POST_ARGS); 10020fa2881Sschwarze static int post_eoln(POST_ARGS); 101e214f641Sschwarze static int post_ex(POST_ARGS); 1027e92c062Sschwarze static int post_fa(POST_ARGS); 1030c5064e3Sschwarze static int post_fn(POST_ARGS); 1040c5064e3Sschwarze static int post_fname(POST_ARGS); 105753701eeSschwarze static int post_fo(POST_ARGS); 1064039b21cSschwarze static int post_hyph(POST_ARGS); 107753701eeSschwarze static int post_hyphtext(POST_ARGS); 1084039b21cSschwarze static int post_ignpar(POST_ARGS); 10967c719adSschwarze static int post_it(POST_ARGS); 11067c719adSschwarze static int post_lb(POST_ARGS); 1114039b21cSschwarze static int post_literal(POST_ARGS); 112753701eeSschwarze static int post_nd(POST_ARGS); 11367c719adSschwarze static int post_nm(POST_ARGS); 114af216717Sschwarze static int post_ns(POST_ARGS); 11520fa2881Sschwarze static int post_os(POST_ARGS); 116e0dd4c9cSschwarze static int post_par(POST_ARGS); 11767c719adSschwarze static int post_root(POST_ARGS); 118011fe33bSschwarze static int post_rs(POST_ARGS); 11967c719adSschwarze static int post_sh(POST_ARGS); 12067c719adSschwarze static int post_sh_head(POST_ARGS); 121cd6c268fSschwarze static int post_sh_name(POST_ARGS); 1227c384856Sschwarze static int post_sh_see_also(POST_ARGS); 123cd6c268fSschwarze static int post_sh_authors(POST_ARGS); 12467c719adSschwarze static int post_st(POST_ARGS); 1258521b0bcSschwarze static int post_vt(POST_ARGS); 126f73abda9Skristaps static int pre_an(PRE_ARGS); 127f73abda9Skristaps static int pre_bd(PRE_ARGS); 128f73abda9Skristaps static int pre_bl(PRE_ARGS); 129f73abda9Skristaps static int pre_dd(PRE_ARGS); 130f73abda9Skristaps static int pre_display(PRE_ARGS); 131f73abda9Skristaps static int pre_dt(PRE_ARGS); 13220fa2881Sschwarze static int pre_literal(PRE_ARGS); 133551cd4a8Sschwarze static int pre_obsolete(PRE_ARGS); 134f73abda9Skristaps static int pre_os(PRE_ARGS); 13520fa2881Sschwarze static int pre_par(PRE_ARGS); 13620fa2881Sschwarze static int pre_std(PRE_ARGS); 137f73abda9Skristaps 13819a69263Sschwarze static const struct valids mdoc_valids[MDOC_MAX] = { 139099cfa7eSschwarze { NULL, NULL }, /* Ap */ 140753701eeSschwarze { pre_dd, post_dd }, /* Dd */ 141753701eeSschwarze { pre_dt, post_dt }, /* Dt */ 142753701eeSschwarze { pre_os, post_os }, /* Os */ 143753701eeSschwarze { NULL, post_sh }, /* Sh */ 144753701eeSschwarze { NULL, post_ignpar }, /* Ss */ 145753701eeSschwarze { pre_par, post_par }, /* Pp */ 146753701eeSschwarze { pre_display, post_d1 }, /* D1 */ 147753701eeSschwarze { pre_literal, post_literal }, /* Dl */ 148753701eeSschwarze { pre_bd, post_literal }, /* Bd */ 149f73abda9Skristaps { NULL, NULL }, /* Ed */ 150753701eeSschwarze { pre_bl, post_bl }, /* Bl */ 151f73abda9Skristaps { NULL, NULL }, /* El */ 152753701eeSschwarze { pre_par, post_it }, /* It */ 153e7a93ef3Sschwarze { NULL, NULL }, /* Ad */ 154753701eeSschwarze { pre_an, post_an }, /* An */ 155753701eeSschwarze { NULL, post_defaults }, /* Ar */ 156e7a93ef3Sschwarze { NULL, NULL }, /* Cd */ 157f73abda9Skristaps { NULL, NULL }, /* Cm */ 158f73abda9Skristaps { NULL, NULL }, /* Dv */ 1594039b21cSschwarze { NULL, NULL }, /* Er */ 160f73abda9Skristaps { NULL, NULL }, /* Ev */ 161753701eeSschwarze { pre_std, post_ex }, /* Ex */ 1627e92c062Sschwarze { NULL, post_fa }, /* Fa */ 163753701eeSschwarze { NULL, ewarn_ge1 }, /* Fd */ 164f73abda9Skristaps { NULL, NULL }, /* Fl */ 1650c5064e3Sschwarze { NULL, post_fn }, /* Fn */ 166e7a93ef3Sschwarze { NULL, NULL }, /* Ft */ 167e7a93ef3Sschwarze { NULL, NULL }, /* Ic */ 168753701eeSschwarze { NULL, ewarn_eq1 }, /* In */ 169753701eeSschwarze { NULL, post_defaults }, /* Li */ 170753701eeSschwarze { NULL, post_nd }, /* Nd */ 171753701eeSschwarze { NULL, post_nm }, /* Nm */ 172bca76d61Sschwarze { NULL, NULL }, /* Op */ 173d52d1586Sschwarze { pre_obsolete, NULL }, /* Ot */ 174753701eeSschwarze { NULL, post_defaults }, /* Pa */ 175d52d1586Sschwarze { pre_std, NULL }, /* Rv */ 176753701eeSschwarze { NULL, post_st }, /* St */ 177f73abda9Skristaps { NULL, NULL }, /* Va */ 178753701eeSschwarze { NULL, post_vt }, /* Vt */ 179753701eeSschwarze { NULL, ewarn_ge1 }, /* Xr */ 180753701eeSschwarze { NULL, ewarn_ge1 }, /* %A */ 181753701eeSschwarze { NULL, post_hyphtext }, /* %B */ /* FIXME: can be used outside Rs/Re. */ 182753701eeSschwarze { NULL, ewarn_ge1 }, /* %D */ 183753701eeSschwarze { NULL, ewarn_ge1 }, /* %I */ 184753701eeSschwarze { NULL, ewarn_ge1 }, /* %J */ 185753701eeSschwarze { NULL, post_hyphtext }, /* %N */ 186753701eeSschwarze { NULL, post_hyphtext }, /* %O */ 187753701eeSschwarze { NULL, ewarn_ge1 }, /* %P */ 188753701eeSschwarze { NULL, post_hyphtext }, /* %R */ 189753701eeSschwarze { NULL, post_hyphtext }, /* %T */ /* FIXME: can be used outside Rs/Re. */ 190753701eeSschwarze { NULL, ewarn_ge1 }, /* %V */ 191f73abda9Skristaps { NULL, NULL }, /* Ac */ 192f73abda9Skristaps { NULL, NULL }, /* Ao */ 193bca76d61Sschwarze { NULL, NULL }, /* Aq */ 194753701eeSschwarze { NULL, post_at }, /* At */ 195f73abda9Skristaps { NULL, NULL }, /* Bc */ 196753701eeSschwarze { NULL, post_bf }, /* Bf */ 197f73abda9Skristaps { NULL, NULL }, /* Bo */ 198bca76d61Sschwarze { NULL, NULL }, /* Bq */ 199f73abda9Skristaps { NULL, NULL }, /* Bsx */ 200753701eeSschwarze { NULL, post_bx }, /* Bx */ 201753701eeSschwarze { NULL, ebool }, /* Db */ 202f73abda9Skristaps { NULL, NULL }, /* Dc */ 203f73abda9Skristaps { NULL, NULL }, /* Do */ 204bca76d61Sschwarze { NULL, NULL }, /* Dq */ 205f73abda9Skristaps { NULL, NULL }, /* Ec */ 206f73abda9Skristaps { NULL, NULL }, /* Ef */ 207f73abda9Skristaps { NULL, NULL }, /* Em */ 208f73abda9Skristaps { NULL, NULL }, /* Eo */ 209f73abda9Skristaps { NULL, NULL }, /* Fx */ 210e7a93ef3Sschwarze { NULL, NULL }, /* Ms */ 211753701eeSschwarze { NULL, ewarn_eq0 }, /* No */ 212753701eeSschwarze { NULL, post_ns }, /* Ns */ 213f73abda9Skristaps { NULL, NULL }, /* Nx */ 214f73abda9Skristaps { NULL, NULL }, /* Ox */ 215f73abda9Skristaps { NULL, NULL }, /* Pc */ 216753701eeSschwarze { NULL, ewarn_eq1 }, /* Pf */ 217f73abda9Skristaps { NULL, NULL }, /* Po */ 218bca76d61Sschwarze { NULL, NULL }, /* Pq */ 219f73abda9Skristaps { NULL, NULL }, /* Qc */ 220bca76d61Sschwarze { NULL, NULL }, /* Ql */ 221f73abda9Skristaps { NULL, NULL }, /* Qo */ 222bca76d61Sschwarze { NULL, NULL }, /* Qq */ 223f73abda9Skristaps { NULL, NULL }, /* Re */ 224753701eeSschwarze { NULL, post_rs }, /* Rs */ 225f73abda9Skristaps { NULL, NULL }, /* Sc */ 226f73abda9Skristaps { NULL, NULL }, /* So */ 227bca76d61Sschwarze { NULL, NULL }, /* Sq */ 228753701eeSschwarze { NULL, ebool }, /* Sm */ 229753701eeSschwarze { NULL, post_hyph }, /* Sx */ 230e7a93ef3Sschwarze { NULL, NULL }, /* Sy */ 231e7a93ef3Sschwarze { NULL, NULL }, /* Tn */ 232f73abda9Skristaps { NULL, NULL }, /* Ux */ 233f73abda9Skristaps { NULL, NULL }, /* Xc */ 234f73abda9Skristaps { NULL, NULL }, /* Xo */ 235753701eeSschwarze { NULL, post_fo }, /* Fo */ 236f73abda9Skristaps { NULL, NULL }, /* Fc */ 237f73abda9Skristaps { NULL, NULL }, /* Oo */ 238f73abda9Skristaps { NULL, NULL }, /* Oc */ 239753701eeSschwarze { NULL, post_bk }, /* Bk */ 240f73abda9Skristaps { NULL, NULL }, /* Ek */ 241753701eeSschwarze { NULL, post_eoln }, /* Bt */ 242f73abda9Skristaps { NULL, NULL }, /* Hf */ 243d52d1586Sschwarze { pre_obsolete, NULL }, /* Fr */ 244753701eeSschwarze { NULL, post_eoln }, /* Ud */ 245753701eeSschwarze { NULL, post_lb }, /* Lb */ 246753701eeSschwarze { pre_par, post_par }, /* Lp */ 247e7a93ef3Sschwarze { NULL, NULL }, /* Lk */ 248753701eeSschwarze { NULL, post_defaults }, /* Mt */ 249bca76d61Sschwarze { NULL, NULL }, /* Brq */ 250f73abda9Skristaps { NULL, NULL }, /* Bro */ 251f73abda9Skristaps { NULL, NULL }, /* Brc */ 252753701eeSschwarze { NULL, ewarn_ge1 }, /* %C */ 253753701eeSschwarze { pre_obsolete, post_es }, /* Es */ 254753701eeSschwarze { pre_obsolete, post_en }, /* En */ 255f73abda9Skristaps { NULL, NULL }, /* Dx */ 256753701eeSschwarze { NULL, ewarn_ge1 }, /* %Q */ 257753701eeSschwarze { NULL, post_par }, /* br */ 258753701eeSschwarze { NULL, post_par }, /* sp */ 259753701eeSschwarze { NULL, ewarn_eq1 }, /* %U */ 2606093755cSschwarze { NULL, NULL }, /* Ta */ 2615281506aSschwarze { NULL, NULL }, /* ll */ 262f73abda9Skristaps }; 263f73abda9Skristaps 26420fa2881Sschwarze #define RSORD_MAX 14 /* Number of `Rs' blocks. */ 26520fa2881Sschwarze 26620fa2881Sschwarze static const enum mdoct rsord[RSORD_MAX] = { 26720fa2881Sschwarze MDOC__A, 26820fa2881Sschwarze MDOC__T, 26920fa2881Sschwarze MDOC__B, 27020fa2881Sschwarze MDOC__I, 27120fa2881Sschwarze MDOC__J, 27220fa2881Sschwarze MDOC__R, 27320fa2881Sschwarze MDOC__N, 27420fa2881Sschwarze MDOC__V, 2750397c682Sschwarze MDOC__U, 27620fa2881Sschwarze MDOC__P, 27720fa2881Sschwarze MDOC__Q, 2784e32ec8fSschwarze MDOC__C, 27920fa2881Sschwarze MDOC__D, 2804e32ec8fSschwarze MDOC__O 28120fa2881Sschwarze }; 28220fa2881Sschwarze 28319a69263Sschwarze static const char * const secnames[SEC__MAX] = { 28419a69263Sschwarze NULL, 28519a69263Sschwarze "NAME", 28619a69263Sschwarze "LIBRARY", 28719a69263Sschwarze "SYNOPSIS", 28819a69263Sschwarze "DESCRIPTION", 28903ab2f23Sdlg "CONTEXT", 29019a69263Sschwarze "IMPLEMENTATION NOTES", 29119a69263Sschwarze "RETURN VALUES", 29219a69263Sschwarze "ENVIRONMENT", 29319a69263Sschwarze "FILES", 29419a69263Sschwarze "EXIT STATUS", 29519a69263Sschwarze "EXAMPLES", 29619a69263Sschwarze "DIAGNOSTICS", 29719a69263Sschwarze "COMPATIBILITY", 29819a69263Sschwarze "ERRORS", 29919a69263Sschwarze "SEE ALSO", 30019a69263Sschwarze "STANDARDS", 30119a69263Sschwarze "HISTORY", 30219a69263Sschwarze "AUTHORS", 30319a69263Sschwarze "CAVEATS", 30419a69263Sschwarze "BUGS", 30519a69263Sschwarze "SECURITY CONSIDERATIONS", 30619a69263Sschwarze NULL 30719a69263Sschwarze }; 308f73abda9Skristaps 30949aff9f8Sschwarze 310f73abda9Skristaps int 3116093755cSschwarze mdoc_valid_pre(struct mdoc *mdoc, struct mdoc_node *n) 312f73abda9Skristaps { 313d52d1586Sschwarze v_pre p; 314f73abda9Skristaps 3152791bd1cSschwarze switch (n->type) { 31649aff9f8Sschwarze case MDOC_TEXT: 317d52d1586Sschwarze check_text(mdoc, n->line, n->pos, n->string); 3182791bd1cSschwarze /* FALLTHROUGH */ 31949aff9f8Sschwarze case MDOC_TBL: 3202791bd1cSschwarze /* FALLTHROUGH */ 32149aff9f8Sschwarze case MDOC_EQN: 3228d973ab1Sschwarze /* FALLTHROUGH */ 32349aff9f8Sschwarze case MDOC_ROOT: 32420fa2881Sschwarze return(1); 3252791bd1cSschwarze default: 3262791bd1cSschwarze break; 327f73abda9Skristaps } 328f73abda9Skristaps 32920fa2881Sschwarze check_args(mdoc, n); 330d52d1586Sschwarze p = mdoc_valids[n->tok].pre; 331d52d1586Sschwarze return(*p ? (*p)(mdoc, n) : 1); 332f73abda9Skristaps } 333f73abda9Skristaps 334f73abda9Skristaps int 335f73abda9Skristaps mdoc_valid_post(struct mdoc *mdoc) 336f73abda9Skristaps { 337753701eeSschwarze struct mdoc_node *n; 338753701eeSschwarze v_post p; 339f73abda9Skristaps 340753701eeSschwarze n = mdoc->last; 341753701eeSschwarze if (n->flags & MDOC_VALID) 342f73abda9Skristaps return(1); 343753701eeSschwarze n->flags |= MDOC_VALID; 344f73abda9Skristaps 345753701eeSschwarze switch (n->type) { 34649aff9f8Sschwarze case MDOC_TEXT: 3472791bd1cSschwarze /* FALLTHROUGH */ 34849aff9f8Sschwarze case MDOC_EQN: 3498d973ab1Sschwarze /* FALLTHROUGH */ 35049aff9f8Sschwarze case MDOC_TBL: 351f73abda9Skristaps return(1); 35249aff9f8Sschwarze case MDOC_ROOT: 353f73abda9Skristaps return(post_root(mdoc)); 3542791bd1cSschwarze default: 355753701eeSschwarze p = mdoc_valids[n->tok].post; 356753701eeSschwarze return(*p ? (*p)(mdoc) : 1); 3572791bd1cSschwarze } 358f73abda9Skristaps } 359f73abda9Skristaps 3607c2be9f8Sschwarze static int 3617ead8a4eSschwarze check_count(struct mdoc *mdoc, enum mdoc_type type, 3627c2be9f8Sschwarze enum check_lvl lvl, enum check_ineq ineq, int val) 363f73abda9Skristaps { 3647c2be9f8Sschwarze const char *p; 365bb648afaSschwarze enum mandocerr t; 3667c2be9f8Sschwarze 3677ead8a4eSschwarze if (mdoc->last->type != type) 3687c2be9f8Sschwarze return(1); 3697c2be9f8Sschwarze 3707c2be9f8Sschwarze switch (ineq) { 37149aff9f8Sschwarze case CHECK_LT: 3727c2be9f8Sschwarze p = "less than "; 3737ead8a4eSschwarze if (mdoc->last->nchild < val) 3747c2be9f8Sschwarze return(1); 3757c2be9f8Sschwarze break; 37649aff9f8Sschwarze case CHECK_GT: 377bb648afaSschwarze p = "more than "; 3787ead8a4eSschwarze if (mdoc->last->nchild > val) 3797c2be9f8Sschwarze return(1); 3807c2be9f8Sschwarze break; 38149aff9f8Sschwarze case CHECK_EQ: 3827c2be9f8Sschwarze p = ""; 3837ead8a4eSschwarze if (val == mdoc->last->nchild) 3847c2be9f8Sschwarze return(1); 3857c2be9f8Sschwarze break; 38620fa2881Sschwarze default: 38720fa2881Sschwarze abort(); 38820fa2881Sschwarze /* NOTREACHED */ 3897c2be9f8Sschwarze } 3907c2be9f8Sschwarze 391bb648afaSschwarze t = lvl == CHECK_WARN ? MANDOCERR_ARGCWARN : MANDOCERR_ARGCOUNT; 39249aff9f8Sschwarze mandoc_vmsg(t, mdoc->parse, mdoc->last->line, 39349aff9f8Sschwarze mdoc->last->pos, "want %s%d children (have %d)", 3947ead8a4eSschwarze p, val, mdoc->last->nchild); 39519a69263Sschwarze return(1); 3967c2be9f8Sschwarze } 397f73abda9Skristaps 3987c2be9f8Sschwarze static int 3997c2be9f8Sschwarze berr_ge1(POST_ARGS) 400f73abda9Skristaps { 401f73abda9Skristaps 402bb648afaSschwarze return(check_count(mdoc, MDOC_BODY, CHECK_ERROR, CHECK_GT, 0)); 403f73abda9Skristaps } 404f73abda9Skristaps 4057c2be9f8Sschwarze static int 4067c2be9f8Sschwarze bwarn_ge1(POST_ARGS) 4077c2be9f8Sschwarze { 4087c2be9f8Sschwarze return(check_count(mdoc, MDOC_BODY, CHECK_WARN, CHECK_GT, 0)); 409f73abda9Skristaps } 410f73abda9Skristaps 4117c2be9f8Sschwarze static int 4127c2be9f8Sschwarze ewarn_eq0(POST_ARGS) 4137c2be9f8Sschwarze { 4147c2be9f8Sschwarze return(check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 0)); 4157c2be9f8Sschwarze } 4167c2be9f8Sschwarze 4177c2be9f8Sschwarze static int 418bb648afaSschwarze ewarn_eq1(POST_ARGS) 419bb648afaSschwarze { 420bb648afaSschwarze return(check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 1)); 421bb648afaSschwarze } 422bb648afaSschwarze 423bb648afaSschwarze static int 4247c2be9f8Sschwarze ewarn_ge1(POST_ARGS) 4257c2be9f8Sschwarze { 4267c2be9f8Sschwarze return(check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_GT, 0)); 4277c2be9f8Sschwarze } 4287c2be9f8Sschwarze 4297c2be9f8Sschwarze static int 430bb648afaSschwarze ewarn_le1(POST_ARGS) 4317c2be9f8Sschwarze { 432bb648afaSschwarze return(check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_LT, 2)); 4337c2be9f8Sschwarze } 4347c2be9f8Sschwarze 4357c2be9f8Sschwarze static int 4367c2be9f8Sschwarze hwarn_eq0(POST_ARGS) 4377c2be9f8Sschwarze { 4387c2be9f8Sschwarze return(check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_EQ, 0)); 4397c2be9f8Sschwarze } 4407c2be9f8Sschwarze 4417c2be9f8Sschwarze static int 4427c2be9f8Sschwarze hwarn_eq1(POST_ARGS) 4437c2be9f8Sschwarze { 4447c2be9f8Sschwarze return(check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_EQ, 1)); 4457c2be9f8Sschwarze } 4467c2be9f8Sschwarze 4477c2be9f8Sschwarze static int 448bb648afaSschwarze hwarn_ge1(POST_ARGS) 449bb648afaSschwarze { 450bb648afaSschwarze return(check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_GT, 0)); 451bb648afaSschwarze } 452bb648afaSschwarze 45320fa2881Sschwarze static void 4547ead8a4eSschwarze check_args(struct mdoc *mdoc, struct mdoc_node *n) 455f73abda9Skristaps { 456f73abda9Skristaps int i; 457f73abda9Skristaps 458f73abda9Skristaps if (NULL == n->args) 45920fa2881Sschwarze return; 460f73abda9Skristaps 461f73abda9Skristaps assert(n->args->argc); 462f73abda9Skristaps for (i = 0; i < (int)n->args->argc; i++) 4637ead8a4eSschwarze check_argv(mdoc, n, &n->args->argv[i]); 464f73abda9Skristaps } 465f73abda9Skristaps 46620fa2881Sschwarze static void 4677ead8a4eSschwarze check_argv(struct mdoc *mdoc, struct mdoc_node *n, struct mdoc_argv *v) 468f73abda9Skristaps { 469f73abda9Skristaps int i; 470f73abda9Skristaps 471f73abda9Skristaps for (i = 0; i < (int)v->sz; i++) 4727ead8a4eSschwarze check_text(mdoc, v->line, v->pos, v->value[i]); 473f73abda9Skristaps } 474f73abda9Skristaps 47520fa2881Sschwarze static void 4767ead8a4eSschwarze check_text(struct mdoc *mdoc, int ln, int pos, char *p) 477f73abda9Skristaps { 47804e980cbSschwarze char *cp; 479769ee804Sschwarze 4807ead8a4eSschwarze if (MDOC_LITERAL & mdoc->flags) 4811cdbf331Sschwarze return; 4821cdbf331Sschwarze 4831cdbf331Sschwarze for (cp = p; NULL != (p = strchr(p, '\t')); p++) 484dd5b31c3Sschwarze mandoc_msg(MANDOCERR_FI_TAB, mdoc->parse, 485dd5b31c3Sschwarze ln, pos + (int)(p - cp), NULL); 486f73abda9Skristaps } 487f73abda9Skristaps 488f73abda9Skristaps static int 489f73abda9Skristaps pre_display(PRE_ARGS) 490f73abda9Skristaps { 491f73abda9Skristaps struct mdoc_node *node; 492f73abda9Skristaps 493f73abda9Skristaps if (MDOC_BLOCK != n->type) 494f73abda9Skristaps return(1); 495f73abda9Skristaps 496f73abda9Skristaps for (node = mdoc->last->parent; node; node = node->parent) 497f73abda9Skristaps if (MDOC_BLOCK == node->type) 498f73abda9Skristaps if (MDOC_Bd == node->tok) 499f73abda9Skristaps break; 50020fa2881Sschwarze 50105c39368Sschwarze if (node) 502b723eac2Sschwarze mandoc_vmsg(MANDOCERR_BD_NEST, 503b723eac2Sschwarze mdoc->parse, n->line, n->pos, 504b723eac2Sschwarze "%s in Bd", mdoc_macronames[n->tok]); 50505c39368Sschwarze 50605c39368Sschwarze return(1); 507f73abda9Skristaps } 508f73abda9Skristaps 509f73abda9Skristaps static int 510f73abda9Skristaps pre_bl(PRE_ARGS) 511f73abda9Skristaps { 512769ee804Sschwarze struct mdoc_node *np; 513aa99c14fSschwarze struct mdoc_argv *argv, *wa; 5144a9f685fSschwarze int i; 515aa99c14fSschwarze enum mdocargt mdoclt; 5164a9f685fSschwarze enum mdoc_list lt; 517f73abda9Skristaps 5186093755cSschwarze if (MDOC_BLOCK != n->type) { 519769ee804Sschwarze if (ENDBODY_NOT != n->end) { 520769ee804Sschwarze assert(n->pending); 521769ee804Sschwarze np = n->pending->parent; 522769ee804Sschwarze } else 523769ee804Sschwarze np = n->parent; 524769ee804Sschwarze 525769ee804Sschwarze assert(np); 526769ee804Sschwarze assert(MDOC_BLOCK == np->type); 527769ee804Sschwarze assert(MDOC_Bl == np->tok); 528f73abda9Skristaps return(1); 5296e03d529Sschwarze } 530f73abda9Skristaps 5316093755cSschwarze /* 5326093755cSschwarze * First figure out which kind of list to use: bind ourselves to 5336093755cSschwarze * the first mentioned list type and warn about any remaining 5346093755cSschwarze * ones. If we find no list type, we default to LIST_item. 5356093755cSschwarze */ 536f73abda9Skristaps 537dadc3a61Sschwarze wa = (n->args == NULL) ? NULL : n->args->argv; 538aa99c14fSschwarze mdoclt = MDOC_ARG_MAX; 5396093755cSschwarze for (i = 0; n->args && i < (int)n->args->argc; i++) { 5404a9f685fSschwarze argv = n->args->argv + i; 5416093755cSschwarze lt = LIST__NONE; 5424a9f685fSschwarze switch (argv->arg) { 5436093755cSschwarze /* Set list types. */ 54449aff9f8Sschwarze case MDOC_Bullet: 5456093755cSschwarze lt = LIST_bullet; 5466093755cSschwarze break; 54749aff9f8Sschwarze case MDOC_Dash: 5486093755cSschwarze lt = LIST_dash; 5496093755cSschwarze break; 55049aff9f8Sschwarze case MDOC_Enum: 5516093755cSschwarze lt = LIST_enum; 5526093755cSschwarze break; 55349aff9f8Sschwarze case MDOC_Hyphen: 5546093755cSschwarze lt = LIST_hyphen; 5556093755cSschwarze break; 55649aff9f8Sschwarze case MDOC_Item: 5576093755cSschwarze lt = LIST_item; 5586093755cSschwarze break; 55949aff9f8Sschwarze case MDOC_Tag: 5606093755cSschwarze lt = LIST_tag; 5616093755cSschwarze break; 56249aff9f8Sschwarze case MDOC_Diag: 5636093755cSschwarze lt = LIST_diag; 5646093755cSschwarze break; 56549aff9f8Sschwarze case MDOC_Hang: 5666093755cSschwarze lt = LIST_hang; 5676093755cSschwarze break; 56849aff9f8Sschwarze case MDOC_Ohang: 5696093755cSschwarze lt = LIST_ohang; 5706093755cSschwarze break; 57149aff9f8Sschwarze case MDOC_Inset: 5726093755cSschwarze lt = LIST_inset; 5736093755cSschwarze break; 57449aff9f8Sschwarze case MDOC_Column: 5756093755cSschwarze lt = LIST_column; 57664d728e4Sschwarze break; 5776093755cSschwarze /* Set list arguments. */ 57849aff9f8Sschwarze case MDOC_Compact: 5794a9f685fSschwarze if (n->norm->Bl.comp) 5804a9f685fSschwarze mandoc_msg(MANDOCERR_ARG_REP, 5814a9f685fSschwarze mdoc->parse, argv->line, 5824a9f685fSschwarze argv->pos, "Bl -compact"); 5834a9f685fSschwarze n->norm->Bl.comp = 1; 58450e63e03Sschwarze break; 58549aff9f8Sschwarze case MDOC_Width: 586aa99c14fSschwarze wa = argv; 5874a9f685fSschwarze if (0 == argv->sz) { 5884a9f685fSschwarze mandoc_msg(MANDOCERR_ARG_EMPTY, 5894a9f685fSschwarze mdoc->parse, argv->line, 5904a9f685fSschwarze argv->pos, "Bl -width"); 5914a9f685fSschwarze n->norm->Bl.width = "0n"; 59222972b14Sschwarze break; 59322972b14Sschwarze } 5944a9f685fSschwarze if (NULL != n->norm->Bl.width) 5954a9f685fSschwarze mandoc_vmsg(MANDOCERR_ARG_REP, 5964a9f685fSschwarze mdoc->parse, argv->line, 5974a9f685fSschwarze argv->pos, "Bl -width %s", 5984a9f685fSschwarze argv->value[0]); 5994a9f685fSschwarze n->norm->Bl.width = argv->value[0]; 60064d728e4Sschwarze break; 60149aff9f8Sschwarze case MDOC_Offset: 6024a9f685fSschwarze if (0 == argv->sz) { 6034a9f685fSschwarze mandoc_msg(MANDOCERR_ARG_EMPTY, 6044a9f685fSschwarze mdoc->parse, argv->line, 6054a9f685fSschwarze argv->pos, "Bl -offset"); 60631e23753Sschwarze break; 60731e23753Sschwarze } 6084a9f685fSschwarze if (NULL != n->norm->Bl.offs) 6094a9f685fSschwarze mandoc_vmsg(MANDOCERR_ARG_REP, 6104a9f685fSschwarze mdoc->parse, argv->line, 6114a9f685fSschwarze argv->pos, "Bl -offset %s", 6124a9f685fSschwarze argv->value[0]); 6134a9f685fSschwarze n->norm->Bl.offs = argv->value[0]; 614f73abda9Skristaps break; 615ddce0b0cSschwarze default: 616ddce0b0cSschwarze continue; 617f73abda9Skristaps } 618dc0d8bb2Sschwarze if (LIST__NONE == lt) 619dc0d8bb2Sschwarze continue; 620aa99c14fSschwarze mdoclt = argv->arg; 621f73abda9Skristaps 6226093755cSschwarze /* Check: multiple list types. */ 6236093755cSschwarze 624dc0d8bb2Sschwarze if (LIST__NONE != n->norm->Bl.type) { 625bd594191Sschwarze mandoc_vmsg(MANDOCERR_BL_REP, 626dc0d8bb2Sschwarze mdoc->parse, n->line, n->pos, 627bd594191Sschwarze "Bl -%s", mdoc_argnames[argv->arg]); 628dc0d8bb2Sschwarze continue; 629769ee804Sschwarze } 6306093755cSschwarze 6316093755cSschwarze /* The list type should come first. */ 6326093755cSschwarze 6338c62fbf5Sschwarze if (n->norm->Bl.width || 6348c62fbf5Sschwarze n->norm->Bl.offs || 6358c62fbf5Sschwarze n->norm->Bl.comp) 636bd594191Sschwarze mandoc_vmsg(MANDOCERR_BL_LATETYPE, 637bd594191Sschwarze mdoc->parse, n->line, n->pos, "Bl -%s", 63866788495Sschwarze mdoc_argnames[n->args->argv[0].arg]); 639dc0d8bb2Sschwarze 640dc0d8bb2Sschwarze n->norm->Bl.type = lt; 641dc0d8bb2Sschwarze if (LIST_column == lt) { 642dc0d8bb2Sschwarze n->norm->Bl.ncols = argv->sz; 643dc0d8bb2Sschwarze n->norm->Bl.cols = (void *)argv->value; 644dc0d8bb2Sschwarze } 6456093755cSschwarze } 6466093755cSschwarze 6476093755cSschwarze /* Allow lists to default to LIST_item. */ 6486093755cSschwarze 6498c62fbf5Sschwarze if (LIST__NONE == n->norm->Bl.type) { 650bd594191Sschwarze mandoc_msg(MANDOCERR_BL_NOTYPE, mdoc->parse, 651bd594191Sschwarze n->line, n->pos, "Bl"); 6528c62fbf5Sschwarze n->norm->Bl.type = LIST_item; 6536e03d529Sschwarze } 654f73abda9Skristaps 65564d728e4Sschwarze /* 65664d728e4Sschwarze * Validate the width field. Some list types don't need width 65764d728e4Sschwarze * types and should be warned about them. Others should have it 6585eced068Sschwarze * and must also be warned. Yet others have a default and need 6595eced068Sschwarze * no warning. 66064d728e4Sschwarze */ 66164d728e4Sschwarze 6628c62fbf5Sschwarze switch (n->norm->Bl.type) { 66349aff9f8Sschwarze case LIST_tag: 6645eced068Sschwarze if (NULL == n->norm->Bl.width) 665bd594191Sschwarze mandoc_msg(MANDOCERR_BL_NOWIDTH, mdoc->parse, 666bd594191Sschwarze n->line, n->pos, "Bl -tag"); 667f73abda9Skristaps break; 66849aff9f8Sschwarze case LIST_column: 6696093755cSschwarze /* FALLTHROUGH */ 67049aff9f8Sschwarze case LIST_diag: 6716093755cSschwarze /* FALLTHROUGH */ 67249aff9f8Sschwarze case LIST_ohang: 6736093755cSschwarze /* FALLTHROUGH */ 67449aff9f8Sschwarze case LIST_inset: 6756093755cSschwarze /* FALLTHROUGH */ 67649aff9f8Sschwarze case LIST_item: 6778c62fbf5Sschwarze if (n->norm->Bl.width) 678aa99c14fSschwarze mandoc_vmsg(MANDOCERR_BL_SKIPW, mdoc->parse, 679aa99c14fSschwarze wa->line, wa->pos, "Bl -%s", 680aa99c14fSschwarze mdoc_argnames[mdoclt]); 6816093755cSschwarze break; 68249aff9f8Sschwarze case LIST_bullet: 6835eced068Sschwarze /* FALLTHROUGH */ 68449aff9f8Sschwarze case LIST_dash: 6855eced068Sschwarze /* FALLTHROUGH */ 68649aff9f8Sschwarze case LIST_hyphen: 6875eced068Sschwarze if (NULL == n->norm->Bl.width) 6885eced068Sschwarze n->norm->Bl.width = "2n"; 6895eced068Sschwarze break; 69049aff9f8Sschwarze case LIST_enum: 6915eced068Sschwarze if (NULL == n->norm->Bl.width) 6925eced068Sschwarze n->norm->Bl.width = "3n"; 6935eced068Sschwarze break; 69464d728e4Sschwarze default: 695f73abda9Skristaps break; 69664d728e4Sschwarze } 69764d728e4Sschwarze 698d52d1586Sschwarze return(pre_par(mdoc, n)); 699f73abda9Skristaps } 700f73abda9Skristaps 701f73abda9Skristaps static int 702f73abda9Skristaps pre_bd(PRE_ARGS) 703f73abda9Skristaps { 704769ee804Sschwarze struct mdoc_node *np; 7054a9f685fSschwarze struct mdoc_argv *argv; 7064a9f685fSschwarze int i; 7074a9f685fSschwarze enum mdoc_disp dt; 708f73abda9Skristaps 709d52d1586Sschwarze pre_literal(mdoc, n); 710d52d1586Sschwarze 71131e23753Sschwarze if (MDOC_BLOCK != n->type) { 712769ee804Sschwarze if (ENDBODY_NOT != n->end) { 713769ee804Sschwarze assert(n->pending); 714769ee804Sschwarze np = n->pending->parent; 715769ee804Sschwarze } else 716769ee804Sschwarze np = n->parent; 717769ee804Sschwarze 718769ee804Sschwarze assert(np); 719769ee804Sschwarze assert(MDOC_BLOCK == np->type); 720769ee804Sschwarze assert(MDOC_Bd == np->tok); 721f73abda9Skristaps return(1); 7226e03d529Sschwarze } 723f73abda9Skristaps 72431e23753Sschwarze for (i = 0; n->args && i < (int)n->args->argc; i++) { 7254a9f685fSschwarze argv = n->args->argv + i; 72631e23753Sschwarze dt = DISP__NONE; 72731e23753Sschwarze 7284a9f685fSschwarze switch (argv->arg) { 72949aff9f8Sschwarze case MDOC_Centred: 7302065e47aSschwarze dt = DISP_centered; 73131e23753Sschwarze break; 73249aff9f8Sschwarze case MDOC_Ragged: 73331e23753Sschwarze dt = DISP_ragged; 73431e23753Sschwarze break; 73549aff9f8Sschwarze case MDOC_Unfilled: 73631e23753Sschwarze dt = DISP_unfilled; 73731e23753Sschwarze break; 73849aff9f8Sschwarze case MDOC_Filled: 73931e23753Sschwarze dt = DISP_filled; 74031e23753Sschwarze break; 74149aff9f8Sschwarze case MDOC_Literal: 74231e23753Sschwarze dt = DISP_literal; 743f73abda9Skristaps break; 74449aff9f8Sschwarze case MDOC_File: 745bd594191Sschwarze mandoc_msg(MANDOCERR_BD_FILE, mdoc->parse, 746bd594191Sschwarze n->line, n->pos, NULL); 7476e03d529Sschwarze return(0); 74849aff9f8Sschwarze case MDOC_Offset: 7494a9f685fSschwarze if (0 == argv->sz) { 7504a9f685fSschwarze mandoc_msg(MANDOCERR_ARG_EMPTY, 7514a9f685fSschwarze mdoc->parse, argv->line, 7524a9f685fSschwarze argv->pos, "Bd -offset"); 753f73abda9Skristaps break; 754f73abda9Skristaps } 7554a9f685fSschwarze if (NULL != n->norm->Bd.offs) 7564a9f685fSschwarze mandoc_vmsg(MANDOCERR_ARG_REP, 7574a9f685fSschwarze mdoc->parse, argv->line, 7584a9f685fSschwarze argv->pos, "Bd -offset %s", 7594a9f685fSschwarze argv->value[0]); 7604a9f685fSschwarze n->norm->Bd.offs = argv->value[0]; 76131e23753Sschwarze break; 76249aff9f8Sschwarze case MDOC_Compact: 7634a9f685fSschwarze if (n->norm->Bd.comp) 7644a9f685fSschwarze mandoc_msg(MANDOCERR_ARG_REP, 7654a9f685fSschwarze mdoc->parse, argv->line, 7664a9f685fSschwarze argv->pos, "Bd -compact"); 7674a9f685fSschwarze n->norm->Bd.comp = 1; 76831e23753Sschwarze break; 76931e23753Sschwarze default: 77031e23753Sschwarze abort(); 77131e23753Sschwarze /* NOTREACHED */ 77231e23753Sschwarze } 773dc0d8bb2Sschwarze if (DISP__NONE == dt) 774dc0d8bb2Sschwarze continue; 77531e23753Sschwarze 776dc0d8bb2Sschwarze if (DISP__NONE == n->norm->Bd.type) 7778c62fbf5Sschwarze n->norm->Bd.type = dt; 778dc0d8bb2Sschwarze else 779bd594191Sschwarze mandoc_vmsg(MANDOCERR_BD_REP, 780dc0d8bb2Sschwarze mdoc->parse, n->line, n->pos, 781bd594191Sschwarze "Bd -%s", mdoc_argnames[argv->arg]); 78231e23753Sschwarze } 78331e23753Sschwarze 7848c62fbf5Sschwarze if (DISP__NONE == n->norm->Bd.type) { 785bd594191Sschwarze mandoc_msg(MANDOCERR_BD_NOTYPE, mdoc->parse, 786bd594191Sschwarze n->line, n->pos, "Bd"); 7878c62fbf5Sschwarze n->norm->Bd.type = DISP_ragged; 78831e23753Sschwarze } 78931e23753Sschwarze 790d52d1586Sschwarze return(pre_par(mdoc, n)); 791f73abda9Skristaps } 792f73abda9Skristaps 793f73abda9Skristaps static int 794f73abda9Skristaps pre_an(PRE_ARGS) 795f73abda9Skristaps { 796aa99c14fSschwarze struct mdoc_argv *argv; 797aa99c14fSschwarze size_t i; 798f73abda9Skristaps 799aa99c14fSschwarze if (n->args == NULL) 800f73abda9Skristaps return(1); 801769ee804Sschwarze 802aa99c14fSschwarze for (i = 1; i < n->args->argc; i++) { 803aa99c14fSschwarze argv = n->args->argv + i; 804aa99c14fSschwarze mandoc_vmsg(MANDOCERR_AN_REP, 805aa99c14fSschwarze mdoc->parse, argv->line, argv->pos, 806aa99c14fSschwarze "An -%s", mdoc_argnames[argv->arg]); 807aa99c14fSschwarze } 8087c2be9f8Sschwarze 809aa99c14fSschwarze argv = n->args->argv; 810aa99c14fSschwarze if (argv->arg == MDOC_Split) 8118c62fbf5Sschwarze n->norm->An.auth = AUTH_split; 812aa99c14fSschwarze else if (argv->arg == MDOC_Nosplit) 8138c62fbf5Sschwarze n->norm->An.auth = AUTH_nosplit; 814769ee804Sschwarze else 815769ee804Sschwarze abort(); 816769ee804Sschwarze 817769ee804Sschwarze return(1); 818f73abda9Skristaps } 819f73abda9Skristaps 820f73abda9Skristaps static int 82120fa2881Sschwarze pre_std(PRE_ARGS) 822f73abda9Skristaps { 823f73abda9Skristaps 82420fa2881Sschwarze if (n->args && 1 == n->args->argc) 82520fa2881Sschwarze if (MDOC_Std == n->args->argv[0].arg) 82620fa2881Sschwarze return(1); 827f73abda9Skristaps 82866788495Sschwarze mandoc_msg(MANDOCERR_ARG_STD, mdoc->parse, 82966788495Sschwarze n->line, n->pos, mdoc_macronames[n->tok]); 8306093755cSschwarze return(1); 8316093755cSschwarze } 8326093755cSschwarze 8336093755cSschwarze static int 834551cd4a8Sschwarze pre_obsolete(PRE_ARGS) 835551cd4a8Sschwarze { 836551cd4a8Sschwarze 837551cd4a8Sschwarze if (MDOC_ELEM == n->type || MDOC_BLOCK == n->type) 838551cd4a8Sschwarze mandoc_msg(MANDOCERR_MACRO_OBS, mdoc->parse, 839551cd4a8Sschwarze n->line, n->pos, mdoc_macronames[n->tok]); 840551cd4a8Sschwarze return(1); 841551cd4a8Sschwarze } 842551cd4a8Sschwarze 843551cd4a8Sschwarze static int 844f73abda9Skristaps pre_dt(PRE_ARGS) 845f73abda9Skristaps { 846f73abda9Skristaps 8473fdead0cSschwarze if (mdoc->meta.title != NULL) 84851fcab2fSschwarze mandoc_msg(MANDOCERR_PROLOG_REP, mdoc->parse, 84951fcab2fSschwarze n->line, n->pos, "Dt"); 8503fdead0cSschwarze else if (mdoc->meta.os != NULL) 8513fdead0cSschwarze mandoc_msg(MANDOCERR_PROLOG_ORDER, mdoc->parse, 8523fdead0cSschwarze n->line, n->pos, "Dt after Os"); 853f73abda9Skristaps return(1); 854f73abda9Skristaps } 855f73abda9Skristaps 856f73abda9Skristaps static int 857f73abda9Skristaps pre_os(PRE_ARGS) 858f73abda9Skristaps { 859f73abda9Skristaps 8603fdead0cSschwarze if (mdoc->meta.os != NULL) 86151fcab2fSschwarze mandoc_msg(MANDOCERR_PROLOG_REP, mdoc->parse, 86251fcab2fSschwarze n->line, n->pos, "Os"); 8633fdead0cSschwarze else if (mdoc->flags & MDOC_PBODY) 8643fdead0cSschwarze mandoc_msg(MANDOCERR_PROLOG_LATE, mdoc->parse, 8653fdead0cSschwarze n->line, n->pos, "Os"); 866f73abda9Skristaps return(1); 867f73abda9Skristaps } 868f73abda9Skristaps 869f73abda9Skristaps static int 870f73abda9Skristaps pre_dd(PRE_ARGS) 871f73abda9Skristaps { 872f73abda9Skristaps 8733fdead0cSschwarze if (mdoc->meta.date != NULL) 87451fcab2fSschwarze mandoc_msg(MANDOCERR_PROLOG_REP, mdoc->parse, 87551fcab2fSschwarze n->line, n->pos, "Dd"); 8763fdead0cSschwarze else if (mdoc->flags & MDOC_PBODY) 8773fdead0cSschwarze mandoc_msg(MANDOCERR_PROLOG_LATE, mdoc->parse, 8783fdead0cSschwarze n->line, n->pos, "Dd"); 8793fdead0cSschwarze else if (mdoc->meta.title != NULL) 8803fdead0cSschwarze mandoc_msg(MANDOCERR_PROLOG_ORDER, mdoc->parse, 8813fdead0cSschwarze n->line, n->pos, "Dd after Dt"); 8823fdead0cSschwarze else if (mdoc->meta.os != NULL) 8833fdead0cSschwarze mandoc_msg(MANDOCERR_PROLOG_ORDER, mdoc->parse, 8843fdead0cSschwarze n->line, n->pos, "Dd after Os"); 885f73abda9Skristaps return(1); 886f73abda9Skristaps } 887f73abda9Skristaps 888f73abda9Skristaps static int 889f73abda9Skristaps post_bf(POST_ARGS) 890f73abda9Skristaps { 891ecb10c32Sschwarze struct mdoc_node *np, *nch; 892ddce0b0cSschwarze enum mdocargt arg; 893f73abda9Skristaps 894769ee804Sschwarze /* 895769ee804Sschwarze * Unlike other data pointers, these are "housed" by the HEAD 896769ee804Sschwarze * element, which contains the goods. 897769ee804Sschwarze */ 898769ee804Sschwarze 899769ee804Sschwarze if (MDOC_HEAD != mdoc->last->type) { 900769ee804Sschwarze if (ENDBODY_NOT != mdoc->last->end) { 901769ee804Sschwarze assert(mdoc->last->pending); 902769ee804Sschwarze np = mdoc->last->pending->parent->head; 903769ee804Sschwarze } else if (MDOC_BLOCK != mdoc->last->type) { 904769ee804Sschwarze np = mdoc->last->parent->head; 905769ee804Sschwarze } else 906769ee804Sschwarze np = mdoc->last->head; 907769ee804Sschwarze 908769ee804Sschwarze assert(np); 909769ee804Sschwarze assert(MDOC_HEAD == np->type); 910769ee804Sschwarze assert(MDOC_Bf == np->tok); 911f73abda9Skristaps return(1); 9126e03d529Sschwarze } 913f73abda9Skristaps 914769ee804Sschwarze np = mdoc->last; 915769ee804Sschwarze assert(MDOC_BLOCK == np->parent->type); 916769ee804Sschwarze assert(MDOC_Bf == np->parent->tok); 91750d41253Sschwarze 918ecb10c32Sschwarze /* Check the number of arguments. */ 919f73abda9Skristaps 920ecb10c32Sschwarze nch = np->child; 921ecb10c32Sschwarze if (NULL == np->parent->args) { 922ecb10c32Sschwarze if (NULL == nch) { 923bd594191Sschwarze mandoc_msg(MANDOCERR_BF_NOFONT, mdoc->parse, 924bd594191Sschwarze np->line, np->pos, "Bf"); 92520fa2881Sschwarze return(1); 92620fa2881Sschwarze } 927ecb10c32Sschwarze nch = nch->next; 928ecb10c32Sschwarze } 929ecb10c32Sschwarze if (NULL != nch) 930ecb10c32Sschwarze mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse, 931ecb10c32Sschwarze nch->line, nch->pos, "Bf ... %s", nch->string); 932769ee804Sschwarze 933769ee804Sschwarze /* Extract argument into data. */ 934769ee804Sschwarze 935769ee804Sschwarze if (np->parent->args) { 936769ee804Sschwarze arg = np->parent->args->argv[0].arg; 937769ee804Sschwarze if (MDOC_Emphasis == arg) 9388c62fbf5Sschwarze np->norm->Bf.font = FONT_Em; 939769ee804Sschwarze else if (MDOC_Literal == arg) 9408c62fbf5Sschwarze np->norm->Bf.font = FONT_Li; 941769ee804Sschwarze else if (MDOC_Symbolic == arg) 9428c62fbf5Sschwarze np->norm->Bf.font = FONT_Sy; 943769ee804Sschwarze else 944769ee804Sschwarze abort(); 945769ee804Sschwarze return(1); 946769ee804Sschwarze } 947769ee804Sschwarze 948769ee804Sschwarze /* Extract parameter into data. */ 949769ee804Sschwarze 950769ee804Sschwarze if (0 == strcmp(np->child->string, "Em")) 9518c62fbf5Sschwarze np->norm->Bf.font = FONT_Em; 952769ee804Sschwarze else if (0 == strcmp(np->child->string, "Li")) 9538c62fbf5Sschwarze np->norm->Bf.font = FONT_Li; 954769ee804Sschwarze else if (0 == strcmp(np->child->string, "Sy")) 9558c62fbf5Sschwarze np->norm->Bf.font = FONT_Sy; 95620fa2881Sschwarze else 957ecb10c32Sschwarze mandoc_vmsg(MANDOCERR_BF_BADFONT, mdoc->parse, 958ecb10c32Sschwarze np->child->line, np->child->pos, 959ecb10c32Sschwarze "Bf %s", np->child->string); 960769ee804Sschwarze 961769ee804Sschwarze return(1); 962f73abda9Skristaps } 963f73abda9Skristaps 964f73abda9Skristaps static int 96571719887Sschwarze post_lb(POST_ARGS) 96671719887Sschwarze { 96777e000ffSschwarze struct mdoc_node *n; 96877e000ffSschwarze const char *stdlibname; 96977e000ffSschwarze char *libname; 97071719887Sschwarze 971bb648afaSschwarze check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 1); 972bb648afaSschwarze 97377e000ffSschwarze n = mdoc->last->child; 97420fa2881Sschwarze 97577e000ffSschwarze assert(n); 97677e000ffSschwarze assert(MDOC_TEXT == n->type); 97720fa2881Sschwarze 97877e000ffSschwarze if (NULL == (stdlibname = mdoc_a2lib(n->string))) 97977e000ffSschwarze mandoc_asprintf(&libname, 98077e000ffSschwarze "library \\(lq%s\\(rq", n->string); 98177e000ffSschwarze else 98277e000ffSschwarze libname = mandoc_strdup(stdlibname); 98320fa2881Sschwarze 98477e000ffSschwarze free(n->string); 98577e000ffSschwarze n->string = libname; 98620fa2881Sschwarze return(1); 98720fa2881Sschwarze } 98871719887Sschwarze 98971719887Sschwarze static int 990b31af00dSschwarze post_eoln(POST_ARGS) 991b31af00dSschwarze { 992ecb10c32Sschwarze const struct mdoc_node *n; 993b31af00dSschwarze 994ecb10c32Sschwarze n = mdoc->last; 995ecb10c32Sschwarze if (n->child) 996ecb10c32Sschwarze mandoc_vmsg(MANDOCERR_ARG_SKIP, 997ecb10c32Sschwarze mdoc->parse, n->line, n->pos, 998ecb10c32Sschwarze "%s %s", mdoc_macronames[n->tok], 999ecb10c32Sschwarze n->child->string); 1000b31af00dSschwarze return(1); 1001b31af00dSschwarze } 1002b31af00dSschwarze 1003b31af00dSschwarze static int 10040c5064e3Sschwarze post_fname(POST_ARGS) 10050c5064e3Sschwarze { 10060c5064e3Sschwarze const struct mdoc_node *n; 1007*0ff14c71Sschwarze const char *cp; 10080c5064e3Sschwarze size_t pos; 10090c5064e3Sschwarze 10100c5064e3Sschwarze n = mdoc->last->child; 10110c5064e3Sschwarze pos = strcspn(n->string, "()"); 1012*0ff14c71Sschwarze cp = n->string + pos; 1013*0ff14c71Sschwarze if ( ! (cp[0] == '\0' || (cp[0] == '(' && cp[1] == '*'))) 10140c5064e3Sschwarze mandoc_msg(MANDOCERR_FN_PAREN, mdoc->parse, 10150c5064e3Sschwarze n->line, n->pos + pos, n->string); 10160c5064e3Sschwarze return(1); 10170c5064e3Sschwarze } 10180c5064e3Sschwarze 10190c5064e3Sschwarze static int 10200c5064e3Sschwarze post_fn(POST_ARGS) 10210c5064e3Sschwarze { 10220c5064e3Sschwarze 10230c5064e3Sschwarze post_fname(mdoc); 10240c5064e3Sschwarze post_fa(mdoc); 10250c5064e3Sschwarze return(1); 10260c5064e3Sschwarze } 10270c5064e3Sschwarze 10280c5064e3Sschwarze static int 1029753701eeSschwarze post_fo(POST_ARGS) 1030753701eeSschwarze { 1031753701eeSschwarze 1032753701eeSschwarze hwarn_eq1(mdoc); 1033753701eeSschwarze bwarn_ge1(mdoc); 1034b8e7c8e3Sschwarze if (mdoc->last->type == MDOC_HEAD && mdoc->last->nchild) 10350c5064e3Sschwarze post_fname(mdoc); 1036753701eeSschwarze return(1); 1037753701eeSschwarze } 1038753701eeSschwarze 1039753701eeSschwarze static int 10407e92c062Sschwarze post_fa(POST_ARGS) 10417e92c062Sschwarze { 10427e92c062Sschwarze const struct mdoc_node *n; 10437e92c062Sschwarze const char *cp; 10447e92c062Sschwarze 10457e92c062Sschwarze for (n = mdoc->last->child; n != NULL; n = n->next) { 10467e92c062Sschwarze for (cp = n->string; *cp != '\0'; cp++) { 10477e92c062Sschwarze /* Ignore callbacks and alterations. */ 10487e92c062Sschwarze if (*cp == '(' || *cp == '{') 10497e92c062Sschwarze break; 10507e92c062Sschwarze if (*cp != ',') 10517e92c062Sschwarze continue; 10527e92c062Sschwarze mandoc_msg(MANDOCERR_FA_COMMA, mdoc->parse, 10537e92c062Sschwarze n->line, n->pos + (cp - n->string), 10547e92c062Sschwarze n->string); 10557e92c062Sschwarze break; 10567e92c062Sschwarze } 10577e92c062Sschwarze } 10587e92c062Sschwarze return(1); 10597e92c062Sschwarze } 10607e92c062Sschwarze 10617e92c062Sschwarze static int 10628521b0bcSschwarze post_vt(POST_ARGS) 10638521b0bcSschwarze { 10648521b0bcSschwarze const struct mdoc_node *n; 10658521b0bcSschwarze 10668521b0bcSschwarze /* 10678521b0bcSschwarze * The Vt macro comes in both ELEM and BLOCK form, both of which 10688521b0bcSschwarze * have different syntaxes (yet more context-sensitive 1069e7a93ef3Sschwarze * behaviour). ELEM types must have a child, which is already 1070e7a93ef3Sschwarze * guaranteed by the in_line parsing routine; BLOCK types, 10718521b0bcSschwarze * specifically the BODY, should only have TEXT children. 10728521b0bcSschwarze */ 10738521b0bcSschwarze 10748521b0bcSschwarze if (MDOC_BODY != mdoc->last->type) 10758521b0bcSschwarze return(1); 10768521b0bcSschwarze 10778521b0bcSschwarze for (n = mdoc->last->child; n; n = n->next) 1078bc49dbe1Sschwarze if (MDOC_TEXT != n->type) 1079dd25b57cSschwarze mandoc_msg(MANDOCERR_VT_CHILD, mdoc->parse, 1080dd25b57cSschwarze n->line, n->pos, mdoc_macronames[n->tok]); 10818521b0bcSschwarze 10828521b0bcSschwarze return(1); 10838521b0bcSschwarze } 10848521b0bcSschwarze 10858521b0bcSschwarze static int 1086f73abda9Skristaps post_nm(POST_ARGS) 1087f73abda9Skristaps { 108820fa2881Sschwarze 1089160ac481Sschwarze if (NULL != mdoc->meta.name) 109020fa2881Sschwarze return(1); 109120fa2881Sschwarze 109283af2bccSschwarze mdoc_deroff(&mdoc->meta.name, mdoc->last); 109320fa2881Sschwarze 1094e214f641Sschwarze if (NULL == mdoc->meta.name) 1095bd594191Sschwarze mandoc_msg(MANDOCERR_NM_NONAME, mdoc->parse, 1096bd594191Sschwarze mdoc->last->line, mdoc->last->pos, "Nm"); 109720fa2881Sschwarze return(1); 109820fa2881Sschwarze } 109920fa2881Sschwarze 110020fa2881Sschwarze static int 1101753701eeSschwarze post_nd(POST_ARGS) 1102753701eeSschwarze { 1103753701eeSschwarze 1104753701eeSschwarze berr_ge1(mdoc); 1105753701eeSschwarze return(post_hyph(mdoc)); 1106753701eeSschwarze } 1107753701eeSschwarze 1108753701eeSschwarze static int 1109753701eeSschwarze post_d1(POST_ARGS) 1110753701eeSschwarze { 1111753701eeSschwarze 1112753701eeSschwarze bwarn_ge1(mdoc); 1113753701eeSschwarze return(post_hyph(mdoc)); 1114753701eeSschwarze } 1115753701eeSschwarze 1116753701eeSschwarze static int 111720fa2881Sschwarze post_literal(POST_ARGS) 111820fa2881Sschwarze { 111920fa2881Sschwarze 1120753701eeSschwarze if (mdoc->last->tok == MDOC_Bd) 1121753701eeSschwarze hwarn_eq0(mdoc); 1122753701eeSschwarze bwarn_ge1(mdoc); 1123753701eeSschwarze 112420fa2881Sschwarze /* 112520fa2881Sschwarze * The `Dl' (note "el" not "one") and `Bd' macros unset the 112620fa2881Sschwarze * MDOC_LITERAL flag as they leave. Note that `Bd' only sets 112720fa2881Sschwarze * this in literal mode, but it doesn't hurt to just switch it 112820fa2881Sschwarze * off in general since displays can't be nested. 112920fa2881Sschwarze */ 113020fa2881Sschwarze 113120fa2881Sschwarze if (MDOC_BODY == mdoc->last->type) 113220fa2881Sschwarze mdoc->flags &= ~MDOC_LITERAL; 113320fa2881Sschwarze 113420fa2881Sschwarze return(1); 113520fa2881Sschwarze } 113620fa2881Sschwarze 113720fa2881Sschwarze static int 113820fa2881Sschwarze post_defaults(POST_ARGS) 113920fa2881Sschwarze { 114020fa2881Sschwarze struct mdoc_node *nn; 114120fa2881Sschwarze 114220fa2881Sschwarze /* 114320fa2881Sschwarze * The `Ar' defaults to "file ..." if no value is provided as an 114420fa2881Sschwarze * argument; the `Mt' and `Pa' macros use "~"; the `Li' just 114520fa2881Sschwarze * gets an empty string. 114620fa2881Sschwarze */ 1147f73abda9Skristaps 1148f73abda9Skristaps if (mdoc->last->child) 1149f73abda9Skristaps return(1); 115020fa2881Sschwarze 115120fa2881Sschwarze nn = mdoc->last; 115220fa2881Sschwarze mdoc->next = MDOC_NEXT_CHILD; 115320fa2881Sschwarze 115420fa2881Sschwarze switch (nn->tok) { 115549aff9f8Sschwarze case MDOC_Ar: 115620fa2881Sschwarze if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "file")) 115720fa2881Sschwarze return(0); 115820fa2881Sschwarze if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "...")) 115920fa2881Sschwarze return(0); 116020fa2881Sschwarze break; 116149aff9f8Sschwarze case MDOC_Li: 116220fa2881Sschwarze if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "")) 116320fa2881Sschwarze return(0); 116420fa2881Sschwarze break; 116549aff9f8Sschwarze case MDOC_Pa: 116620fa2881Sschwarze /* FALLTHROUGH */ 116749aff9f8Sschwarze case MDOC_Mt: 116820fa2881Sschwarze if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "~")) 116920fa2881Sschwarze return(0); 117020fa2881Sschwarze break; 117120fa2881Sschwarze default: 117220fa2881Sschwarze abort(); 117320fa2881Sschwarze /* NOTREACHED */ 1174f73abda9Skristaps } 1175f73abda9Skristaps 117620fa2881Sschwarze mdoc->last = nn; 117720fa2881Sschwarze return(1); 117820fa2881Sschwarze } 1179f73abda9Skristaps 1180f73abda9Skristaps static int 1181f73abda9Skristaps post_at(POST_ARGS) 1182f73abda9Skristaps { 11830b2f1307Sschwarze struct mdoc_node *n; 11840b2f1307Sschwarze const char *std_att; 11850b2f1307Sschwarze char *att; 118620fa2881Sschwarze 1187753701eeSschwarze n = mdoc->last; 1188753701eeSschwarze if (n->child == NULL) { 1189753701eeSschwarze mdoc->next = MDOC_NEXT_CHILD; 1190753701eeSschwarze if ( ! mdoc_word_alloc(mdoc, n->line, n->pos, "AT&T UNIX")) 1191753701eeSschwarze return(0); 1192753701eeSschwarze mdoc->last = n; 1193753701eeSschwarze return(1); 1194753701eeSschwarze } 1195753701eeSschwarze 119620fa2881Sschwarze /* 119720fa2881Sschwarze * If we have a child, look it up in the standard keys. If a 119820fa2881Sschwarze * key exist, use that instead of the child; if it doesn't, 119920fa2881Sschwarze * prefix "AT&T UNIX " to the existing data. 120020fa2881Sschwarze */ 1201f73abda9Skristaps 1202753701eeSschwarze n = n->child; 12030b2f1307Sschwarze assert(MDOC_TEXT == n->type); 12040b2f1307Sschwarze if (NULL == (std_att = mdoc_a2att(n->string))) { 1205bd594191Sschwarze mandoc_vmsg(MANDOCERR_AT_BAD, mdoc->parse, 1206bd594191Sschwarze n->line, n->pos, "At %s", n->string); 12070b2f1307Sschwarze mandoc_asprintf(&att, "AT&T UNIX %s", n->string); 12080b2f1307Sschwarze } else 12090b2f1307Sschwarze att = mandoc_strdup(std_att); 1210f73abda9Skristaps 12110b2f1307Sschwarze free(n->string); 12120b2f1307Sschwarze n->string = att; 121320fa2881Sschwarze return(1); 121420fa2881Sschwarze } 1215f73abda9Skristaps 1216f73abda9Skristaps static int 1217f73abda9Skristaps post_an(POST_ARGS) 1218f73abda9Skristaps { 1219769ee804Sschwarze struct mdoc_node *np; 1220f73abda9Skristaps 1221769ee804Sschwarze np = mdoc->last; 1222e7a93ef3Sschwarze if (AUTH__NONE == np->norm->An.auth) { 1223e7a93ef3Sschwarze if (0 == np->child) 1224e7a93ef3Sschwarze check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_GT, 0); 1225e7a93ef3Sschwarze } else if (np->child) 1226bb648afaSschwarze check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 0); 122720fa2881Sschwarze 122820fa2881Sschwarze return(1); 1229f73abda9Skristaps } 1230f73abda9Skristaps 1231f73abda9Skristaps static int 1232551cd4a8Sschwarze post_en(POST_ARGS) 1233551cd4a8Sschwarze { 1234551cd4a8Sschwarze 1235551cd4a8Sschwarze if (MDOC_BLOCK == mdoc->last->type) 1236551cd4a8Sschwarze mdoc->last->norm->Es = mdoc->last_es; 1237551cd4a8Sschwarze return(1); 1238551cd4a8Sschwarze } 1239551cd4a8Sschwarze 1240551cd4a8Sschwarze static int 1241551cd4a8Sschwarze post_es(POST_ARGS) 1242551cd4a8Sschwarze { 1243551cd4a8Sschwarze 1244551cd4a8Sschwarze mdoc->last_es = mdoc->last; 1245551cd4a8Sschwarze return(1); 1246551cd4a8Sschwarze } 1247551cd4a8Sschwarze 1248551cd4a8Sschwarze static int 1249f73abda9Skristaps post_it(POST_ARGS) 1250f73abda9Skristaps { 125119a69263Sschwarze int i, cols; 12526093755cSschwarze enum mdoc_list lt; 12539530682eSschwarze struct mdoc_node *nbl, *nit, *nch; 1254f73abda9Skristaps 12559530682eSschwarze nit = mdoc->last; 12569530682eSschwarze if (MDOC_BLOCK != nit->type) 1257f73abda9Skristaps return(1); 1258f73abda9Skristaps 12599530682eSschwarze nbl = nit->parent->parent; 12609530682eSschwarze lt = nbl->norm->Bl.type; 12616093755cSschwarze 12626093755cSschwarze switch (lt) { 126349aff9f8Sschwarze case LIST_tag: 12649530682eSschwarze /* FALLTHROUGH */ 126549aff9f8Sschwarze case LIST_hang: 1266f73abda9Skristaps /* FALLTHROUGH */ 126749aff9f8Sschwarze case LIST_ohang: 1268f73abda9Skristaps /* FALLTHROUGH */ 126949aff9f8Sschwarze case LIST_inset: 1270f73abda9Skristaps /* FALLTHROUGH */ 127149aff9f8Sschwarze case LIST_diag: 12729530682eSschwarze if (NULL == nit->head->child) 1273bd594191Sschwarze mandoc_vmsg(MANDOCERR_IT_NOHEAD, 12749530682eSschwarze mdoc->parse, nit->line, nit->pos, 1275bd594191Sschwarze "Bl -%s It", 12769530682eSschwarze mdoc_argnames[nbl->args->argv[0].arg]); 1277f73abda9Skristaps break; 127849aff9f8Sschwarze case LIST_bullet: 1279f73abda9Skristaps /* FALLTHROUGH */ 128049aff9f8Sschwarze case LIST_dash: 1281f73abda9Skristaps /* FALLTHROUGH */ 128249aff9f8Sschwarze case LIST_enum: 1283f73abda9Skristaps /* FALLTHROUGH */ 128449aff9f8Sschwarze case LIST_hyphen: 12859530682eSschwarze if (NULL == nit->body->child) 1286bd594191Sschwarze mandoc_vmsg(MANDOCERR_IT_NOBODY, 128766788495Sschwarze mdoc->parse, nit->line, nit->pos, 1288bd594191Sschwarze "Bl -%s It", 128966788495Sschwarze mdoc_argnames[nbl->args->argv[0].arg]); 1290f73abda9Skristaps /* FALLTHROUGH */ 129149aff9f8Sschwarze case LIST_item: 12929530682eSschwarze if (NULL != nit->head->child) 1293ecb10c32Sschwarze mandoc_vmsg(MANDOCERR_ARG_SKIP, 1294ecb10c32Sschwarze mdoc->parse, nit->line, nit->pos, 1295ecb10c32Sschwarze "It %s", nit->head->child->string); 1296f73abda9Skristaps break; 129749aff9f8Sschwarze case LIST_column: 12989530682eSschwarze cols = (int)nbl->norm->Bl.ncols; 12996093755cSschwarze 13009530682eSschwarze assert(NULL == nit->head->child); 13016093755cSschwarze 13029530682eSschwarze for (i = 0, nch = nit->child; nch; nch = nch->next) 13039530682eSschwarze if (MDOC_BODY == nch->type) 1304f73abda9Skristaps i++; 130553292e81Sschwarze 1306e14c4c11Sschwarze if (i < cols || i > cols + 1) 1307e14c4c11Sschwarze mandoc_vmsg(MANDOCERR_ARGCOUNT, 1308e14c4c11Sschwarze mdoc->parse, nit->line, nit->pos, 13096e03d529Sschwarze "columns == %d (have %d)", cols, i); 1310e14c4c11Sschwarze break; 1311f73abda9Skristaps default: 131266788495Sschwarze abort(); 1313f73abda9Skristaps } 1314f73abda9Skristaps 1315f73abda9Skristaps return(1); 1316f73abda9Skristaps } 1317f73abda9Skristaps 131820fa2881Sschwarze static int 131920fa2881Sschwarze post_bl_block(POST_ARGS) 132020fa2881Sschwarze { 1321bb99f0faSschwarze struct mdoc_node *n, *ni, *nc; 132220fa2881Sschwarze 132320fa2881Sschwarze /* 132420fa2881Sschwarze * These are fairly complicated, so we've broken them into two 132520fa2881Sschwarze * functions. post_bl_block_tag() is called when a -tag is 132620fa2881Sschwarze * specified, but no -width (it must be guessed). The second 132720fa2881Sschwarze * when a -width is specified (macro indicators must be 132820fa2881Sschwarze * rewritten into real lengths). 132920fa2881Sschwarze */ 133020fa2881Sschwarze 133120fa2881Sschwarze n = mdoc->last; 133220fa2881Sschwarze 13338c62fbf5Sschwarze if (LIST_tag == n->norm->Bl.type && 13348c62fbf5Sschwarze NULL == n->norm->Bl.width) { 133520fa2881Sschwarze if ( ! post_bl_block_tag(mdoc)) 133620fa2881Sschwarze return(0); 1337bb99f0faSschwarze assert(n->norm->Bl.width); 13388c62fbf5Sschwarze } else if (NULL != n->norm->Bl.width) { 133920fa2881Sschwarze if ( ! post_bl_block_width(mdoc)) 134020fa2881Sschwarze return(0); 13418c62fbf5Sschwarze assert(n->norm->Bl.width); 1342bb99f0faSschwarze } 1343bb99f0faSschwarze 1344bb99f0faSschwarze for (ni = n->body->child; ni; ni = ni->next) { 1345bb99f0faSschwarze if (NULL == ni->body) 1346bb99f0faSschwarze continue; 1347bb99f0faSschwarze nc = ni->body->last; 1348bb99f0faSschwarze while (NULL != nc) { 1349bb99f0faSschwarze switch (nc->tok) { 135049aff9f8Sschwarze case MDOC_Pp: 1351bb99f0faSschwarze /* FALLTHROUGH */ 135249aff9f8Sschwarze case MDOC_Lp: 1353bb99f0faSschwarze /* FALLTHROUGH */ 135449aff9f8Sschwarze case MDOC_br: 1355bb99f0faSschwarze break; 1356bb99f0faSschwarze default: 1357bb99f0faSschwarze nc = NULL; 1358bb99f0faSschwarze continue; 1359bb99f0faSschwarze } 1360bb99f0faSschwarze if (NULL == ni->next) { 136120369664Sschwarze mandoc_msg(MANDOCERR_PAR_MOVE, 136220369664Sschwarze mdoc->parse, nc->line, nc->pos, 136320369664Sschwarze mdoc_macronames[nc->tok]); 1364bb99f0faSschwarze if ( ! mdoc_node_relink(mdoc, nc)) 1365bb99f0faSschwarze return(0); 1366bb99f0faSschwarze } else if (0 == n->norm->Bl.comp && 1367bb99f0faSschwarze LIST_column != n->norm->Bl.type) { 136820369664Sschwarze mandoc_vmsg(MANDOCERR_PAR_SKIP, 136920369664Sschwarze mdoc->parse, nc->line, nc->pos, 137020369664Sschwarze "%s before It", 137120369664Sschwarze mdoc_macronames[nc->tok]); 1372bb99f0faSschwarze mdoc_node_delete(mdoc, nc); 1373bb99f0faSschwarze } else 1374bb99f0faSschwarze break; 1375bb99f0faSschwarze nc = ni->body->last; 1376bb99f0faSschwarze } 1377bb99f0faSschwarze } 137820fa2881Sschwarze return(1); 137920fa2881Sschwarze } 138020fa2881Sschwarze 138120fa2881Sschwarze static int 138220fa2881Sschwarze post_bl_block_width(POST_ARGS) 138320fa2881Sschwarze { 138420fa2881Sschwarze size_t width; 138520fa2881Sschwarze int i; 138620fa2881Sschwarze enum mdoct tok; 138720fa2881Sschwarze struct mdoc_node *n; 138847813146Sschwarze char buf[24]; 138920fa2881Sschwarze 139020fa2881Sschwarze n = mdoc->last; 139120fa2881Sschwarze 139220fa2881Sschwarze /* 139320fa2881Sschwarze * Calculate the real width of a list from the -width string, 139420fa2881Sschwarze * which may contain a macro (with a known default width), a 139520fa2881Sschwarze * literal string, or a scaling width. 139620fa2881Sschwarze * 139720fa2881Sschwarze * If the value to -width is a macro, then we re-write it to be 139820fa2881Sschwarze * the macro's width as set in share/tmac/mdoc/doc-common. 139920fa2881Sschwarze */ 140020fa2881Sschwarze 14018c62fbf5Sschwarze if (0 == strcmp(n->norm->Bl.width, "Ds")) 140220fa2881Sschwarze width = 6; 14038c62fbf5Sschwarze else if (MDOC_MAX == (tok = mdoc_hash_find(n->norm->Bl.width))) 140420fa2881Sschwarze return(1); 1405dc0d8bb2Sschwarze else 1406dc0d8bb2Sschwarze width = macro2len(tok); 140720fa2881Sschwarze 140820fa2881Sschwarze /* The value already exists: free and reallocate it. */ 140920fa2881Sschwarze 141020fa2881Sschwarze assert(n->args); 141120fa2881Sschwarze 141220fa2881Sschwarze for (i = 0; i < (int)n->args->argc; i++) 141320fa2881Sschwarze if (MDOC_Width == n->args->argv[i].arg) 141420fa2881Sschwarze break; 141520fa2881Sschwarze 141620fa2881Sschwarze assert(i < (int)n->args->argc); 141720fa2881Sschwarze 141847813146Sschwarze (void)snprintf(buf, sizeof(buf), "%un", (unsigned int)width); 141920fa2881Sschwarze free(n->args->argv[i].value[0]); 142020fa2881Sschwarze n->args->argv[i].value[0] = mandoc_strdup(buf); 142120fa2881Sschwarze 142220fa2881Sschwarze /* Set our width! */ 14238c62fbf5Sschwarze n->norm->Bl.width = n->args->argv[i].value[0]; 142420fa2881Sschwarze return(1); 142520fa2881Sschwarze } 142620fa2881Sschwarze 142720fa2881Sschwarze static int 142820fa2881Sschwarze post_bl_block_tag(POST_ARGS) 142920fa2881Sschwarze { 143020fa2881Sschwarze struct mdoc_node *n, *nn; 143120fa2881Sschwarze size_t sz, ssz; 143220fa2881Sschwarze int i; 143347813146Sschwarze char buf[24]; 143420fa2881Sschwarze 143520fa2881Sschwarze /* 143620fa2881Sschwarze * Calculate the -width for a `Bl -tag' list if it hasn't been 143720fa2881Sschwarze * provided. Uses the first head macro. NOTE AGAIN: this is 143820fa2881Sschwarze * ONLY if the -width argument has NOT been provided. See 143920fa2881Sschwarze * post_bl_block_width() for converting the -width string. 144020fa2881Sschwarze */ 144120fa2881Sschwarze 144220fa2881Sschwarze sz = 10; 144320fa2881Sschwarze n = mdoc->last; 144420fa2881Sschwarze 144520fa2881Sschwarze for (nn = n->body->child; nn; nn = nn->next) { 144620fa2881Sschwarze if (MDOC_It != nn->tok) 144720fa2881Sschwarze continue; 144820fa2881Sschwarze 144920fa2881Sschwarze assert(MDOC_BLOCK == nn->type); 145020fa2881Sschwarze nn = nn->head->child; 145120fa2881Sschwarze 145220fa2881Sschwarze if (nn == NULL) 145320fa2881Sschwarze break; 145420fa2881Sschwarze 145520fa2881Sschwarze if (MDOC_TEXT == nn->type) { 145620fa2881Sschwarze sz = strlen(nn->string) + 1; 145720fa2881Sschwarze break; 145820fa2881Sschwarze } 145920fa2881Sschwarze 146019a69263Sschwarze if (0 != (ssz = macro2len(nn->tok))) 146120fa2881Sschwarze sz = ssz; 146220fa2881Sschwarze 146320fa2881Sschwarze break; 146420fa2881Sschwarze } 146520fa2881Sschwarze 146620fa2881Sschwarze /* Defaults to ten ens. */ 146720fa2881Sschwarze 146847813146Sschwarze (void)snprintf(buf, sizeof(buf), "%un", (unsigned int)sz); 146920fa2881Sschwarze 147020fa2881Sschwarze /* 147120fa2881Sschwarze * We have to dynamically add this to the macro's argument list. 147220fa2881Sschwarze * We're guaranteed that a MDOC_Width doesn't already exist. 147320fa2881Sschwarze */ 147420fa2881Sschwarze 147520fa2881Sschwarze assert(n->args); 147620fa2881Sschwarze i = (int)(n->args->argc)++; 147720fa2881Sschwarze 14788286bf36Sschwarze n->args->argv = mandoc_reallocarray(n->args->argv, 14798286bf36Sschwarze n->args->argc, sizeof(struct mdoc_argv)); 148020fa2881Sschwarze 148120fa2881Sschwarze n->args->argv[i].arg = MDOC_Width; 148220fa2881Sschwarze n->args->argv[i].line = n->line; 148320fa2881Sschwarze n->args->argv[i].pos = n->pos; 148420fa2881Sschwarze n->args->argv[i].sz = 1; 148520fa2881Sschwarze n->args->argv[i].value = mandoc_malloc(sizeof(char *)); 148620fa2881Sschwarze n->args->argv[i].value[0] = mandoc_strdup(buf); 148720fa2881Sschwarze 148820fa2881Sschwarze /* Set our width! */ 14898c62fbf5Sschwarze n->norm->Bl.width = n->args->argv[i].value[0]; 149020fa2881Sschwarze return(1); 149120fa2881Sschwarze } 149220fa2881Sschwarze 1493f73abda9Skristaps static int 1494395185ccSschwarze post_bl_head(POST_ARGS) 1495395185ccSschwarze { 149620fa2881Sschwarze struct mdoc_node *np, *nn, *nnp; 1497f5174743Sschwarze struct mdoc_argv *argv; 149820fa2881Sschwarze int i, j; 1499395185ccSschwarze 15008c62fbf5Sschwarze if (LIST_column != mdoc->last->norm->Bl.type) 150120fa2881Sschwarze /* FIXME: this should be ERROR class... */ 150220fa2881Sschwarze return(hwarn_eq0(mdoc)); 1503395185ccSschwarze 150420fa2881Sschwarze /* 1505f5174743Sschwarze * Append old-style lists, where the column width specifiers 150620fa2881Sschwarze * trail as macro parameters, to the new-style ("normal-form") 150720fa2881Sschwarze * lists where they're argument values following -column. 150820fa2881Sschwarze */ 150920fa2881Sschwarze 1510f5174743Sschwarze if (mdoc->last->child == NULL) 151120fa2881Sschwarze return(1); 151220fa2881Sschwarze 151320fa2881Sschwarze np = mdoc->last->parent; 151420fa2881Sschwarze assert(np->args); 151520fa2881Sschwarze 151620fa2881Sschwarze for (j = 0; j < (int)np->args->argc; j++) 151720fa2881Sschwarze if (MDOC_Column == np->args->argv[j].arg) 151820fa2881Sschwarze break; 151920fa2881Sschwarze 152020fa2881Sschwarze assert(j < (int)np->args->argc); 152120fa2881Sschwarze 152220fa2881Sschwarze /* 1523a5e11edeSschwarze * Accommodate for new-style groff column syntax. Shuffle the 152420fa2881Sschwarze * child nodes, all of which must be TEXT, as arguments for the 152520fa2881Sschwarze * column field. Then, delete the head children. 152620fa2881Sschwarze */ 152720fa2881Sschwarze 1528f5174743Sschwarze argv = np->args->argv + j; 1529f5174743Sschwarze i = argv->sz; 1530f5174743Sschwarze argv->sz += mdoc->last->nchild; 1531f5174743Sschwarze argv->value = mandoc_reallocarray(argv->value, 1532f5174743Sschwarze argv->sz, sizeof(char *)); 153320fa2881Sschwarze 1534f5174743Sschwarze mdoc->last->norm->Bl.ncols = argv->sz; 1535f5174743Sschwarze mdoc->last->norm->Bl.cols = (void *)argv->value; 153620fa2881Sschwarze 1537f5174743Sschwarze for (nn = mdoc->last->child; nn; i++) { 1538f5174743Sschwarze argv->value[i] = nn->string; 153920fa2881Sschwarze nn->string = NULL; 154020fa2881Sschwarze nnp = nn; 154120fa2881Sschwarze nn = nn->next; 154220fa2881Sschwarze mdoc_node_delete(NULL, nnp); 1543395185ccSschwarze } 154420fa2881Sschwarze 154520fa2881Sschwarze mdoc->last->nchild = 0; 154620fa2881Sschwarze mdoc->last->child = NULL; 154720fa2881Sschwarze 15486093755cSschwarze return(1); 1549b16e7ddfSschwarze } 1550b16e7ddfSschwarze 1551395185ccSschwarze static int 1552f73abda9Skristaps post_bl(POST_ARGS) 1553f73abda9Skristaps { 15542a427d60Sschwarze struct mdoc_node *nparent, *nprev; /* of the Bl block */ 15552a427d60Sschwarze struct mdoc_node *nblock, *nbody; /* of the Bl */ 15562a427d60Sschwarze struct mdoc_node *nchild, *nnext; /* of the Bl body */ 1557f73abda9Skristaps 15582a427d60Sschwarze nbody = mdoc->last; 15592a427d60Sschwarze switch (nbody->type) { 156049aff9f8Sschwarze case MDOC_BLOCK: 156120fa2881Sschwarze return(post_bl_block(mdoc)); 156249aff9f8Sschwarze case MDOC_HEAD: 15632a427d60Sschwarze return(post_bl_head(mdoc)); 156449aff9f8Sschwarze case MDOC_BODY: 1565f6127a73Sschwarze break; 15662a427d60Sschwarze default: 15672a427d60Sschwarze return(1); 1568f6127a73Sschwarze } 1569f6127a73Sschwarze 1570753701eeSschwarze bwarn_ge1(mdoc); 1571753701eeSschwarze 15722a427d60Sschwarze nchild = nbody->child; 15732a427d60Sschwarze while (NULL != nchild) { 15742a427d60Sschwarze if (MDOC_It == nchild->tok || MDOC_Sm == nchild->tok) { 15752a427d60Sschwarze nchild = nchild->next; 15762a427d60Sschwarze continue; 15772a427d60Sschwarze } 15782a427d60Sschwarze 1579dd25b57cSschwarze mandoc_msg(MANDOCERR_BL_MOVE, mdoc->parse, 1580dd25b57cSschwarze nchild->line, nchild->pos, 1581dd25b57cSschwarze mdoc_macronames[nchild->tok]); 15822a427d60Sschwarze 15832a427d60Sschwarze /* 15842a427d60Sschwarze * Move the node out of the Bl block. 15852a427d60Sschwarze * First, collect all required node pointers. 15862a427d60Sschwarze */ 15872a427d60Sschwarze 15882a427d60Sschwarze nblock = nbody->parent; 15892a427d60Sschwarze nprev = nblock->prev; 15902a427d60Sschwarze nparent = nblock->parent; 15912a427d60Sschwarze nnext = nchild->next; 15922a427d60Sschwarze 15932a427d60Sschwarze /* 15942a427d60Sschwarze * Unlink this child. 15952a427d60Sschwarze */ 15962a427d60Sschwarze 15972a427d60Sschwarze assert(NULL == nchild->prev); 15982a427d60Sschwarze if (0 == --nbody->nchild) { 15992a427d60Sschwarze nbody->child = NULL; 16002a427d60Sschwarze nbody->last = NULL; 16012a427d60Sschwarze assert(NULL == nnext); 16022a427d60Sschwarze } else { 16032a427d60Sschwarze nbody->child = nnext; 16042a427d60Sschwarze nnext->prev = NULL; 16052a427d60Sschwarze } 16062a427d60Sschwarze 16072a427d60Sschwarze /* 16082a427d60Sschwarze * Relink this child. 16092a427d60Sschwarze */ 16102a427d60Sschwarze 16112a427d60Sschwarze nchild->parent = nparent; 16122a427d60Sschwarze nchild->prev = nprev; 16132a427d60Sschwarze nchild->next = nblock; 16142a427d60Sschwarze 16152a427d60Sschwarze nblock->prev = nchild; 16162a427d60Sschwarze nparent->nchild++; 16172a427d60Sschwarze if (NULL == nprev) 16182a427d60Sschwarze nparent->child = nchild; 16192a427d60Sschwarze else 16202a427d60Sschwarze nprev->next = nchild; 16212a427d60Sschwarze 16222a427d60Sschwarze nchild = nnext; 1623f73abda9Skristaps } 1624f73abda9Skristaps 1625f73abda9Skristaps return(1); 1626f73abda9Skristaps } 1627f73abda9Skristaps 1628f73abda9Skristaps static int 1629753701eeSschwarze post_bk(POST_ARGS) 1630753701eeSschwarze { 1631753701eeSschwarze 1632753701eeSschwarze hwarn_eq0(mdoc); 1633753701eeSschwarze bwarn_ge1(mdoc); 1634753701eeSschwarze return(1); 1635753701eeSschwarze } 1636753701eeSschwarze 1637753701eeSschwarze static int 1638f73abda9Skristaps ebool(struct mdoc *mdoc) 1639f73abda9Skristaps { 1640dc0d8bb2Sschwarze struct mdoc_node *nch; 1641dc0d8bb2Sschwarze enum mdoct tok; 1642f73abda9Skristaps 1643dc0d8bb2Sschwarze tok = mdoc->last->tok; 1644dc0d8bb2Sschwarze nch = mdoc->last->child; 1645dc0d8bb2Sschwarze 1646dc0d8bb2Sschwarze if (NULL == nch) { 1647dc0d8bb2Sschwarze if (MDOC_Sm == tok) 1648f9e7bf99Sschwarze mdoc->flags ^= MDOC_SMOFF; 1649f73abda9Skristaps return(1); 1650bb648afaSschwarze } 1651f9e7bf99Sschwarze 1652f9e7bf99Sschwarze check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_LT, 2); 1653f73abda9Skristaps 1654dc0d8bb2Sschwarze assert(MDOC_TEXT == nch->type); 165520fa2881Sschwarze 1656dc0d8bb2Sschwarze if (0 == strcmp(nch->string, "on")) { 1657dc0d8bb2Sschwarze if (MDOC_Sm == tok) 1658ec2beb53Sschwarze mdoc->flags &= ~MDOC_SMOFF; 165920fa2881Sschwarze return(1); 1660ec2beb53Sschwarze } 1661dc0d8bb2Sschwarze if (0 == strcmp(nch->string, "off")) { 1662dc0d8bb2Sschwarze if (MDOC_Sm == tok) 1663ec2beb53Sschwarze mdoc->flags |= MDOC_SMOFF; 166420fa2881Sschwarze return(1); 1665ec2beb53Sschwarze } 166620fa2881Sschwarze 1667dc0d8bb2Sschwarze mandoc_vmsg(MANDOCERR_SM_BAD, 1668dc0d8bb2Sschwarze mdoc->parse, nch->line, nch->pos, 1669dc0d8bb2Sschwarze "%s %s", mdoc_macronames[tok], nch->string); 1670dc0d8bb2Sschwarze return(mdoc_node_relink(mdoc, nch)); 167120fa2881Sschwarze } 1672f73abda9Skristaps 1673f73abda9Skristaps static int 1674f73abda9Skristaps post_root(POST_ARGS) 1675f73abda9Skristaps { 167620fa2881Sschwarze struct mdoc_node *n; 1677f73abda9Skristaps 1678ac1f49d0Sschwarze /* Add missing prologue data. */ 167920fa2881Sschwarze 1680ac1f49d0Sschwarze if (mdoc->meta.date == NULL) 1681ac1f49d0Sschwarze mdoc->meta.date = mdoc->quick ? 1682ac1f49d0Sschwarze mandoc_strdup("") : 1683ac1f49d0Sschwarze mandoc_normdate(mdoc->parse, NULL, 0, 0); 16843fdead0cSschwarze 16853fdead0cSschwarze if (mdoc->meta.title == NULL) { 16863fdead0cSschwarze mandoc_msg(MANDOCERR_DT_NOTITLE, 16873fdead0cSschwarze mdoc->parse, 0, 0, "EOF"); 16883fdead0cSschwarze mdoc->meta.title = mandoc_strdup("UNTITLED"); 16893fdead0cSschwarze } 16903fdead0cSschwarze 1691ac1f49d0Sschwarze if (mdoc->meta.vol == NULL) 1692ac1f49d0Sschwarze mdoc->meta.vol = mandoc_strdup("LOCAL"); 16933fdead0cSschwarze 16943fdead0cSschwarze if (mdoc->meta.os == NULL) { 16953fdead0cSschwarze mandoc_msg(MANDOCERR_OS_MISSING, 16963fdead0cSschwarze mdoc->parse, 0, 0, NULL); 16973fdead0cSschwarze mdoc->meta.os = mandoc_strdup(""); 1698f73abda9Skristaps } 1699f73abda9Skristaps 170020fa2881Sschwarze /* Check that we begin with a proper `Sh'. */ 170120fa2881Sschwarze 1702e20417bdSschwarze n = mdoc->first->child; 1703e20417bdSschwarze while (n != NULL && mdoc_macros[n->tok].flags & MDOC_PROLOGUE) 1704e20417bdSschwarze n = n->next; 1705e20417bdSschwarze 1706e20417bdSschwarze if (n == NULL) 1707e20417bdSschwarze mandoc_msg(MANDOCERR_DOC_EMPTY, mdoc->parse, 0, 0, NULL); 1708e20417bdSschwarze else if (n->tok != MDOC_Sh) 170951fcab2fSschwarze mandoc_msg(MANDOCERR_SEC_BEFORE, mdoc->parse, 1710e20417bdSschwarze n->line, n->pos, mdoc_macronames[n->tok]); 171120fa2881Sschwarze 1712ac1f49d0Sschwarze return(1); 171320fa2881Sschwarze } 1714f73abda9Skristaps 1715f73abda9Skristaps static int 1716f73abda9Skristaps post_st(POST_ARGS) 1717f73abda9Skristaps { 1718dc0d8bb2Sschwarze struct mdoc_node *n, *nch; 171920fa2881Sschwarze const char *p; 1720f73abda9Skristaps 1721dc0d8bb2Sschwarze n = mdoc->last; 1722dc0d8bb2Sschwarze nch = n->child; 1723dc0d8bb2Sschwarze 1724dc0d8bb2Sschwarze if (NULL == nch) { 1725307e5a07Sschwarze mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse, 1726dc0d8bb2Sschwarze n->line, n->pos, mdoc_macronames[n->tok]); 1727dc0d8bb2Sschwarze mdoc_node_delete(mdoc, n); 1728bb648afaSschwarze return(1); 1729bb648afaSschwarze } 173020fa2881Sschwarze 1731dc0d8bb2Sschwarze assert(MDOC_TEXT == nch->type); 173220fa2881Sschwarze 1733dc0d8bb2Sschwarze if (NULL == (p = mdoc_a2st(nch->string))) { 1734bd594191Sschwarze mandoc_vmsg(MANDOCERR_ST_BAD, mdoc->parse, 1735bd594191Sschwarze nch->line, nch->pos, "St %s", nch->string); 1736dc0d8bb2Sschwarze mdoc_node_delete(mdoc, n); 173720fa2881Sschwarze } else { 1738dc0d8bb2Sschwarze free(nch->string); 1739dc0d8bb2Sschwarze nch->string = mandoc_strdup(p); 1740f73abda9Skristaps } 1741f73abda9Skristaps 174220fa2881Sschwarze return(1); 174320fa2881Sschwarze } 1744f73abda9Skristaps 1745f73abda9Skristaps static int 1746011fe33bSschwarze post_rs(POST_ARGS) 1747011fe33bSschwarze { 174820fa2881Sschwarze struct mdoc_node *nn, *next, *prev; 174920fa2881Sschwarze int i, j; 1750011fe33bSschwarze 1751bb648afaSschwarze switch (mdoc->last->type) { 175249aff9f8Sschwarze case MDOC_HEAD: 1753bb648afaSschwarze check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_EQ, 0); 1754011fe33bSschwarze return(1); 175549aff9f8Sschwarze case MDOC_BODY: 1756bb648afaSschwarze if (mdoc->last->child) 1757bb648afaSschwarze break; 1758bb648afaSschwarze check_count(mdoc, MDOC_BODY, CHECK_WARN, CHECK_GT, 0); 1759bb648afaSschwarze return(1); 1760bb648afaSschwarze default: 1761bb648afaSschwarze return(1); 1762bb648afaSschwarze } 1763011fe33bSschwarze 176420fa2881Sschwarze /* 176520fa2881Sschwarze * The full `Rs' block needs special handling to order the 176620fa2881Sschwarze * sub-elements according to `rsord'. Pick through each element 1767b538baa5Sschwarze * and correctly order it. This is an insertion sort. 176820fa2881Sschwarze */ 176920fa2881Sschwarze 177020fa2881Sschwarze next = NULL; 177120fa2881Sschwarze for (nn = mdoc->last->child->next; nn; nn = next) { 177220fa2881Sschwarze /* Determine order of `nn'. */ 177320fa2881Sschwarze for (i = 0; i < RSORD_MAX; i++) 177420fa2881Sschwarze if (rsord[i] == nn->tok) 177520fa2881Sschwarze break; 177620fa2881Sschwarze 1777b538baa5Sschwarze if (i == RSORD_MAX) { 1778b538baa5Sschwarze mandoc_msg(MANDOCERR_RS_BAD, 1779b538baa5Sschwarze mdoc->parse, nn->line, nn->pos, 1780b538baa5Sschwarze mdoc_macronames[nn->tok]); 1781b538baa5Sschwarze i = -1; 1782b538baa5Sschwarze } else if (MDOC__J == nn->tok || MDOC__B == nn->tok) 1783b538baa5Sschwarze mdoc->last->norm->Rs.quote_T++; 1784b538baa5Sschwarze 178520fa2881Sschwarze /* 178620fa2881Sschwarze * Remove `nn' from the chain. This somewhat 178720fa2881Sschwarze * repeats mdoc_node_unlink(), but since we're 178820fa2881Sschwarze * just re-ordering, there's no need for the 178920fa2881Sschwarze * full unlink process. 179020fa2881Sschwarze */ 179120fa2881Sschwarze 179220fa2881Sschwarze if (NULL != (next = nn->next)) 179320fa2881Sschwarze next->prev = nn->prev; 179420fa2881Sschwarze 179520fa2881Sschwarze if (NULL != (prev = nn->prev)) 179620fa2881Sschwarze prev->next = nn->next; 179720fa2881Sschwarze 179820fa2881Sschwarze nn->prev = nn->next = NULL; 179920fa2881Sschwarze 180020fa2881Sschwarze /* 180120fa2881Sschwarze * Scan back until we reach a node that's 180220fa2881Sschwarze * ordered before `nn'. 180320fa2881Sschwarze */ 180420fa2881Sschwarze 180520fa2881Sschwarze for ( ; prev ; prev = prev->prev) { 180620fa2881Sschwarze /* Determine order of `prev'. */ 180720fa2881Sschwarze for (j = 0; j < RSORD_MAX; j++) 180820fa2881Sschwarze if (rsord[j] == prev->tok) 180920fa2881Sschwarze break; 1810b538baa5Sschwarze if (j == RSORD_MAX) 1811b538baa5Sschwarze j = -1; 181220fa2881Sschwarze 181320fa2881Sschwarze if (j <= i) 181420fa2881Sschwarze break; 181520fa2881Sschwarze } 181620fa2881Sschwarze 181720fa2881Sschwarze /* 181820fa2881Sschwarze * Set `nn' back into its correct place in front 181920fa2881Sschwarze * of the `prev' node. 182020fa2881Sschwarze */ 182120fa2881Sschwarze 182220fa2881Sschwarze nn->prev = prev; 182320fa2881Sschwarze 182420fa2881Sschwarze if (prev) { 182520fa2881Sschwarze if (prev->next) 182620fa2881Sschwarze prev->next->prev = nn; 182720fa2881Sschwarze nn->next = prev->next; 182820fa2881Sschwarze prev->next = nn; 182920fa2881Sschwarze } else { 183020fa2881Sschwarze mdoc->last->child->prev = nn; 183120fa2881Sschwarze nn->next = mdoc->last->child; 183220fa2881Sschwarze mdoc->last->child = nn; 183320fa2881Sschwarze } 1834011fe33bSschwarze } 1835011fe33bSschwarze 1836011fe33bSschwarze return(1); 1837011fe33bSschwarze } 1838011fe33bSschwarze 18394039b21cSschwarze /* 18404039b21cSschwarze * For some arguments of some macros, 18414039b21cSschwarze * convert all breakable hyphens into ASCII_HYPH. 18424039b21cSschwarze */ 18434039b21cSschwarze static int 18444039b21cSschwarze post_hyph(POST_ARGS) 18454039b21cSschwarze { 18464039b21cSschwarze struct mdoc_node *n, *nch; 18474039b21cSschwarze char *cp; 18484039b21cSschwarze 18494039b21cSschwarze n = mdoc->last; 18504039b21cSschwarze switch (n->type) { 185149aff9f8Sschwarze case MDOC_HEAD: 18524039b21cSschwarze if (MDOC_Sh == n->tok || MDOC_Ss == n->tok) 18534039b21cSschwarze break; 18544039b21cSschwarze return(1); 185549aff9f8Sschwarze case MDOC_BODY: 18564039b21cSschwarze if (MDOC_D1 == n->tok || MDOC_Nd == n->tok) 18574039b21cSschwarze break; 18584039b21cSschwarze return(1); 185949aff9f8Sschwarze case MDOC_ELEM: 18604039b21cSschwarze break; 18614039b21cSschwarze default: 18624039b21cSschwarze return(1); 18634039b21cSschwarze } 18644039b21cSschwarze 18654039b21cSschwarze for (nch = n->child; nch; nch = nch->next) { 18664039b21cSschwarze if (MDOC_TEXT != nch->type) 18674039b21cSschwarze continue; 18684039b21cSschwarze cp = nch->string; 1869b7e2b14eSschwarze if ('\0' == *cp) 18704039b21cSschwarze continue; 18714039b21cSschwarze while ('\0' != *(++cp)) 18724039b21cSschwarze if ('-' == *cp && 18734039b21cSschwarze isalpha((unsigned char)cp[-1]) && 18744039b21cSschwarze isalpha((unsigned char)cp[1])) 18754039b21cSschwarze *cp = ASCII_HYPH; 18764039b21cSschwarze } 18774039b21cSschwarze return(1); 18784039b21cSschwarze } 18794039b21cSschwarze 1880011fe33bSschwarze static int 1881753701eeSschwarze post_hyphtext(POST_ARGS) 1882753701eeSschwarze { 1883753701eeSschwarze 1884753701eeSschwarze ewarn_ge1(mdoc); 1885753701eeSschwarze return(post_hyph(mdoc)); 1886753701eeSschwarze } 1887753701eeSschwarze 1888753701eeSschwarze static int 1889af216717Sschwarze post_ns(POST_ARGS) 1890af216717Sschwarze { 1891af216717Sschwarze 1892af216717Sschwarze if (MDOC_LINE & mdoc->last->flags) 189328153913Sschwarze mandoc_msg(MANDOCERR_NS_SKIP, mdoc->parse, 189428153913Sschwarze mdoc->last->line, mdoc->last->pos, NULL); 1895af216717Sschwarze return(1); 1896af216717Sschwarze } 1897af216717Sschwarze 1898af216717Sschwarze static int 1899f73abda9Skristaps post_sh(POST_ARGS) 1900f73abda9Skristaps { 1901f73abda9Skristaps 1902753701eeSschwarze post_ignpar(mdoc); 1903753701eeSschwarze 1904cd6c268fSschwarze switch (mdoc->last->type) { 1905cd6c268fSschwarze case MDOC_HEAD: 1906f73abda9Skristaps return(post_sh_head(mdoc)); 1907cd6c268fSschwarze case MDOC_BODY: 1908cd6c268fSschwarze switch (mdoc->lastsec) { 1909cd6c268fSschwarze case SEC_NAME: 1910cd6c268fSschwarze return(post_sh_name(mdoc)); 19117c384856Sschwarze case SEC_SEE_ALSO: 19127c384856Sschwarze return(post_sh_see_also(mdoc)); 1913cd6c268fSschwarze case SEC_AUTHORS: 1914cd6c268fSschwarze return(post_sh_authors(mdoc)); 1915cd6c268fSschwarze default: 1916cd6c268fSschwarze break; 1917cd6c268fSschwarze } 1918cd6c268fSschwarze break; 1919cd6c268fSschwarze default: 1920cd6c268fSschwarze break; 1921cd6c268fSschwarze } 1922f73abda9Skristaps 1923f73abda9Skristaps return(1); 1924f73abda9Skristaps } 1925f73abda9Skristaps 1926f73abda9Skristaps static int 1927cd6c268fSschwarze post_sh_name(POST_ARGS) 1928f73abda9Skristaps { 1929f73abda9Skristaps struct mdoc_node *n; 1930f73abda9Skristaps 1931f73abda9Skristaps /* 1932f73abda9Skristaps * Warn if the NAME section doesn't contain the `Nm' and `Nd' 1933f73abda9Skristaps * macros (can have multiple `Nm' and one `Nd'). Note that the 1934f73abda9Skristaps * children of the BODY declaration can also be "text". 1935f73abda9Skristaps */ 1936f73abda9Skristaps 193720fa2881Sschwarze if (NULL == (n = mdoc->last->child)) { 193851fcab2fSschwarze mandoc_msg(MANDOCERR_NAMESEC_BAD, mdoc->parse, 193951fcab2fSschwarze mdoc->last->line, mdoc->last->pos, "empty"); 194020fa2881Sschwarze return(1); 194120fa2881Sschwarze } 1942f73abda9Skristaps 1943f73abda9Skristaps for ( ; n && n->next; n = n->next) { 1944f73abda9Skristaps if (MDOC_ELEM == n->type && MDOC_Nm == n->tok) 1945f73abda9Skristaps continue; 1946f73abda9Skristaps if (MDOC_TEXT == n->type) 1947f73abda9Skristaps continue; 194851fcab2fSschwarze mandoc_msg(MANDOCERR_NAMESEC_BAD, mdoc->parse, 194951fcab2fSschwarze n->line, n->pos, mdoc_macronames[n->tok]); 1950f73abda9Skristaps } 1951f73abda9Skristaps 195249d529b5Sschwarze assert(n); 19534602e85cSschwarze if (MDOC_BLOCK == n->type && MDOC_Nd == n->tok) 1954f73abda9Skristaps return(1); 1955f73abda9Skristaps 195651fcab2fSschwarze mandoc_msg(MANDOCERR_NAMESEC_BAD, mdoc->parse, 195751fcab2fSschwarze n->line, n->pos, mdoc_macronames[n->tok]); 195820fa2881Sschwarze return(1); 195920fa2881Sschwarze } 1960f73abda9Skristaps 1961f73abda9Skristaps static int 19627c384856Sschwarze post_sh_see_also(POST_ARGS) 19637c384856Sschwarze { 19647c384856Sschwarze const struct mdoc_node *n; 19657c384856Sschwarze const char *name, *sec; 19667c384856Sschwarze const char *lastname, *lastsec, *lastpunct; 19677c384856Sschwarze int cmp; 19687c384856Sschwarze 19697c384856Sschwarze n = mdoc->last->child; 19707c384856Sschwarze lastname = lastsec = lastpunct = NULL; 19717c384856Sschwarze while (n != NULL) { 19727c384856Sschwarze if (n->tok != MDOC_Xr || n->nchild < 2) 19737c384856Sschwarze break; 19747c384856Sschwarze 19757c384856Sschwarze /* Process one .Xr node. */ 19767c384856Sschwarze 19777c384856Sschwarze name = n->child->string; 19787c384856Sschwarze sec = n->child->next->string; 19797c384856Sschwarze if (lastsec != NULL) { 19807c384856Sschwarze if (lastpunct[0] != ',' || lastpunct[1] != '\0') 19817c384856Sschwarze mandoc_vmsg(MANDOCERR_XR_PUNCT, 19827c384856Sschwarze mdoc->parse, n->line, n->pos, 19837c384856Sschwarze "%s before %s(%s)", lastpunct, 19847c384856Sschwarze name, sec); 19857c384856Sschwarze cmp = strcmp(lastsec, sec); 19867c384856Sschwarze if (cmp > 0) 19877c384856Sschwarze mandoc_vmsg(MANDOCERR_XR_ORDER, 19887c384856Sschwarze mdoc->parse, n->line, n->pos, 19897c384856Sschwarze "%s(%s) after %s(%s)", name, 19907c384856Sschwarze sec, lastname, lastsec); 19917c384856Sschwarze else if (cmp == 0 && 19927c384856Sschwarze strcasecmp(lastname, name) > 0) 19937c384856Sschwarze mandoc_vmsg(MANDOCERR_XR_ORDER, 19947c384856Sschwarze mdoc->parse, n->line, n->pos, 19957c384856Sschwarze "%s after %s", name, lastname); 19967c384856Sschwarze } 19977c384856Sschwarze lastname = name; 19987c384856Sschwarze lastsec = sec; 19997c384856Sschwarze 20007c384856Sschwarze /* Process the following node. */ 20017c384856Sschwarze 20027c384856Sschwarze n = n->next; 20037c384856Sschwarze if (n == NULL) 20047c384856Sschwarze break; 20057c384856Sschwarze if (n->tok == MDOC_Xr) { 20067c384856Sschwarze lastpunct = "none"; 20077c384856Sschwarze continue; 20087c384856Sschwarze } 20097c384856Sschwarze if (n->type != MDOC_TEXT) 20107c384856Sschwarze break; 20117c384856Sschwarze for (name = n->string; *name != '\0'; name++) 20127c384856Sschwarze if (isalpha((const unsigned char)*name)) 20137c384856Sschwarze return(1); 20147c384856Sschwarze lastpunct = n->string; 20157c384856Sschwarze if (n->next == NULL) 20167c384856Sschwarze mandoc_vmsg(MANDOCERR_XR_PUNCT, mdoc->parse, 20177c384856Sschwarze n->line, n->pos, "%s after %s(%s)", 20187c384856Sschwarze lastpunct, lastname, lastsec); 20197c384856Sschwarze n = n->next; 20207c384856Sschwarze } 20217c384856Sschwarze return(1); 20227c384856Sschwarze } 20237c384856Sschwarze 20247c384856Sschwarze static int 2025cd6c268fSschwarze child_an(const struct mdoc_node *n) 2026cd6c268fSschwarze { 2027cd6c268fSschwarze 2028cd6c268fSschwarze for (n = n->child; n != NULL; n = n->next) 2029cd6c268fSschwarze if ((n->tok == MDOC_An && n->nchild) || child_an(n)) 2030cd6c268fSschwarze return(1); 2031cd6c268fSschwarze return(0); 2032cd6c268fSschwarze } 2033cd6c268fSschwarze 2034cd6c268fSschwarze static int 2035cd6c268fSschwarze post_sh_authors(POST_ARGS) 2036cd6c268fSschwarze { 2037cd6c268fSschwarze 2038cd6c268fSschwarze if ( ! child_an(mdoc->last)) 2039cd6c268fSschwarze mandoc_msg(MANDOCERR_AN_MISSING, mdoc->parse, 2040cd6c268fSschwarze mdoc->last->line, mdoc->last->pos, NULL); 2041cd6c268fSschwarze return(1); 2042cd6c268fSschwarze } 2043cd6c268fSschwarze 2044cd6c268fSschwarze static int 2045f73abda9Skristaps post_sh_head(POST_ARGS) 2046f73abda9Skristaps { 2047a2cff342Sschwarze struct mdoc_node *n; 204851fcab2fSschwarze const char *goodsec; 204946133849Sschwarze char *secname; 2050f73abda9Skristaps enum mdoc_sec sec; 2051f73abda9Skristaps 2052f73abda9Skristaps /* 2053f73abda9Skristaps * Process a new section. Sections are either "named" or 205420fa2881Sschwarze * "custom". Custom sections are user-defined, while named ones 205520fa2881Sschwarze * follow a conventional order and may only appear in certain 205620fa2881Sschwarze * manual sections. 2057f73abda9Skristaps */ 2058f73abda9Skristaps 205983af2bccSschwarze secname = NULL; 206004e980cbSschwarze sec = SEC_CUSTOM; 206146133849Sschwarze mdoc_deroff(&secname, mdoc->last); 206246133849Sschwarze sec = NULL == secname ? SEC_CUSTOM : a2sec(secname); 2063f73abda9Skristaps 206420fa2881Sschwarze /* The NAME should be first. */ 2065f73abda9Skristaps 2066fccfce9dSschwarze if (SEC_NAME != sec && SEC_NONE == mdoc->lastnamed) 2067bd594191Sschwarze mandoc_vmsg(MANDOCERR_NAMESEC_FIRST, mdoc->parse, 2068bd594191Sschwarze mdoc->last->line, mdoc->last->pos, 2069bd594191Sschwarze "Sh %s", secname); 207020fa2881Sschwarze 207120fa2881Sschwarze /* The SYNOPSIS gets special attention in other areas. */ 207220fa2881Sschwarze 207322881299Sschwarze if (SEC_SYNOPSIS == sec) { 207475088a49Sschwarze roff_setreg(mdoc->roff, "nS", 1, '='); 207520fa2881Sschwarze mdoc->flags |= MDOC_SYNOPSIS; 207622881299Sschwarze } else { 207775088a49Sschwarze roff_setreg(mdoc->roff, "nS", 0, '='); 207820fa2881Sschwarze mdoc->flags &= ~MDOC_SYNOPSIS; 207922881299Sschwarze } 208020fa2881Sschwarze 208120fa2881Sschwarze /* Mark our last section. */ 208220fa2881Sschwarze 208320fa2881Sschwarze mdoc->lastsec = sec; 20841eccdf28Sschwarze 20851eccdf28Sschwarze /* 20861eccdf28Sschwarze * Set the section attribute for the current HEAD, for its 20871eccdf28Sschwarze * parent BLOCK, and for the HEAD children; the latter can 20881eccdf28Sschwarze * only be TEXT nodes, so no recursion is needed. 20891eccdf28Sschwarze * For other blocks and elements, including .Sh BODY, this is 20901eccdf28Sschwarze * done when allocating the node data structures, but for .Sh 20911eccdf28Sschwarze * BLOCK and HEAD, the section is still unknown at that time. 20921eccdf28Sschwarze */ 20931eccdf28Sschwarze 2094a2cff342Sschwarze mdoc->last->parent->sec = sec; 2095a2cff342Sschwarze mdoc->last->sec = sec; 2096a2cff342Sschwarze for (n = mdoc->last->child; n; n = n->next) 2097a2cff342Sschwarze n->sec = sec; 209820fa2881Sschwarze 209920fa2881Sschwarze /* We don't care about custom sections after this. */ 2100fccfce9dSschwarze 210146133849Sschwarze if (SEC_CUSTOM == sec) { 210246133849Sschwarze free(secname); 2103f73abda9Skristaps return(1); 210446133849Sschwarze } 2105fccfce9dSschwarze 21066be99f77Sschwarze /* 210720fa2881Sschwarze * Check whether our non-custom section is being repeated or is 210820fa2881Sschwarze * out of order. 21096be99f77Sschwarze */ 2110f73abda9Skristaps 211120fa2881Sschwarze if (sec == mdoc->lastnamed) 2112bd594191Sschwarze mandoc_vmsg(MANDOCERR_SEC_REP, mdoc->parse, 2113bd594191Sschwarze mdoc->last->line, mdoc->last->pos, 2114bd594191Sschwarze "Sh %s", secname); 211520fa2881Sschwarze 211620fa2881Sschwarze if (sec < mdoc->lastnamed) 2117bd594191Sschwarze mandoc_vmsg(MANDOCERR_SEC_ORDER, mdoc->parse, 2118bd594191Sschwarze mdoc->last->line, mdoc->last->pos, 2119bd594191Sschwarze "Sh %s", secname); 212020fa2881Sschwarze 212120fa2881Sschwarze /* Mark the last named section. */ 212220fa2881Sschwarze 212320fa2881Sschwarze mdoc->lastnamed = sec; 212420fa2881Sschwarze 212520fa2881Sschwarze /* Check particular section/manual conventions. */ 212620fa2881Sschwarze 21273fdead0cSschwarze if (mdoc->meta.msec == NULL) { 21283fdead0cSschwarze free(secname); 21293fdead0cSschwarze return(1); 21303fdead0cSschwarze } 213120fa2881Sschwarze 213251fcab2fSschwarze goodsec = NULL; 213320fa2881Sschwarze switch (sec) { 213449aff9f8Sschwarze case SEC_ERRORS: 2135be89e780Sschwarze if (*mdoc->meta.msec == '4') 2136be89e780Sschwarze break; 213751fcab2fSschwarze goodsec = "2, 3, 4, 9"; 2138be89e780Sschwarze /* FALLTHROUGH */ 213949aff9f8Sschwarze case SEC_RETURN_VALUES: 214020fa2881Sschwarze /* FALLTHROUGH */ 214149aff9f8Sschwarze case SEC_LIBRARY: 214292c0ca7fSschwarze if (*mdoc->meta.msec == '2') 2143f73abda9Skristaps break; 214492c0ca7fSschwarze if (*mdoc->meta.msec == '3') 214592c0ca7fSschwarze break; 214651fcab2fSschwarze if (NULL == goodsec) 214751fcab2fSschwarze goodsec = "2, 3, 9"; 214803ab2f23Sdlg /* FALLTHROUGH */ 214949aff9f8Sschwarze case SEC_CONTEXT: 215092c0ca7fSschwarze if (*mdoc->meta.msec == '9') 215192c0ca7fSschwarze break; 215251fcab2fSschwarze if (NULL == goodsec) 215351fcab2fSschwarze goodsec = "9"; 215451fcab2fSschwarze mandoc_vmsg(MANDOCERR_SEC_MSEC, mdoc->parse, 215551fcab2fSschwarze mdoc->last->line, mdoc->last->pos, 2156bd594191Sschwarze "Sh %s for %s only", secname, goodsec); 215720fa2881Sschwarze break; 2158f73abda9Skristaps default: 2159f73abda9Skristaps break; 2160f73abda9Skristaps } 2161f73abda9Skristaps 216246133849Sschwarze free(secname); 2163f73abda9Skristaps return(1); 2164f73abda9Skristaps } 2165d39b9a9cSschwarze 216620fa2881Sschwarze static int 2167f6127a73Sschwarze post_ignpar(POST_ARGS) 2168f6127a73Sschwarze { 2169f6127a73Sschwarze struct mdoc_node *np; 2170f6127a73Sschwarze 2171753701eeSschwarze hwarn_ge1(mdoc); 2172753701eeSschwarze post_hyph(mdoc); 2173753701eeSschwarze 2174f6127a73Sschwarze if (MDOC_BODY != mdoc->last->type) 2175f6127a73Sschwarze return(1); 2176f6127a73Sschwarze 2177f6127a73Sschwarze if (NULL != (np = mdoc->last->child)) 2178f6127a73Sschwarze if (MDOC_Pp == np->tok || MDOC_Lp == np->tok) { 217920369664Sschwarze mandoc_vmsg(MANDOCERR_PAR_SKIP, 218020369664Sschwarze mdoc->parse, np->line, np->pos, 218120369664Sschwarze "%s after %s", mdoc_macronames[np->tok], 218220369664Sschwarze mdoc_macronames[mdoc->last->tok]); 2183f6127a73Sschwarze mdoc_node_delete(mdoc, np); 2184f6127a73Sschwarze } 2185f6127a73Sschwarze 2186f6127a73Sschwarze if (NULL != (np = mdoc->last->last)) 2187f6127a73Sschwarze if (MDOC_Pp == np->tok || MDOC_Lp == np->tok) { 218820369664Sschwarze mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse, 218920369664Sschwarze np->line, np->pos, "%s at the end of %s", 219020369664Sschwarze mdoc_macronames[np->tok], 219120369664Sschwarze mdoc_macronames[mdoc->last->tok]); 2192f6127a73Sschwarze mdoc_node_delete(mdoc, np); 2193f6127a73Sschwarze } 2194f6127a73Sschwarze 2195f6127a73Sschwarze return(1); 2196f6127a73Sschwarze } 2197f6127a73Sschwarze 2198f6127a73Sschwarze static int 219920fa2881Sschwarze pre_par(PRE_ARGS) 2200d39b9a9cSschwarze { 2201d39b9a9cSschwarze 2202d39b9a9cSschwarze if (NULL == mdoc->last) 2203d39b9a9cSschwarze return(1); 2204f6127a73Sschwarze if (MDOC_ELEM != n->type && MDOC_BLOCK != n->type) 2205f6127a73Sschwarze return(1); 2206d39b9a9cSschwarze 220720fa2881Sschwarze /* 220820fa2881Sschwarze * Don't allow prior `Lp' or `Pp' prior to a paragraph-type 220920fa2881Sschwarze * block: `Lp', `Pp', or non-compact `Bd' or `Bl'. 221020fa2881Sschwarze */ 2211d39b9a9cSschwarze 2212e0dd4c9cSschwarze if (MDOC_Pp != mdoc->last->tok && 2213e0dd4c9cSschwarze MDOC_Lp != mdoc->last->tok && 2214e0dd4c9cSschwarze MDOC_br != mdoc->last->tok) 2215d39b9a9cSschwarze return(1); 22168c62fbf5Sschwarze if (MDOC_Bl == n->tok && n->norm->Bl.comp) 2217d39b9a9cSschwarze return(1); 22188c62fbf5Sschwarze if (MDOC_Bd == n->tok && n->norm->Bd.comp) 2219d39b9a9cSschwarze return(1); 22208c62fbf5Sschwarze if (MDOC_It == n->tok && n->parent->norm->Bl.comp) 2221f6127a73Sschwarze return(1); 2222d39b9a9cSschwarze 222320369664Sschwarze mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse, 222420369664Sschwarze mdoc->last->line, mdoc->last->pos, 222520369664Sschwarze "%s before %s", mdoc_macronames[mdoc->last->tok], 222620369664Sschwarze mdoc_macronames[n->tok]); 2227d39b9a9cSschwarze mdoc_node_delete(mdoc, mdoc->last); 2228d39b9a9cSschwarze return(1); 2229d39b9a9cSschwarze } 223020fa2881Sschwarze 223120fa2881Sschwarze static int 2232e0dd4c9cSschwarze post_par(POST_ARGS) 2233e0dd4c9cSschwarze { 223420369664Sschwarze struct mdoc_node *np; 2235e0dd4c9cSschwarze 2236753701eeSschwarze if (mdoc->last->tok == MDOC_sp) 2237753701eeSschwarze ewarn_le1(mdoc); 2238753701eeSschwarze else 2239753701eeSschwarze ewarn_eq0(mdoc); 2240753701eeSschwarze 2241e0dd4c9cSschwarze if (MDOC_ELEM != mdoc->last->type && 2242e0dd4c9cSschwarze MDOC_BLOCK != mdoc->last->type) 2243e0dd4c9cSschwarze return(1); 2244e0dd4c9cSschwarze 224520369664Sschwarze if (NULL == (np = mdoc->last->prev)) { 224620369664Sschwarze np = mdoc->last->parent; 224720369664Sschwarze if (MDOC_Sh != np->tok && MDOC_Ss != np->tok) 2248e0dd4c9cSschwarze return(1); 2249e0dd4c9cSschwarze } else { 225020369664Sschwarze if (MDOC_Pp != np->tok && MDOC_Lp != np->tok && 2251e0dd4c9cSschwarze (MDOC_br != mdoc->last->tok || 225220369664Sschwarze (MDOC_sp != np->tok && MDOC_br != np->tok))) 2253e0dd4c9cSschwarze return(1); 2254e0dd4c9cSschwarze } 2255e0dd4c9cSschwarze 225620369664Sschwarze mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse, 225720369664Sschwarze mdoc->last->line, mdoc->last->pos, 225820369664Sschwarze "%s after %s", mdoc_macronames[mdoc->last->tok], 225920369664Sschwarze mdoc_macronames[np->tok]); 2260e0dd4c9cSschwarze mdoc_node_delete(mdoc, mdoc->last); 2261e0dd4c9cSschwarze return(1); 2262e0dd4c9cSschwarze } 2263e0dd4c9cSschwarze 2264e0dd4c9cSschwarze static int 226520fa2881Sschwarze pre_literal(PRE_ARGS) 226620fa2881Sschwarze { 226720fa2881Sschwarze 2268d52d1586Sschwarze pre_display(mdoc, n); 2269d52d1586Sschwarze 227020fa2881Sschwarze if (MDOC_BODY != n->type) 227120fa2881Sschwarze return(1); 227220fa2881Sschwarze 227320fa2881Sschwarze /* 227420fa2881Sschwarze * The `Dl' (note "el" not "one") and `Bd -literal' and `Bd 227520fa2881Sschwarze * -unfilled' macros set MDOC_LITERAL on entrance to the body. 227620fa2881Sschwarze */ 227720fa2881Sschwarze 227820fa2881Sschwarze switch (n->tok) { 227949aff9f8Sschwarze case MDOC_Dl: 228020fa2881Sschwarze mdoc->flags |= MDOC_LITERAL; 228120fa2881Sschwarze break; 228249aff9f8Sschwarze case MDOC_Bd: 22838c62fbf5Sschwarze if (DISP_literal == n->norm->Bd.type) 228420fa2881Sschwarze mdoc->flags |= MDOC_LITERAL; 22858c62fbf5Sschwarze if (DISP_unfilled == n->norm->Bd.type) 228620fa2881Sschwarze mdoc->flags |= MDOC_LITERAL; 228720fa2881Sschwarze break; 228820fa2881Sschwarze default: 228920fa2881Sschwarze abort(); 229020fa2881Sschwarze /* NOTREACHED */ 229120fa2881Sschwarze } 229220fa2881Sschwarze 229320fa2881Sschwarze return(1); 229420fa2881Sschwarze } 229520fa2881Sschwarze 229620fa2881Sschwarze static int 229720fa2881Sschwarze post_dd(POST_ARGS) 229820fa2881Sschwarze { 229920fa2881Sschwarze struct mdoc_node *n; 230083af2bccSschwarze char *datestr; 230120fa2881Sschwarze 2302b058e777Sschwarze if (mdoc->meta.date) 2303b058e777Sschwarze free(mdoc->meta.date); 230420fa2881Sschwarze 2305b058e777Sschwarze n = mdoc->last; 2306b058e777Sschwarze if (NULL == n->child || '\0' == n->child->string[0]) { 2307231c7061Sschwarze mdoc->meta.date = mdoc->quick ? mandoc_strdup("") : 2308231c7061Sschwarze mandoc_normdate(mdoc->parse, NULL, n->line, n->pos); 23093fdead0cSschwarze goto out; 231020fa2881Sschwarze } 231120fa2881Sschwarze 231283af2bccSschwarze datestr = NULL; 231383af2bccSschwarze mdoc_deroff(&datestr, n); 231483af2bccSschwarze if (mdoc->quick) 231583af2bccSschwarze mdoc->meta.date = datestr; 231683af2bccSschwarze else { 231783af2bccSschwarze mdoc->meta.date = mandoc_normdate(mdoc->parse, 231883af2bccSschwarze datestr, n->line, n->pos); 231983af2bccSschwarze free(datestr); 232004e980cbSschwarze } 23213fdead0cSschwarze out: 23223fdead0cSschwarze mdoc_node_delete(mdoc, n); 23233fdead0cSschwarze return(1); 232420fa2881Sschwarze } 232520fa2881Sschwarze 232620fa2881Sschwarze static int 232720fa2881Sschwarze post_dt(POST_ARGS) 232820fa2881Sschwarze { 232920fa2881Sschwarze struct mdoc_node *nn, *n; 233020fa2881Sschwarze const char *cp; 233120fa2881Sschwarze char *p; 233220fa2881Sschwarze 233320fa2881Sschwarze n = mdoc->last; 233420fa2881Sschwarze 233520fa2881Sschwarze free(mdoc->meta.title); 23363fdead0cSschwarze free(mdoc->meta.msec); 233720fa2881Sschwarze free(mdoc->meta.vol); 233820fa2881Sschwarze free(mdoc->meta.arch); 233920fa2881Sschwarze 23403fdead0cSschwarze mdoc->meta.title = NULL; 23413fdead0cSschwarze mdoc->meta.msec = NULL; 23423fdead0cSschwarze mdoc->meta.vol = NULL; 23433fdead0cSschwarze mdoc->meta.arch = NULL; 234420fa2881Sschwarze 234551fcab2fSschwarze /* First check that all characters are uppercase. */ 234620fa2881Sschwarze 234720fa2881Sschwarze if (NULL != (nn = n->child)) 234820fa2881Sschwarze for (p = nn->string; *p; p++) { 234904e980cbSschwarze if (toupper((unsigned char)*p) == *p) 235020fa2881Sschwarze continue; 2351bd594191Sschwarze mandoc_vmsg(MANDOCERR_TITLE_CASE, 235251fcab2fSschwarze mdoc->parse, nn->line, 235351fcab2fSschwarze nn->pos + (p - nn->string), 2354bd594191Sschwarze "Dt %s", nn->string); 235520fa2881Sschwarze break; 235620fa2881Sschwarze } 235720fa2881Sschwarze 23583fdead0cSschwarze /* No argument: msec and arch remain NULL. */ 235920fa2881Sschwarze 236020fa2881Sschwarze if (NULL == (nn = n->child)) { 23613fdead0cSschwarze mandoc_msg(MANDOCERR_DT_NOTITLE, 23623fdead0cSschwarze mdoc->parse, n->line, n->pos, "Dt"); 23633fdead0cSschwarze mdoc->meta.title = mandoc_strdup("UNTITLED"); 236420fa2881Sschwarze mdoc->meta.vol = mandoc_strdup("LOCAL"); 23653fdead0cSschwarze goto out; 236620fa2881Sschwarze } 236720fa2881Sschwarze 23683fdead0cSschwarze /* One argument: msec and arch remain NULL. */ 236920fa2881Sschwarze 237049aff9f8Sschwarze mdoc->meta.title = mandoc_strdup( 23713fdead0cSschwarze '\0' == nn->string[0] ? "UNTITLED" : nn->string); 237220fa2881Sschwarze 237320fa2881Sschwarze if (NULL == (nn = nn->next)) { 23743fdead0cSschwarze mandoc_vmsg(MANDOCERR_MSEC_MISSING, 23753fdead0cSschwarze mdoc->parse, n->line, n->pos, 23763fdead0cSschwarze "Dt %s", mdoc->meta.title); 237720fa2881Sschwarze mdoc->meta.vol = mandoc_strdup("LOCAL"); 23783fdead0cSschwarze goto out; 237920fa2881Sschwarze } 238020fa2881Sschwarze 238120fa2881Sschwarze /* Handles: `.Dt TITLE SEC' 238249aff9f8Sschwarze * title = TITLE, 238349aff9f8Sschwarze * volume = SEC is msec ? format(msec) : SEC, 238420fa2881Sschwarze * msec = SEC is msec ? atoi(msec) : 0, 238520fa2881Sschwarze * arch = NULL 238620fa2881Sschwarze */ 238720fa2881Sschwarze 238888ec69e3Sschwarze cp = mandoc_a2msec(nn->string); 238920fa2881Sschwarze if (cp) { 239020fa2881Sschwarze mdoc->meta.vol = mandoc_strdup(cp); 239120fa2881Sschwarze mdoc->meta.msec = mandoc_strdup(nn->string); 239220fa2881Sschwarze } else { 2393bd594191Sschwarze mandoc_vmsg(MANDOCERR_MSEC_BAD, mdoc->parse, 2394bd594191Sschwarze nn->line, nn->pos, "Dt ... %s", nn->string); 239520fa2881Sschwarze mdoc->meta.vol = mandoc_strdup(nn->string); 239620fa2881Sschwarze mdoc->meta.msec = mandoc_strdup(nn->string); 239720fa2881Sschwarze } 239820fa2881Sschwarze 239920fa2881Sschwarze if (NULL == (nn = nn->next)) 24003fdead0cSschwarze goto out; 240120fa2881Sschwarze 240220fa2881Sschwarze /* Handles: `.Dt TITLE SEC VOL' 240349aff9f8Sschwarze * title = TITLE, 240449aff9f8Sschwarze * volume = VOL is vol ? format(VOL) : 240520fa2881Sschwarze * VOL is arch ? format(arch) : 240620fa2881Sschwarze * VOL 240720fa2881Sschwarze */ 240820fa2881Sschwarze 240920fa2881Sschwarze cp = mdoc_a2vol(nn->string); 241020fa2881Sschwarze if (cp) { 241120fa2881Sschwarze free(mdoc->meta.vol); 241220fa2881Sschwarze mdoc->meta.vol = mandoc_strdup(cp); 241320fa2881Sschwarze } else { 241420fa2881Sschwarze cp = mdoc_a2arch(nn->string); 241520fa2881Sschwarze if (NULL == cp) { 2416bd594191Sschwarze mandoc_vmsg(MANDOCERR_ARCH_BAD, mdoc->parse, 2417bd594191Sschwarze nn->line, nn->pos, "Dt ... %s", nn->string); 241820fa2881Sschwarze free(mdoc->meta.vol); 241920fa2881Sschwarze mdoc->meta.vol = mandoc_strdup(nn->string); 242020fa2881Sschwarze } else 242120fa2881Sschwarze mdoc->meta.arch = mandoc_strdup(cp); 242220fa2881Sschwarze } 242320fa2881Sschwarze 242420fa2881Sschwarze /* Ignore any subsequent parameters... */ 242520fa2881Sschwarze /* FIXME: warn about subsequent parameters. */ 24263fdead0cSschwarze out: 24273fdead0cSschwarze mdoc_node_delete(mdoc, n); 242820fa2881Sschwarze return(1); 242920fa2881Sschwarze } 243020fa2881Sschwarze 243120fa2881Sschwarze static int 2432992063deSschwarze post_bx(POST_ARGS) 2433992063deSschwarze { 2434992063deSschwarze struct mdoc_node *n; 2435992063deSschwarze 2436992063deSschwarze /* 2437992063deSschwarze * Make `Bx's second argument always start with an uppercase 2438992063deSschwarze * letter. Groff checks if it's an "accepted" term, but we just 2439992063deSschwarze * uppercase blindly. 2440992063deSschwarze */ 2441992063deSschwarze 2442992063deSschwarze n = mdoc->last->child; 2443992063deSschwarze if (n && NULL != (n = n->next)) 244449aff9f8Sschwarze *n->string = (char)toupper((unsigned char)*n->string); 2445992063deSschwarze 2446992063deSschwarze return(1); 2447992063deSschwarze } 2448992063deSschwarze 2449992063deSschwarze static int 245020fa2881Sschwarze post_os(POST_ARGS) 245120fa2881Sschwarze { 245220fa2881Sschwarze #ifndef OSNAME 245320fa2881Sschwarze struct utsname utsname; 24544c468128Sschwarze static char *defbuf; 245520fa2881Sschwarze #endif 24564c468128Sschwarze struct mdoc_node *n; 245720fa2881Sschwarze 245820fa2881Sschwarze n = mdoc->last; 245920fa2881Sschwarze 246020fa2881Sschwarze /* 2461353fa9ecSschwarze * Set the operating system by way of the `Os' macro. 2462353fa9ecSschwarze * The order of precedence is: 2463353fa9ecSschwarze * 1. the argument of the `Os' macro, unless empty 2464353fa9ecSschwarze * 2. the -Ios=foo command line argument, if provided 2465353fa9ecSschwarze * 3. -DOSNAME="\"foo\"", if provided during compilation 2466353fa9ecSschwarze * 4. "sysname release" from uname(3) 246720fa2881Sschwarze */ 246820fa2881Sschwarze 246920fa2881Sschwarze free(mdoc->meta.os); 247083af2bccSschwarze mdoc->meta.os = NULL; 247183af2bccSschwarze mdoc_deroff(&mdoc->meta.os, n); 247283af2bccSschwarze if (mdoc->meta.os) 24733fdead0cSschwarze goto out; 24744c468128Sschwarze 2475353fa9ecSschwarze if (mdoc->defos) { 2476353fa9ecSschwarze mdoc->meta.os = mandoc_strdup(mdoc->defos); 24773fdead0cSschwarze goto out; 2478353fa9ecSschwarze } 24794c468128Sschwarze 248020fa2881Sschwarze #ifdef OSNAME 24814c468128Sschwarze mdoc->meta.os = mandoc_strdup(OSNAME); 248220fa2881Sschwarze #else /*!OSNAME */ 24834c468128Sschwarze if (NULL == defbuf) { 2484a35fc07aSschwarze if (-1 == uname(&utsname)) { 2485f79e7afeSschwarze mandoc_msg(MANDOCERR_OS_UNAME, mdoc->parse, 2486f79e7afeSschwarze n->line, n->pos, "Os"); 24874c468128Sschwarze defbuf = mandoc_strdup("UNKNOWN"); 2488a450f7c4Sschwarze } else 2489a450f7c4Sschwarze mandoc_asprintf(&defbuf, "%s %s", 2490a450f7c4Sschwarze utsname.sysname, utsname.release); 249120fa2881Sschwarze } 24924c468128Sschwarze mdoc->meta.os = mandoc_strdup(defbuf); 249320fa2881Sschwarze #endif /*!OSNAME*/ 24943fdead0cSschwarze 24953fdead0cSschwarze out: 24963fdead0cSschwarze mdoc_node_delete(mdoc, n); 24973fdead0cSschwarze return(1); 249820fa2881Sschwarze } 249920fa2881Sschwarze 2500e214f641Sschwarze /* 2501e214f641Sschwarze * If no argument is provided, 2502e214f641Sschwarze * fill in the name of the current manual page. 2503e214f641Sschwarze */ 250420fa2881Sschwarze static int 2505e214f641Sschwarze post_ex(POST_ARGS) 250620fa2881Sschwarze { 2507e214f641Sschwarze struct mdoc_node *n; 250820fa2881Sschwarze 250920fa2881Sschwarze n = mdoc->last; 251020fa2881Sschwarze 251120fa2881Sschwarze if (n->child) 251220fa2881Sschwarze return(1); 251320fa2881Sschwarze 2514e214f641Sschwarze if (mdoc->meta.name == NULL) { 2515bd594191Sschwarze mandoc_msg(MANDOCERR_EX_NONAME, mdoc->parse, 2516bd594191Sschwarze n->line, n->pos, "Ex"); 251720fa2881Sschwarze return(1); 2518e214f641Sschwarze } 251920fa2881Sschwarze 252020fa2881Sschwarze mdoc->next = MDOC_NEXT_CHILD; 252120fa2881Sschwarze 252220fa2881Sschwarze if ( ! mdoc_word_alloc(mdoc, n->line, n->pos, mdoc->meta.name)) 252320fa2881Sschwarze return(0); 252420fa2881Sschwarze 2525e214f641Sschwarze mdoc->last = n; 252620fa2881Sschwarze return(1); 252720fa2881Sschwarze } 252820fa2881Sschwarze 252919a69263Sschwarze static enum mdoc_sec 253019a69263Sschwarze a2sec(const char *p) 253119a69263Sschwarze { 253219a69263Sschwarze int i; 253319a69263Sschwarze 253419a69263Sschwarze for (i = 0; i < (int)SEC__MAX; i++) 253519a69263Sschwarze if (secnames[i] && 0 == strcmp(p, secnames[i])) 253619a69263Sschwarze return((enum mdoc_sec)i); 253719a69263Sschwarze 253819a69263Sschwarze return(SEC_CUSTOM); 253919a69263Sschwarze } 254019a69263Sschwarze 254119a69263Sschwarze static size_t 254219a69263Sschwarze macro2len(enum mdoct macro) 254319a69263Sschwarze { 254419a69263Sschwarze 254519a69263Sschwarze switch (macro) { 254649aff9f8Sschwarze case MDOC_Ad: 254719a69263Sschwarze return(12); 254849aff9f8Sschwarze case MDOC_Ao: 254919a69263Sschwarze return(12); 255049aff9f8Sschwarze case MDOC_An: 255119a69263Sschwarze return(12); 255249aff9f8Sschwarze case MDOC_Aq: 255319a69263Sschwarze return(12); 255449aff9f8Sschwarze case MDOC_Ar: 255519a69263Sschwarze return(12); 255649aff9f8Sschwarze case MDOC_Bo: 255719a69263Sschwarze return(12); 255849aff9f8Sschwarze case MDOC_Bq: 255919a69263Sschwarze return(12); 256049aff9f8Sschwarze case MDOC_Cd: 256119a69263Sschwarze return(12); 256249aff9f8Sschwarze case MDOC_Cm: 256319a69263Sschwarze return(10); 256449aff9f8Sschwarze case MDOC_Do: 256519a69263Sschwarze return(10); 256649aff9f8Sschwarze case MDOC_Dq: 256719a69263Sschwarze return(12); 256849aff9f8Sschwarze case MDOC_Dv: 256919a69263Sschwarze return(12); 257049aff9f8Sschwarze case MDOC_Eo: 257119a69263Sschwarze return(12); 257249aff9f8Sschwarze case MDOC_Em: 257319a69263Sschwarze return(10); 257449aff9f8Sschwarze case MDOC_Er: 257519a69263Sschwarze return(17); 257649aff9f8Sschwarze case MDOC_Ev: 257719a69263Sschwarze return(15); 257849aff9f8Sschwarze case MDOC_Fa: 257919a69263Sschwarze return(12); 258049aff9f8Sschwarze case MDOC_Fl: 258119a69263Sschwarze return(10); 258249aff9f8Sschwarze case MDOC_Fo: 258319a69263Sschwarze return(16); 258449aff9f8Sschwarze case MDOC_Fn: 258519a69263Sschwarze return(16); 258649aff9f8Sschwarze case MDOC_Ic: 258719a69263Sschwarze return(10); 258849aff9f8Sschwarze case MDOC_Li: 258919a69263Sschwarze return(16); 259049aff9f8Sschwarze case MDOC_Ms: 259119a69263Sschwarze return(6); 259249aff9f8Sschwarze case MDOC_Nm: 259319a69263Sschwarze return(10); 259449aff9f8Sschwarze case MDOC_No: 259519a69263Sschwarze return(12); 259649aff9f8Sschwarze case MDOC_Oo: 259719a69263Sschwarze return(10); 259849aff9f8Sschwarze case MDOC_Op: 259919a69263Sschwarze return(14); 260049aff9f8Sschwarze case MDOC_Pa: 260119a69263Sschwarze return(32); 260249aff9f8Sschwarze case MDOC_Pf: 260319a69263Sschwarze return(12); 260449aff9f8Sschwarze case MDOC_Po: 260519a69263Sschwarze return(12); 260649aff9f8Sschwarze case MDOC_Pq: 260719a69263Sschwarze return(12); 260849aff9f8Sschwarze case MDOC_Ql: 260919a69263Sschwarze return(16); 261049aff9f8Sschwarze case MDOC_Qo: 261119a69263Sschwarze return(12); 261249aff9f8Sschwarze case MDOC_So: 261319a69263Sschwarze return(12); 261449aff9f8Sschwarze case MDOC_Sq: 261519a69263Sschwarze return(12); 261649aff9f8Sschwarze case MDOC_Sy: 261719a69263Sschwarze return(6); 261849aff9f8Sschwarze case MDOC_Sx: 261919a69263Sschwarze return(16); 262049aff9f8Sschwarze case MDOC_Tn: 262119a69263Sschwarze return(10); 262249aff9f8Sschwarze case MDOC_Va: 262319a69263Sschwarze return(12); 262449aff9f8Sschwarze case MDOC_Vt: 262519a69263Sschwarze return(12); 262649aff9f8Sschwarze case MDOC_Xr: 262719a69263Sschwarze return(10); 262819a69263Sschwarze default: 262919a69263Sschwarze break; 263019a69263Sschwarze }; 263119a69263Sschwarze return(0); 263219a69263Sschwarze } 2633