1*2a427d60Sschwarze /* $Id: mdoc_validate.c,v 1.113 2013/10/06 13:27:47 schwarze Exp $ */ 2f73abda9Skristaps /* 322972b14Sschwarze * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv> 422881299Sschwarze * Copyright (c) 2010, 2011, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org> 5f73abda9Skristaps * 6f73abda9Skristaps * Permission to use, copy, modify, and distribute this software for any 7a6464425Sschwarze * purpose with or without fee is hereby granted, provided that the above 8a6464425Sschwarze * copyright notice and this permission notice appear in all copies. 9f73abda9Skristaps * 10a6464425Sschwarze * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11a6464425Sschwarze * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12a6464425Sschwarze * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13a6464425Sschwarze * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14a6464425Sschwarze * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15a6464425Sschwarze * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16a6464425Sschwarze * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17f73abda9Skristaps */ 1820fa2881Sschwarze #ifndef OSNAME 1920fa2881Sschwarze #include <sys/utsname.h> 2020fa2881Sschwarze #endif 2120fa2881Sschwarze 22f73abda9Skristaps #include <sys/types.h> 23f73abda9Skristaps 24f73abda9Skristaps #include <assert.h> 25f73abda9Skristaps #include <ctype.h> 26d92dc4efSschwarze #include <limits.h> 273216dddfSschwarze #include <stdio.h> 28f73abda9Skristaps #include <stdlib.h> 29f73abda9Skristaps #include <string.h> 3020fa2881Sschwarze #include <time.h> 31f73abda9Skristaps 32a35fc07aSschwarze #include "mdoc.h" 336e03d529Sschwarze #include "mandoc.h" 34f73abda9Skristaps #include "libmdoc.h" 35f6854d5cSschwarze #include "libmandoc.h" 36f73abda9Skristaps 37f73abda9Skristaps /* FIXME: .Bl -diag can't have non-text children in HEAD. */ 38f73abda9Skristaps 396093755cSschwarze #define PRE_ARGS struct mdoc *mdoc, struct mdoc_node *n 40f73abda9Skristaps #define POST_ARGS struct mdoc *mdoc 41f73abda9Skristaps 4220fa2881Sschwarze #define NUMSIZ 32 4320fa2881Sschwarze #define DATESIZE 32 4420fa2881Sschwarze 457c2be9f8Sschwarze enum check_ineq { 467c2be9f8Sschwarze CHECK_LT, 477c2be9f8Sschwarze CHECK_GT, 487c2be9f8Sschwarze CHECK_EQ 497c2be9f8Sschwarze }; 507c2be9f8Sschwarze 517c2be9f8Sschwarze enum check_lvl { 527c2be9f8Sschwarze CHECK_WARN, 537c2be9f8Sschwarze CHECK_ERROR, 547c2be9f8Sschwarze }; 557c2be9f8Sschwarze 56f73abda9Skristaps typedef int (*v_pre)(PRE_ARGS); 57f73abda9Skristaps typedef int (*v_post)(POST_ARGS); 58f73abda9Skristaps 59f73abda9Skristaps struct valids { 60f73abda9Skristaps v_pre *pre; 61f73abda9Skristaps v_post *post; 62f73abda9Skristaps }; 63f73abda9Skristaps 647c2be9f8Sschwarze static int check_count(struct mdoc *, enum mdoc_type, 657c2be9f8Sschwarze enum check_lvl, enum check_ineq, int); 66dd94fa3aSschwarze static int check_parent(PRE_ARGS, enum mdoct, enum mdoc_type); 6720fa2881Sschwarze static void check_text(struct mdoc *, int, int, char *); 6820fa2881Sschwarze static void check_argv(struct mdoc *, 6931e23753Sschwarze struct mdoc_node *, struct mdoc_argv *); 7020fa2881Sschwarze static void check_args(struct mdoc *, struct mdoc_node *); 7104e980cbSschwarze static int concat(char *, const struct mdoc_node *, size_t); 7219a69263Sschwarze static enum mdoc_sec a2sec(const char *); 7319a69263Sschwarze static size_t macro2len(enum mdoct); 7467c719adSschwarze 757c2be9f8Sschwarze static int ebool(POST_ARGS); 7667c719adSschwarze static int berr_ge1(POST_ARGS); 7767c719adSschwarze static int bwarn_ge1(POST_ARGS); 78da272f5eSschwarze static int ewarn_eq0(POST_ARGS); 79bb648afaSschwarze static int ewarn_eq1(POST_ARGS); 8067c719adSschwarze static int ewarn_ge1(POST_ARGS); 81bb648afaSschwarze static int ewarn_le1(POST_ARGS); 82b16e7ddfSschwarze static int hwarn_eq0(POST_ARGS); 837c2be9f8Sschwarze static int hwarn_eq1(POST_ARGS); 84bb648afaSschwarze static int hwarn_ge1(POST_ARGS); 8567c719adSschwarze static int hwarn_le1(POST_ARGS); 8667c719adSschwarze 8767c719adSschwarze static int post_an(POST_ARGS); 8867c719adSschwarze static int post_at(POST_ARGS); 8967c719adSschwarze static int post_bf(POST_ARGS); 9067c719adSschwarze static int post_bl(POST_ARGS); 9120fa2881Sschwarze static int post_bl_block(POST_ARGS); 9220fa2881Sschwarze static int post_bl_block_width(POST_ARGS); 9320fa2881Sschwarze static int post_bl_block_tag(POST_ARGS); 9467c719adSschwarze static int post_bl_head(POST_ARGS); 95992063deSschwarze static int post_bx(POST_ARGS); 9620fa2881Sschwarze static int post_dd(POST_ARGS); 976093755cSschwarze static int post_dt(POST_ARGS); 9820fa2881Sschwarze static int post_defaults(POST_ARGS); 9920fa2881Sschwarze static int post_literal(POST_ARGS); 10020fa2881Sschwarze static int post_eoln(POST_ARGS); 10167c719adSschwarze static int post_it(POST_ARGS); 10267c719adSschwarze static int post_lb(POST_ARGS); 10367c719adSschwarze static int post_nm(POST_ARGS); 104af216717Sschwarze static int post_ns(POST_ARGS); 10520fa2881Sschwarze static int post_os(POST_ARGS); 106e0dd4c9cSschwarze static int post_par(POST_ARGS); 107f6127a73Sschwarze static int post_ignpar(POST_ARGS); 10820fa2881Sschwarze static int post_prol(POST_ARGS); 10967c719adSschwarze static int post_root(POST_ARGS); 110011fe33bSschwarze static int post_rs(POST_ARGS); 11167c719adSschwarze static int post_sh(POST_ARGS); 11267c719adSschwarze static int post_sh_body(POST_ARGS); 11367c719adSschwarze static int post_sh_head(POST_ARGS); 11467c719adSschwarze static int post_st(POST_ARGS); 11520fa2881Sschwarze static int post_std(POST_ARGS); 1168521b0bcSschwarze static int post_vt(POST_ARGS); 117f73abda9Skristaps static int pre_an(PRE_ARGS); 118f73abda9Skristaps static int pre_bd(PRE_ARGS); 119f73abda9Skristaps static int pre_bl(PRE_ARGS); 120f73abda9Skristaps static int pre_dd(PRE_ARGS); 121f73abda9Skristaps static int pre_display(PRE_ARGS); 122f73abda9Skristaps static int pre_dt(PRE_ARGS); 123f73abda9Skristaps static int pre_it(PRE_ARGS); 12420fa2881Sschwarze static int pre_literal(PRE_ARGS); 125f73abda9Skristaps static int pre_os(PRE_ARGS); 12620fa2881Sschwarze static int pre_par(PRE_ARGS); 127f73abda9Skristaps static int pre_sh(PRE_ARGS); 128f73abda9Skristaps static int pre_ss(PRE_ARGS); 12920fa2881Sschwarze static int pre_std(PRE_ARGS); 130f73abda9Skristaps 13167c719adSschwarze static v_post posts_an[] = { post_an, NULL }; 13220fa2881Sschwarze static v_post posts_at[] = { post_at, post_defaults, NULL }; 13320fa2881Sschwarze static v_post posts_bd[] = { post_literal, hwarn_eq0, bwarn_ge1, NULL }; 13467c719adSschwarze static v_post posts_bf[] = { hwarn_le1, post_bf, NULL }; 13520fa2881Sschwarze static v_post posts_bk[] = { hwarn_eq0, bwarn_ge1, NULL }; 13667c719adSschwarze static v_post posts_bl[] = { bwarn_ge1, post_bl, NULL }; 137992063deSschwarze static v_post posts_bx[] = { post_bx, NULL }; 138bb648afaSschwarze static v_post posts_bool[] = { ebool, NULL }; 139b31af00dSschwarze static v_post posts_eoln[] = { post_eoln, NULL }; 14020fa2881Sschwarze static v_post posts_defaults[] = { post_defaults, NULL }; 141b058e777Sschwarze static v_post posts_dd[] = { post_dd, post_prol, NULL }; 142bb648afaSschwarze static v_post posts_dl[] = { post_literal, bwarn_ge1, NULL }; 14320fa2881Sschwarze static v_post posts_dt[] = { post_dt, post_prol, NULL }; 14467c719adSschwarze static v_post posts_fo[] = { hwarn_eq1, bwarn_ge1, NULL }; 14567c719adSschwarze static v_post posts_it[] = { post_it, NULL }; 146bb648afaSschwarze static v_post posts_lb[] = { post_lb, NULL }; 14767c719adSschwarze static v_post posts_nd[] = { berr_ge1, NULL }; 14867c719adSschwarze static v_post posts_nm[] = { post_nm, NULL }; 149da272f5eSschwarze static v_post posts_notext[] = { ewarn_eq0, NULL }; 150af216717Sschwarze static v_post posts_ns[] = { post_ns, NULL }; 15120fa2881Sschwarze static v_post posts_os[] = { post_os, post_prol, NULL }; 152e0dd4c9cSschwarze static v_post posts_pp[] = { post_par, ewarn_eq0, NULL }; 153bb648afaSschwarze static v_post posts_rs[] = { post_rs, NULL }; 154a35fc07aSschwarze static v_post posts_sh[] = { post_ignpar, hwarn_ge1, post_sh, NULL }; 155e0dd4c9cSschwarze static v_post posts_sp[] = { post_par, ewarn_le1, NULL }; 156a35fc07aSschwarze static v_post posts_ss[] = { post_ignpar, hwarn_ge1, NULL }; 157bb648afaSschwarze static v_post posts_st[] = { post_st, NULL }; 15820fa2881Sschwarze static v_post posts_std[] = { post_std, NULL }; 159e7a93ef3Sschwarze static v_post posts_text[] = { ewarn_ge1, NULL }; 160bb648afaSschwarze static v_post posts_text1[] = { ewarn_eq1, NULL }; 1618521b0bcSschwarze static v_post posts_vt[] = { post_vt, NULL }; 162bb648afaSschwarze static v_post posts_wline[] = { bwarn_ge1, NULL }; 163f73abda9Skristaps static v_pre pres_an[] = { pre_an, NULL }; 16420fa2881Sschwarze static v_pre pres_bd[] = { pre_display, pre_bd, pre_literal, pre_par, NULL }; 16520fa2881Sschwarze static v_pre pres_bl[] = { pre_bl, pre_par, NULL }; 166f73abda9Skristaps static v_pre pres_d1[] = { pre_display, NULL }; 16720fa2881Sschwarze static v_pre pres_dl[] = { pre_literal, pre_display, NULL }; 16867c719adSschwarze static v_pre pres_dd[] = { pre_dd, NULL }; 1696be99f77Sschwarze static v_pre pres_dt[] = { pre_dt, NULL }; 170b16e7ddfSschwarze static v_pre pres_er[] = { NULL, NULL }; 171974b5ecdSschwarze static v_pre pres_fd[] = { NULL, NULL }; 172f6127a73Sschwarze static v_pre pres_it[] = { pre_it, pre_par, NULL }; 1736be99f77Sschwarze static v_pre pres_os[] = { pre_os, NULL }; 17420fa2881Sschwarze static v_pre pres_pp[] = { pre_par, NULL }; 175f73abda9Skristaps static v_pre pres_sh[] = { pre_sh, NULL }; 176f73abda9Skristaps static v_pre pres_ss[] = { pre_ss, NULL }; 17720fa2881Sschwarze static v_pre pres_std[] = { pre_std, NULL }; 178f73abda9Skristaps 17919a69263Sschwarze static const struct valids mdoc_valids[MDOC_MAX] = { 180099cfa7eSschwarze { NULL, NULL }, /* Ap */ 18120fa2881Sschwarze { pres_dd, posts_dd }, /* Dd */ 1826093755cSschwarze { pres_dt, posts_dt }, /* Dt */ 18320fa2881Sschwarze { pres_os, posts_os }, /* Os */ 184f73abda9Skristaps { pres_sh, posts_sh }, /* Sh */ 185f73abda9Skristaps { pres_ss, posts_ss }, /* Ss */ 186e0dd4c9cSschwarze { pres_pp, posts_pp }, /* Pp */ 187f73abda9Skristaps { pres_d1, posts_wline }, /* D1 */ 18820fa2881Sschwarze { pres_dl, posts_dl }, /* Dl */ 18920fa2881Sschwarze { pres_bd, posts_bd }, /* Bd */ 190f73abda9Skristaps { NULL, NULL }, /* Ed */ 191f73abda9Skristaps { pres_bl, posts_bl }, /* Bl */ 192f73abda9Skristaps { NULL, NULL }, /* El */ 193f73abda9Skristaps { pres_it, posts_it }, /* It */ 194e7a93ef3Sschwarze { NULL, NULL }, /* Ad */ 195f73abda9Skristaps { pres_an, posts_an }, /* An */ 19620fa2881Sschwarze { NULL, posts_defaults }, /* Ar */ 197e7a93ef3Sschwarze { NULL, NULL }, /* Cd */ 198f73abda9Skristaps { NULL, NULL }, /* Cm */ 199f73abda9Skristaps { NULL, NULL }, /* Dv */ 200e7a93ef3Sschwarze { pres_er, NULL }, /* Er */ 201f73abda9Skristaps { NULL, NULL }, /* Ev */ 20220fa2881Sschwarze { pres_std, posts_std }, /* Ex */ 203f73abda9Skristaps { NULL, NULL }, /* Fa */ 204e7a93ef3Sschwarze { pres_fd, posts_text }, /* Fd */ 205f73abda9Skristaps { NULL, NULL }, /* Fl */ 206e7a93ef3Sschwarze { NULL, NULL }, /* Fn */ 207e7a93ef3Sschwarze { NULL, NULL }, /* Ft */ 208e7a93ef3Sschwarze { NULL, NULL }, /* Ic */ 209b822ca0dSschwarze { NULL, posts_text1 }, /* In */ 21020fa2881Sschwarze { NULL, posts_defaults }, /* Li */ 2114602e85cSschwarze { NULL, posts_nd }, /* Nd */ 212f73abda9Skristaps { NULL, posts_nm }, /* Nm */ 213bca76d61Sschwarze { NULL, NULL }, /* Op */ 214f73abda9Skristaps { NULL, NULL }, /* Ot */ 21520fa2881Sschwarze { NULL, posts_defaults }, /* Pa */ 21620fa2881Sschwarze { pres_std, posts_std }, /* Rv */ 217f73abda9Skristaps { NULL, posts_st }, /* St */ 218f73abda9Skristaps { NULL, NULL }, /* Va */ 2198521b0bcSschwarze { NULL, posts_vt }, /* Vt */ 220e7a93ef3Sschwarze { NULL, posts_text }, /* Xr */ 221f73abda9Skristaps { NULL, posts_text }, /* %A */ 2224175bdabSschwarze { NULL, posts_text }, /* %B */ /* FIXME: can be used outside Rs/Re. */ 223b058e777Sschwarze { NULL, posts_text }, /* %D */ 224f73abda9Skristaps { NULL, posts_text }, /* %I */ 225f73abda9Skristaps { NULL, posts_text }, /* %J */ 226f73abda9Skristaps { NULL, posts_text }, /* %N */ 227f73abda9Skristaps { NULL, posts_text }, /* %O */ 228f73abda9Skristaps { NULL, posts_text }, /* %P */ 229f73abda9Skristaps { NULL, posts_text }, /* %R */ 2304175bdabSschwarze { NULL, posts_text }, /* %T */ /* FIXME: can be used outside Rs/Re. */ 231f73abda9Skristaps { NULL, posts_text }, /* %V */ 232f73abda9Skristaps { NULL, NULL }, /* Ac */ 233f73abda9Skristaps { NULL, NULL }, /* Ao */ 234bca76d61Sschwarze { NULL, NULL }, /* Aq */ 235f73abda9Skristaps { NULL, posts_at }, /* At */ 236f73abda9Skristaps { NULL, NULL }, /* Bc */ 237f73abda9Skristaps { NULL, posts_bf }, /* Bf */ 238f73abda9Skristaps { NULL, NULL }, /* Bo */ 239bca76d61Sschwarze { NULL, NULL }, /* Bq */ 240f73abda9Skristaps { NULL, NULL }, /* Bsx */ 241992063deSschwarze { NULL, posts_bx }, /* Bx */ 242f73abda9Skristaps { NULL, posts_bool }, /* Db */ 243f73abda9Skristaps { NULL, NULL }, /* Dc */ 244f73abda9Skristaps { NULL, NULL }, /* Do */ 245bca76d61Sschwarze { NULL, NULL }, /* Dq */ 246f73abda9Skristaps { NULL, NULL }, /* Ec */ 247f73abda9Skristaps { NULL, NULL }, /* Ef */ 248f73abda9Skristaps { NULL, NULL }, /* Em */ 249f73abda9Skristaps { NULL, NULL }, /* Eo */ 250f73abda9Skristaps { NULL, NULL }, /* Fx */ 251e7a93ef3Sschwarze { NULL, NULL }, /* Ms */ 252f73abda9Skristaps { NULL, posts_notext }, /* No */ 253af216717Sschwarze { NULL, posts_ns }, /* Ns */ 254f73abda9Skristaps { NULL, NULL }, /* Nx */ 255f73abda9Skristaps { NULL, NULL }, /* Ox */ 256f73abda9Skristaps { NULL, NULL }, /* Pc */ 257b822ca0dSschwarze { NULL, posts_text1 }, /* Pf */ 258f73abda9Skristaps { NULL, NULL }, /* Po */ 259bca76d61Sschwarze { NULL, NULL }, /* Pq */ 260f73abda9Skristaps { NULL, NULL }, /* Qc */ 261bca76d61Sschwarze { NULL, NULL }, /* Ql */ 262f73abda9Skristaps { NULL, NULL }, /* Qo */ 263bca76d61Sschwarze { NULL, NULL }, /* Qq */ 264f73abda9Skristaps { NULL, NULL }, /* Re */ 2658c62fbf5Sschwarze { NULL, posts_rs }, /* Rs */ 266f73abda9Skristaps { NULL, NULL }, /* Sc */ 267f73abda9Skristaps { NULL, NULL }, /* So */ 268bca76d61Sschwarze { NULL, NULL }, /* Sq */ 269f73abda9Skristaps { NULL, posts_bool }, /* Sm */ 270e7a93ef3Sschwarze { NULL, NULL }, /* Sx */ 271e7a93ef3Sschwarze { NULL, NULL }, /* Sy */ 272e7a93ef3Sschwarze { NULL, NULL }, /* Tn */ 273f73abda9Skristaps { NULL, NULL }, /* Ux */ 274f73abda9Skristaps { NULL, NULL }, /* Xc */ 275f73abda9Skristaps { NULL, NULL }, /* Xo */ 276f73abda9Skristaps { NULL, posts_fo }, /* Fo */ 277f73abda9Skristaps { NULL, NULL }, /* Fc */ 278f73abda9Skristaps { NULL, NULL }, /* Oo */ 279f73abda9Skristaps { NULL, NULL }, /* Oc */ 28020fa2881Sschwarze { NULL, posts_bk }, /* Bk */ 281f73abda9Skristaps { NULL, NULL }, /* Ek */ 282b31af00dSschwarze { NULL, posts_eoln }, /* Bt */ 283f73abda9Skristaps { NULL, NULL }, /* Hf */ 284f73abda9Skristaps { NULL, NULL }, /* Fr */ 285b31af00dSschwarze { NULL, posts_eoln }, /* Ud */ 286b31af00dSschwarze { NULL, posts_lb }, /* Lb */ 287e0dd4c9cSschwarze { pres_pp, posts_pp }, /* Lp */ 288e7a93ef3Sschwarze { NULL, NULL }, /* Lk */ 28920fa2881Sschwarze { NULL, posts_defaults }, /* Mt */ 290bca76d61Sschwarze { NULL, NULL }, /* Brq */ 291f73abda9Skristaps { NULL, NULL }, /* Bro */ 292f73abda9Skristaps { NULL, NULL }, /* Brc */ 293f73abda9Skristaps { NULL, posts_text }, /* %C */ 294f73abda9Skristaps { NULL, NULL }, /* Es */ 295f73abda9Skristaps { NULL, NULL }, /* En */ 296f73abda9Skristaps { NULL, NULL }, /* Dx */ 297f73abda9Skristaps { NULL, posts_text }, /* %Q */ 298e0dd4c9cSschwarze { NULL, posts_pp }, /* br */ 299e0dd4c9cSschwarze { NULL, posts_sp }, /* sp */ 300b822ca0dSschwarze { NULL, posts_text1 }, /* %U */ 3016093755cSschwarze { NULL, NULL }, /* Ta */ 302f73abda9Skristaps }; 303f73abda9Skristaps 30420fa2881Sschwarze #define RSORD_MAX 14 /* Number of `Rs' blocks. */ 30520fa2881Sschwarze 30620fa2881Sschwarze static const enum mdoct rsord[RSORD_MAX] = { 30720fa2881Sschwarze MDOC__A, 30820fa2881Sschwarze MDOC__T, 30920fa2881Sschwarze MDOC__B, 31020fa2881Sschwarze MDOC__I, 31120fa2881Sschwarze MDOC__J, 31220fa2881Sschwarze MDOC__R, 31320fa2881Sschwarze MDOC__N, 31420fa2881Sschwarze MDOC__V, 3150397c682Sschwarze MDOC__U, 31620fa2881Sschwarze MDOC__P, 31720fa2881Sschwarze MDOC__Q, 3184e32ec8fSschwarze MDOC__C, 31920fa2881Sschwarze MDOC__D, 3204e32ec8fSschwarze MDOC__O 32120fa2881Sschwarze }; 32220fa2881Sschwarze 32319a69263Sschwarze static const char * const secnames[SEC__MAX] = { 32419a69263Sschwarze NULL, 32519a69263Sschwarze "NAME", 32619a69263Sschwarze "LIBRARY", 32719a69263Sschwarze "SYNOPSIS", 32819a69263Sschwarze "DESCRIPTION", 32919a69263Sschwarze "IMPLEMENTATION NOTES", 33019a69263Sschwarze "RETURN VALUES", 33119a69263Sschwarze "ENVIRONMENT", 33219a69263Sschwarze "FILES", 33319a69263Sschwarze "EXIT STATUS", 33419a69263Sschwarze "EXAMPLES", 33519a69263Sschwarze "DIAGNOSTICS", 33619a69263Sschwarze "COMPATIBILITY", 33719a69263Sschwarze "ERRORS", 33819a69263Sschwarze "SEE ALSO", 33919a69263Sschwarze "STANDARDS", 34019a69263Sschwarze "HISTORY", 34119a69263Sschwarze "AUTHORS", 34219a69263Sschwarze "CAVEATS", 34319a69263Sschwarze "BUGS", 34419a69263Sschwarze "SECURITY CONSIDERATIONS", 34519a69263Sschwarze NULL 34619a69263Sschwarze }; 347f73abda9Skristaps 348f73abda9Skristaps int 3496093755cSschwarze mdoc_valid_pre(struct mdoc *mdoc, struct mdoc_node *n) 350f73abda9Skristaps { 351f73abda9Skristaps v_pre *p; 352f73abda9Skristaps int line, pos; 35331e23753Sschwarze char *tp; 354f73abda9Skristaps 3552791bd1cSschwarze switch (n->type) { 3562791bd1cSschwarze case (MDOC_TEXT): 357f73abda9Skristaps tp = n->string; 358f73abda9Skristaps line = n->line; 359f73abda9Skristaps pos = n->pos; 36020fa2881Sschwarze check_text(mdoc, line, pos, tp); 3612791bd1cSschwarze /* FALLTHROUGH */ 3622791bd1cSschwarze case (MDOC_TBL): 3632791bd1cSschwarze /* FALLTHROUGH */ 3648d973ab1Sschwarze case (MDOC_EQN): 3658d973ab1Sschwarze /* FALLTHROUGH */ 3662791bd1cSschwarze case (MDOC_ROOT): 36720fa2881Sschwarze return(1); 3682791bd1cSschwarze default: 3692791bd1cSschwarze break; 370f73abda9Skristaps } 371f73abda9Skristaps 37220fa2881Sschwarze check_args(mdoc, n); 37320fa2881Sschwarze 374f73abda9Skristaps if (NULL == mdoc_valids[n->tok].pre) 375f73abda9Skristaps return(1); 376f73abda9Skristaps for (p = mdoc_valids[n->tok].pre; *p; p++) 377f73abda9Skristaps if ( ! (*p)(mdoc, n)) 378f73abda9Skristaps return(0); 379f73abda9Skristaps return(1); 380f73abda9Skristaps } 381f73abda9Skristaps 382f73abda9Skristaps 383f73abda9Skristaps int 384f73abda9Skristaps mdoc_valid_post(struct mdoc *mdoc) 385f73abda9Skristaps { 386f73abda9Skristaps v_post *p; 387f73abda9Skristaps 388f73abda9Skristaps if (MDOC_VALID & mdoc->last->flags) 389f73abda9Skristaps return(1); 390f73abda9Skristaps mdoc->last->flags |= MDOC_VALID; 391f73abda9Skristaps 3922791bd1cSschwarze switch (mdoc->last->type) { 3932791bd1cSschwarze case (MDOC_TEXT): 3942791bd1cSschwarze /* FALLTHROUGH */ 3958d973ab1Sschwarze case (MDOC_EQN): 3968d973ab1Sschwarze /* FALLTHROUGH */ 3972791bd1cSschwarze case (MDOC_TBL): 398f73abda9Skristaps return(1); 3992791bd1cSschwarze case (MDOC_ROOT): 400f73abda9Skristaps return(post_root(mdoc)); 4012791bd1cSschwarze default: 4022791bd1cSschwarze break; 4032791bd1cSschwarze } 404f73abda9Skristaps 405f73abda9Skristaps if (NULL == mdoc_valids[mdoc->last->tok].post) 406f73abda9Skristaps return(1); 407f73abda9Skristaps for (p = mdoc_valids[mdoc->last->tok].post; *p; p++) 408f73abda9Skristaps if ( ! (*p)(mdoc)) 409f73abda9Skristaps return(0); 410f73abda9Skristaps 411f73abda9Skristaps return(1); 412f73abda9Skristaps } 413f73abda9Skristaps 4147c2be9f8Sschwarze static int 4157ead8a4eSschwarze check_count(struct mdoc *mdoc, enum mdoc_type type, 4167c2be9f8Sschwarze enum check_lvl lvl, enum check_ineq ineq, int val) 417f73abda9Skristaps { 4187c2be9f8Sschwarze const char *p; 419bb648afaSschwarze enum mandocerr t; 4207c2be9f8Sschwarze 4217ead8a4eSschwarze if (mdoc->last->type != type) 4227c2be9f8Sschwarze return(1); 4237c2be9f8Sschwarze 4247c2be9f8Sschwarze switch (ineq) { 4257c2be9f8Sschwarze case (CHECK_LT): 4267c2be9f8Sschwarze p = "less than "; 4277ead8a4eSschwarze if (mdoc->last->nchild < val) 4287c2be9f8Sschwarze return(1); 4297c2be9f8Sschwarze break; 4307c2be9f8Sschwarze case (CHECK_GT): 431bb648afaSschwarze p = "more than "; 4327ead8a4eSschwarze if (mdoc->last->nchild > val) 4337c2be9f8Sschwarze return(1); 4347c2be9f8Sschwarze break; 4357c2be9f8Sschwarze case (CHECK_EQ): 4367c2be9f8Sschwarze p = ""; 4377ead8a4eSschwarze if (val == mdoc->last->nchild) 4387c2be9f8Sschwarze return(1); 4397c2be9f8Sschwarze break; 44020fa2881Sschwarze default: 44120fa2881Sschwarze abort(); 44220fa2881Sschwarze /* NOTREACHED */ 4437c2be9f8Sschwarze } 4447c2be9f8Sschwarze 445bb648afaSschwarze t = lvl == CHECK_WARN ? MANDOCERR_ARGCWARN : MANDOCERR_ARGCOUNT; 4467ead8a4eSschwarze mandoc_vmsg(t, mdoc->parse, mdoc->last->line, mdoc->last->pos, 4477c2be9f8Sschwarze "want %s%d children (have %d)", 4487ead8a4eSschwarze p, val, mdoc->last->nchild); 44919a69263Sschwarze return(1); 4507c2be9f8Sschwarze } 451f73abda9Skristaps 4527c2be9f8Sschwarze static int 4537c2be9f8Sschwarze berr_ge1(POST_ARGS) 454f73abda9Skristaps { 455f73abda9Skristaps 456bb648afaSschwarze return(check_count(mdoc, MDOC_BODY, CHECK_ERROR, CHECK_GT, 0)); 457f73abda9Skristaps } 458f73abda9Skristaps 4597c2be9f8Sschwarze static int 4607c2be9f8Sschwarze bwarn_ge1(POST_ARGS) 4617c2be9f8Sschwarze { 4627c2be9f8Sschwarze return(check_count(mdoc, MDOC_BODY, CHECK_WARN, CHECK_GT, 0)); 463f73abda9Skristaps } 464f73abda9Skristaps 4657c2be9f8Sschwarze static int 4667c2be9f8Sschwarze ewarn_eq0(POST_ARGS) 4677c2be9f8Sschwarze { 4687c2be9f8Sschwarze return(check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 0)); 4697c2be9f8Sschwarze } 4707c2be9f8Sschwarze 4717c2be9f8Sschwarze static int 472bb648afaSschwarze ewarn_eq1(POST_ARGS) 473bb648afaSschwarze { 474bb648afaSschwarze return(check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 1)); 475bb648afaSschwarze } 476bb648afaSschwarze 477bb648afaSschwarze static int 4787c2be9f8Sschwarze ewarn_ge1(POST_ARGS) 4797c2be9f8Sschwarze { 4807c2be9f8Sschwarze return(check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_GT, 0)); 4817c2be9f8Sschwarze } 4827c2be9f8Sschwarze 4837c2be9f8Sschwarze static int 484bb648afaSschwarze ewarn_le1(POST_ARGS) 4857c2be9f8Sschwarze { 486bb648afaSschwarze return(check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_LT, 2)); 4877c2be9f8Sschwarze } 4887c2be9f8Sschwarze 4897c2be9f8Sschwarze static int 4907c2be9f8Sschwarze hwarn_eq0(POST_ARGS) 4917c2be9f8Sschwarze { 4927c2be9f8Sschwarze return(check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_EQ, 0)); 4937c2be9f8Sschwarze } 4947c2be9f8Sschwarze 4957c2be9f8Sschwarze static int 4967c2be9f8Sschwarze hwarn_eq1(POST_ARGS) 4977c2be9f8Sschwarze { 4987c2be9f8Sschwarze return(check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_EQ, 1)); 4997c2be9f8Sschwarze } 5007c2be9f8Sschwarze 5017c2be9f8Sschwarze static int 502bb648afaSschwarze hwarn_ge1(POST_ARGS) 503bb648afaSschwarze { 504bb648afaSschwarze return(check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_GT, 0)); 505bb648afaSschwarze } 506bb648afaSschwarze 507bb648afaSschwarze static int 5087c2be9f8Sschwarze hwarn_le1(POST_ARGS) 5097c2be9f8Sschwarze { 5107c2be9f8Sschwarze return(check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_LT, 2)); 5117c2be9f8Sschwarze } 512f73abda9Skristaps 51320fa2881Sschwarze static void 5147ead8a4eSschwarze check_args(struct mdoc *mdoc, struct mdoc_node *n) 515f73abda9Skristaps { 516f73abda9Skristaps int i; 517f73abda9Skristaps 518f73abda9Skristaps if (NULL == n->args) 51920fa2881Sschwarze return; 520f73abda9Skristaps 521f73abda9Skristaps assert(n->args->argc); 522f73abda9Skristaps for (i = 0; i < (int)n->args->argc; i++) 5237ead8a4eSschwarze check_argv(mdoc, n, &n->args->argv[i]); 524f73abda9Skristaps } 525f73abda9Skristaps 52620fa2881Sschwarze static void 5277ead8a4eSschwarze check_argv(struct mdoc *mdoc, struct mdoc_node *n, struct mdoc_argv *v) 528f73abda9Skristaps { 529f73abda9Skristaps int i; 530f73abda9Skristaps 531f73abda9Skristaps for (i = 0; i < (int)v->sz; i++) 5327ead8a4eSschwarze check_text(mdoc, v->line, v->pos, v->value[i]); 533f73abda9Skristaps 53420fa2881Sschwarze /* FIXME: move to post_std(). */ 53520fa2881Sschwarze 53620fa2881Sschwarze if (MDOC_Std == v->arg) 5377ead8a4eSschwarze if ( ! (v->sz || mdoc->meta.name)) 5387ead8a4eSschwarze mdoc_nmsg(mdoc, n, MANDOCERR_NONAME); 539f73abda9Skristaps } 540f73abda9Skristaps 54120fa2881Sschwarze static void 5427ead8a4eSschwarze check_text(struct mdoc *mdoc, int ln, int pos, char *p) 543f73abda9Skristaps { 54404e980cbSschwarze char *cp; 545769ee804Sschwarze 5467ead8a4eSschwarze if (MDOC_LITERAL & mdoc->flags) 5471cdbf331Sschwarze return; 5481cdbf331Sschwarze 5491cdbf331Sschwarze for (cp = p; NULL != (p = strchr(p, '\t')); p++) 5507ead8a4eSschwarze mdoc_pmsg(mdoc, ln, pos + (int)(p - cp), MANDOCERR_BADTAB); 551f73abda9Skristaps } 552f73abda9Skristaps 553f73abda9Skristaps static int 554dd94fa3aSschwarze check_parent(PRE_ARGS, enum mdoct tok, enum mdoc_type t) 555f73abda9Skristaps { 556f73abda9Skristaps 557f73abda9Skristaps assert(n->parent); 558f73abda9Skristaps if ((MDOC_ROOT == t || tok == n->parent->tok) && 559f73abda9Skristaps (t == n->parent->type)) 560f73abda9Skristaps return(1); 561f73abda9Skristaps 562a35fc07aSschwarze mandoc_vmsg(MANDOCERR_SYNTCHILD, mdoc->parse, n->line, 563a35fc07aSschwarze n->pos, "want parent %s", MDOC_ROOT == t ? 564a35fc07aSschwarze "<root>" : mdoc_macronames[tok]); 5656e03d529Sschwarze return(0); 566f73abda9Skristaps } 567f73abda9Skristaps 568f73abda9Skristaps 569f73abda9Skristaps static int 570f73abda9Skristaps pre_display(PRE_ARGS) 571f73abda9Skristaps { 572f73abda9Skristaps struct mdoc_node *node; 573f73abda9Skristaps 574f73abda9Skristaps if (MDOC_BLOCK != n->type) 575f73abda9Skristaps return(1); 576f73abda9Skristaps 577f73abda9Skristaps for (node = mdoc->last->parent; node; node = node->parent) 578f73abda9Skristaps if (MDOC_BLOCK == node->type) 579f73abda9Skristaps if (MDOC_Bd == node->tok) 580f73abda9Skristaps break; 58120fa2881Sschwarze 58205c39368Sschwarze if (node) 5836e03d529Sschwarze mdoc_nmsg(mdoc, n, MANDOCERR_NESTEDDISP); 58405c39368Sschwarze 58505c39368Sschwarze return(1); 586f73abda9Skristaps } 587f73abda9Skristaps 588f73abda9Skristaps 589f73abda9Skristaps static int 590f73abda9Skristaps pre_bl(PRE_ARGS) 591f73abda9Skristaps { 59231e23753Sschwarze int i, comp, dup; 59331e23753Sschwarze const char *offs, *width; 5946093755cSschwarze enum mdoc_list lt; 595769ee804Sschwarze struct mdoc_node *np; 596f73abda9Skristaps 5976093755cSschwarze if (MDOC_BLOCK != n->type) { 598769ee804Sschwarze if (ENDBODY_NOT != n->end) { 599769ee804Sschwarze assert(n->pending); 600769ee804Sschwarze np = n->pending->parent; 601769ee804Sschwarze } else 602769ee804Sschwarze np = n->parent; 603769ee804Sschwarze 604769ee804Sschwarze assert(np); 605769ee804Sschwarze assert(MDOC_BLOCK == np->type); 606769ee804Sschwarze assert(MDOC_Bl == np->tok); 607f73abda9Skristaps return(1); 6086e03d529Sschwarze } 609f73abda9Skristaps 6106093755cSschwarze /* 6116093755cSschwarze * First figure out which kind of list to use: bind ourselves to 6126093755cSschwarze * the first mentioned list type and warn about any remaining 6136093755cSschwarze * ones. If we find no list type, we default to LIST_item. 6146093755cSschwarze */ 615f73abda9Skristaps 616f73abda9Skristaps /* LINTED */ 6176093755cSschwarze for (i = 0; n->args && i < (int)n->args->argc; i++) { 6186093755cSschwarze lt = LIST__NONE; 61931e23753Sschwarze dup = comp = 0; 62031e23753Sschwarze width = offs = NULL; 6216093755cSschwarze switch (n->args->argv[i].arg) { 6226093755cSschwarze /* Set list types. */ 623f73abda9Skristaps case (MDOC_Bullet): 6246093755cSschwarze lt = LIST_bullet; 6256093755cSschwarze break; 626f73abda9Skristaps case (MDOC_Dash): 6276093755cSschwarze lt = LIST_dash; 6286093755cSschwarze break; 629f73abda9Skristaps case (MDOC_Enum): 6306093755cSschwarze lt = LIST_enum; 6316093755cSschwarze break; 632f73abda9Skristaps case (MDOC_Hyphen): 6336093755cSschwarze lt = LIST_hyphen; 6346093755cSschwarze break; 635f73abda9Skristaps case (MDOC_Item): 6366093755cSschwarze lt = LIST_item; 6376093755cSschwarze break; 638f73abda9Skristaps case (MDOC_Tag): 6396093755cSschwarze lt = LIST_tag; 6406093755cSschwarze break; 641f73abda9Skristaps case (MDOC_Diag): 6426093755cSschwarze lt = LIST_diag; 6436093755cSschwarze break; 644f73abda9Skristaps case (MDOC_Hang): 6456093755cSschwarze lt = LIST_hang; 6466093755cSschwarze break; 647f73abda9Skristaps case (MDOC_Ohang): 6486093755cSschwarze lt = LIST_ohang; 6496093755cSschwarze break; 650f73abda9Skristaps case (MDOC_Inset): 6516093755cSschwarze lt = LIST_inset; 6526093755cSschwarze break; 653f73abda9Skristaps case (MDOC_Column): 6546093755cSschwarze lt = LIST_column; 65564d728e4Sschwarze break; 6566093755cSschwarze /* Set list arguments. */ 65750e63e03Sschwarze case (MDOC_Compact): 6588c62fbf5Sschwarze dup = n->norm->Bl.comp; 65931e23753Sschwarze comp = 1; 66050e63e03Sschwarze break; 661f73abda9Skristaps case (MDOC_Width): 66222972b14Sschwarze /* NB: this can be empty! */ 66322972b14Sschwarze if (n->args->argv[i].sz) { 66431e23753Sschwarze width = n->args->argv[i].value[0]; 66522972b14Sschwarze dup = (NULL != n->norm->Bl.width); 66622972b14Sschwarze break; 66722972b14Sschwarze } 66822972b14Sschwarze mdoc_nmsg(mdoc, n, MANDOCERR_IGNARGV); 66964d728e4Sschwarze break; 670f73abda9Skristaps case (MDOC_Offset): 67131e23753Sschwarze /* NB: this can be empty! */ 67231e23753Sschwarze if (n->args->argv[i].sz) { 67331e23753Sschwarze offs = n->args->argv[i].value[0]; 6748c62fbf5Sschwarze dup = (NULL != n->norm->Bl.offs); 67531e23753Sschwarze break; 67631e23753Sschwarze } 67720fa2881Sschwarze mdoc_nmsg(mdoc, n, MANDOCERR_IGNARGV); 678f73abda9Skristaps break; 679ddce0b0cSschwarze default: 680ddce0b0cSschwarze continue; 681f73abda9Skristaps } 682f73abda9Skristaps 6836093755cSschwarze /* Check: duplicate auxiliary arguments. */ 6846093755cSschwarze 68520fa2881Sschwarze if (dup) 68620fa2881Sschwarze mdoc_nmsg(mdoc, n, MANDOCERR_ARGVREP); 6876093755cSschwarze 68831e23753Sschwarze if (comp && ! dup) 6898c62fbf5Sschwarze n->norm->Bl.comp = comp; 69031e23753Sschwarze if (offs && ! dup) 6918c62fbf5Sschwarze n->norm->Bl.offs = offs; 69231e23753Sschwarze if (width && ! dup) 6938c62fbf5Sschwarze n->norm->Bl.width = width; 69431e23753Sschwarze 6956093755cSschwarze /* Check: multiple list types. */ 6966093755cSschwarze 6978c62fbf5Sschwarze if (LIST__NONE != lt && n->norm->Bl.type != LIST__NONE) 69820fa2881Sschwarze mdoc_nmsg(mdoc, n, MANDOCERR_LISTREP); 6996093755cSschwarze 7006093755cSschwarze /* Assign list type. */ 7016093755cSschwarze 7028c62fbf5Sschwarze if (LIST__NONE != lt && n->norm->Bl.type == LIST__NONE) { 7038c62fbf5Sschwarze n->norm->Bl.type = lt; 704769ee804Sschwarze /* Set column information, too. */ 705769ee804Sschwarze if (LIST_column == lt) { 7068c62fbf5Sschwarze n->norm->Bl.ncols = 707769ee804Sschwarze n->args->argv[i].sz; 70804e980cbSschwarze n->norm->Bl.cols = (void *) 709769ee804Sschwarze n->args->argv[i].value; 710769ee804Sschwarze } 711769ee804Sschwarze } 7126093755cSschwarze 7136093755cSschwarze /* The list type should come first. */ 7146093755cSschwarze 7158c62fbf5Sschwarze if (n->norm->Bl.type == LIST__NONE) 7168c62fbf5Sschwarze if (n->norm->Bl.width || 7178c62fbf5Sschwarze n->norm->Bl.offs || 7188c62fbf5Sschwarze n->norm->Bl.comp) 71920fa2881Sschwarze mdoc_nmsg(mdoc, n, MANDOCERR_LISTFIRST); 7206093755cSschwarze 7216093755cSschwarze continue; 7226093755cSschwarze } 7236093755cSschwarze 7246093755cSschwarze /* Allow lists to default to LIST_item. */ 7256093755cSschwarze 7268c62fbf5Sschwarze if (LIST__NONE == n->norm->Bl.type) { 72720fa2881Sschwarze mdoc_nmsg(mdoc, n, MANDOCERR_LISTTYPE); 7288c62fbf5Sschwarze n->norm->Bl.type = LIST_item; 7296e03d529Sschwarze } 730f73abda9Skristaps 73164d728e4Sschwarze /* 73264d728e4Sschwarze * Validate the width field. Some list types don't need width 73364d728e4Sschwarze * types and should be warned about them. Others should have it 7345eced068Sschwarze * and must also be warned. Yet others have a default and need 7355eced068Sschwarze * no warning. 73664d728e4Sschwarze */ 73764d728e4Sschwarze 7388c62fbf5Sschwarze switch (n->norm->Bl.type) { 7396093755cSschwarze case (LIST_tag): 7405eced068Sschwarze if (NULL == n->norm->Bl.width) 74120fa2881Sschwarze mdoc_nmsg(mdoc, n, MANDOCERR_NOWIDTHARG); 742f73abda9Skristaps break; 7436093755cSschwarze case (LIST_column): 7446093755cSschwarze /* FALLTHROUGH */ 7456093755cSschwarze case (LIST_diag): 7466093755cSschwarze /* FALLTHROUGH */ 7476093755cSschwarze case (LIST_ohang): 7486093755cSschwarze /* FALLTHROUGH */ 7496093755cSschwarze case (LIST_inset): 7506093755cSschwarze /* FALLTHROUGH */ 7516093755cSschwarze case (LIST_item): 7528c62fbf5Sschwarze if (n->norm->Bl.width) 753817ac90bSschwarze mdoc_nmsg(mdoc, n, MANDOCERR_IGNARGV); 7546093755cSschwarze break; 7555eced068Sschwarze case (LIST_bullet): 7565eced068Sschwarze /* FALLTHROUGH */ 7575eced068Sschwarze case (LIST_dash): 7585eced068Sschwarze /* FALLTHROUGH */ 7595eced068Sschwarze case (LIST_hyphen): 7605eced068Sschwarze if (NULL == n->norm->Bl.width) 7615eced068Sschwarze n->norm->Bl.width = "2n"; 7625eced068Sschwarze break; 7635eced068Sschwarze case (LIST_enum): 7645eced068Sschwarze if (NULL == n->norm->Bl.width) 7655eced068Sschwarze n->norm->Bl.width = "3n"; 7665eced068Sschwarze break; 76764d728e4Sschwarze default: 768f73abda9Skristaps break; 76964d728e4Sschwarze } 77064d728e4Sschwarze 771f73abda9Skristaps return(1); 772f73abda9Skristaps } 773f73abda9Skristaps 774f73abda9Skristaps 775f73abda9Skristaps static int 776f73abda9Skristaps pre_bd(PRE_ARGS) 777f73abda9Skristaps { 77831e23753Sschwarze int i, dup, comp; 77931e23753Sschwarze enum mdoc_disp dt; 78031e23753Sschwarze const char *offs; 781769ee804Sschwarze struct mdoc_node *np; 782f73abda9Skristaps 78331e23753Sschwarze if (MDOC_BLOCK != n->type) { 784769ee804Sschwarze if (ENDBODY_NOT != n->end) { 785769ee804Sschwarze assert(n->pending); 786769ee804Sschwarze np = n->pending->parent; 787769ee804Sschwarze } else 788769ee804Sschwarze np = n->parent; 789769ee804Sschwarze 790769ee804Sschwarze assert(np); 791769ee804Sschwarze assert(MDOC_BLOCK == np->type); 792769ee804Sschwarze assert(MDOC_Bd == np->tok); 793f73abda9Skristaps return(1); 7946e03d529Sschwarze } 795f73abda9Skristaps 796f73abda9Skristaps /* LINTED */ 79731e23753Sschwarze for (i = 0; n->args && i < (int)n->args->argc; i++) { 79831e23753Sschwarze dt = DISP__NONE; 79931e23753Sschwarze dup = comp = 0; 80031e23753Sschwarze offs = NULL; 80131e23753Sschwarze 802f73abda9Skristaps switch (n->args->argv[i].arg) { 803b822ca0dSschwarze case (MDOC_Centred): 80431e23753Sschwarze dt = DISP_centred; 80531e23753Sschwarze break; 806f73abda9Skristaps case (MDOC_Ragged): 80731e23753Sschwarze dt = DISP_ragged; 80831e23753Sschwarze break; 809f73abda9Skristaps case (MDOC_Unfilled): 81031e23753Sschwarze dt = DISP_unfilled; 81131e23753Sschwarze break; 812f73abda9Skristaps case (MDOC_Filled): 81331e23753Sschwarze dt = DISP_filled; 81431e23753Sschwarze break; 815f73abda9Skristaps case (MDOC_Literal): 81631e23753Sschwarze dt = DISP_literal; 817f73abda9Skristaps break; 81831e23753Sschwarze case (MDOC_File): 81931e23753Sschwarze mdoc_nmsg(mdoc, n, MANDOCERR_BADDISP); 8206e03d529Sschwarze return(0); 82131e23753Sschwarze case (MDOC_Offset): 82231e23753Sschwarze /* NB: this can be empty! */ 82331e23753Sschwarze if (n->args->argv[i].sz) { 82431e23753Sschwarze offs = n->args->argv[i].value[0]; 8258c62fbf5Sschwarze dup = (NULL != n->norm->Bd.offs); 826f73abda9Skristaps break; 827f73abda9Skristaps } 82820fa2881Sschwarze mdoc_nmsg(mdoc, n, MANDOCERR_IGNARGV); 82931e23753Sschwarze break; 83031e23753Sschwarze case (MDOC_Compact): 83131e23753Sschwarze comp = 1; 8328c62fbf5Sschwarze dup = n->norm->Bd.comp; 83331e23753Sschwarze break; 83431e23753Sschwarze default: 83531e23753Sschwarze abort(); 83631e23753Sschwarze /* NOTREACHED */ 83731e23753Sschwarze } 83831e23753Sschwarze 83931e23753Sschwarze /* Check whether we have duplicates. */ 84031e23753Sschwarze 84120fa2881Sschwarze if (dup) 84220fa2881Sschwarze mdoc_nmsg(mdoc, n, MANDOCERR_ARGVREP); 84331e23753Sschwarze 84431e23753Sschwarze /* Make our auxiliary assignments. */ 84531e23753Sschwarze 84631e23753Sschwarze if (offs && ! dup) 8478c62fbf5Sschwarze n->norm->Bd.offs = offs; 84831e23753Sschwarze if (comp && ! dup) 8498c62fbf5Sschwarze n->norm->Bd.comp = comp; 85031e23753Sschwarze 85131e23753Sschwarze /* Check whether a type has already been assigned. */ 85231e23753Sschwarze 8538c62fbf5Sschwarze if (DISP__NONE != dt && n->norm->Bd.type != DISP__NONE) 85420fa2881Sschwarze mdoc_nmsg(mdoc, n, MANDOCERR_DISPREP); 85531e23753Sschwarze 85631e23753Sschwarze /* Make our type assignment. */ 85731e23753Sschwarze 8588c62fbf5Sschwarze if (DISP__NONE != dt && n->norm->Bd.type == DISP__NONE) 8598c62fbf5Sschwarze n->norm->Bd.type = dt; 86031e23753Sschwarze } 86131e23753Sschwarze 8628c62fbf5Sschwarze if (DISP__NONE == n->norm->Bd.type) { 86320fa2881Sschwarze mdoc_nmsg(mdoc, n, MANDOCERR_DISPTYPE); 8648c62fbf5Sschwarze n->norm->Bd.type = DISP_ragged; 86531e23753Sschwarze } 86631e23753Sschwarze 86731e23753Sschwarze return(1); 868f73abda9Skristaps } 869f73abda9Skristaps 870f73abda9Skristaps 871f73abda9Skristaps static int 872f73abda9Skristaps pre_ss(PRE_ARGS) 873f73abda9Skristaps { 874f73abda9Skristaps 875f73abda9Skristaps if (MDOC_BLOCK != n->type) 876f73abda9Skristaps return(1); 877f73abda9Skristaps return(check_parent(mdoc, n, MDOC_Sh, MDOC_BODY)); 878f73abda9Skristaps } 879f73abda9Skristaps 880f73abda9Skristaps 881f73abda9Skristaps static int 882f73abda9Skristaps pre_sh(PRE_ARGS) 883f73abda9Skristaps { 884f73abda9Skristaps 885f73abda9Skristaps if (MDOC_BLOCK != n->type) 886f73abda9Skristaps return(1); 887a4c002ecSschwarze return(check_parent(mdoc, n, MDOC_MAX, MDOC_ROOT)); 888f73abda9Skristaps } 889f73abda9Skristaps 890f73abda9Skristaps 891f73abda9Skristaps static int 892f73abda9Skristaps pre_it(PRE_ARGS) 893f73abda9Skristaps { 894f73abda9Skristaps 895f73abda9Skristaps if (MDOC_BLOCK != n->type) 896f73abda9Skristaps return(1); 89720fa2881Sschwarze 898f73abda9Skristaps return(check_parent(mdoc, n, MDOC_Bl, MDOC_BODY)); 899f73abda9Skristaps } 900f73abda9Skristaps 901f73abda9Skristaps 902f73abda9Skristaps static int 903f73abda9Skristaps pre_an(PRE_ARGS) 904f73abda9Skristaps { 9056475d5b0Sschwarze int i; 906f73abda9Skristaps 907769ee804Sschwarze if (NULL == n->args) 908f73abda9Skristaps return(1); 909769ee804Sschwarze 9106475d5b0Sschwarze for (i = 1; i < (int)n->args->argc; i++) 91120fa2881Sschwarze mdoc_pmsg(mdoc, n->args->argv[i].line, 91220fa2881Sschwarze n->args->argv[i].pos, MANDOCERR_IGNARGV); 9137c2be9f8Sschwarze 914769ee804Sschwarze if (MDOC_Split == n->args->argv[0].arg) 9158c62fbf5Sschwarze n->norm->An.auth = AUTH_split; 916769ee804Sschwarze else if (MDOC_Nosplit == n->args->argv[0].arg) 9178c62fbf5Sschwarze n->norm->An.auth = AUTH_nosplit; 918769ee804Sschwarze else 919769ee804Sschwarze abort(); 920769ee804Sschwarze 921769ee804Sschwarze return(1); 922f73abda9Skristaps } 923f73abda9Skristaps 924f73abda9Skristaps static int 92520fa2881Sschwarze pre_std(PRE_ARGS) 926f73abda9Skristaps { 927f73abda9Skristaps 92820fa2881Sschwarze if (n->args && 1 == n->args->argc) 92920fa2881Sschwarze if (MDOC_Std == n->args->argv[0].arg) 93020fa2881Sschwarze return(1); 931f73abda9Skristaps 93220fa2881Sschwarze mdoc_nmsg(mdoc, n, MANDOCERR_NOARGV); 9336093755cSschwarze return(1); 9346093755cSschwarze } 9356093755cSschwarze 9366093755cSschwarze static int 937f73abda9Skristaps pre_dt(PRE_ARGS) 938f73abda9Skristaps { 939f73abda9Skristaps 940b058e777Sschwarze if (NULL == mdoc->meta.date || mdoc->meta.os) 94120fa2881Sschwarze mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGOOO); 94220fa2881Sschwarze 943f73abda9Skristaps if (mdoc->meta.title) 94420fa2881Sschwarze mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGREP); 94520fa2881Sschwarze 946f73abda9Skristaps return(1); 947f73abda9Skristaps } 948f73abda9Skristaps 949f73abda9Skristaps static int 950f73abda9Skristaps pre_os(PRE_ARGS) 951f73abda9Skristaps { 952f73abda9Skristaps 953b058e777Sschwarze if (NULL == mdoc->meta.title || NULL == mdoc->meta.date) 95420fa2881Sschwarze mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGOOO); 95520fa2881Sschwarze 956f73abda9Skristaps if (mdoc->meta.os) 95720fa2881Sschwarze mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGREP); 95820fa2881Sschwarze 959f73abda9Skristaps return(1); 960f73abda9Skristaps } 961f73abda9Skristaps 962f73abda9Skristaps static int 963f73abda9Skristaps pre_dd(PRE_ARGS) 964f73abda9Skristaps { 965f73abda9Skristaps 966f73abda9Skristaps if (mdoc->meta.title || mdoc->meta.os) 96720fa2881Sschwarze mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGOOO); 96820fa2881Sschwarze 969f73abda9Skristaps if (mdoc->meta.date) 97020fa2881Sschwarze mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGREP); 97120fa2881Sschwarze 972f73abda9Skristaps return(1); 973f73abda9Skristaps } 974f73abda9Skristaps 975f73abda9Skristaps 976f73abda9Skristaps static int 977f73abda9Skristaps post_bf(POST_ARGS) 978f73abda9Skristaps { 979769ee804Sschwarze struct mdoc_node *np; 980ddce0b0cSschwarze enum mdocargt arg; 981f73abda9Skristaps 982769ee804Sschwarze /* 983769ee804Sschwarze * Unlike other data pointers, these are "housed" by the HEAD 984769ee804Sschwarze * element, which contains the goods. 985769ee804Sschwarze */ 986769ee804Sschwarze 987769ee804Sschwarze if (MDOC_HEAD != mdoc->last->type) { 988769ee804Sschwarze if (ENDBODY_NOT != mdoc->last->end) { 989769ee804Sschwarze assert(mdoc->last->pending); 990769ee804Sschwarze np = mdoc->last->pending->parent->head; 991769ee804Sschwarze } else if (MDOC_BLOCK != mdoc->last->type) { 992769ee804Sschwarze np = mdoc->last->parent->head; 993769ee804Sschwarze } else 994769ee804Sschwarze np = mdoc->last->head; 995769ee804Sschwarze 996769ee804Sschwarze assert(np); 997769ee804Sschwarze assert(MDOC_HEAD == np->type); 998769ee804Sschwarze assert(MDOC_Bf == np->tok); 999f73abda9Skristaps return(1); 10006e03d529Sschwarze } 1001f73abda9Skristaps 1002769ee804Sschwarze np = mdoc->last; 1003769ee804Sschwarze assert(MDOC_BLOCK == np->parent->type); 1004769ee804Sschwarze assert(MDOC_Bf == np->parent->tok); 100550d41253Sschwarze 1006769ee804Sschwarze /* 1007769ee804Sschwarze * Cannot have both argument and parameter. 1008769ee804Sschwarze * If neither is specified, let it through with a warning. 1009769ee804Sschwarze */ 1010f73abda9Skristaps 1011769ee804Sschwarze if (np->parent->args && np->child) { 1012769ee804Sschwarze mdoc_nmsg(mdoc, np, MANDOCERR_SYNTARGVCOUNT); 10136e03d529Sschwarze return(0); 101420fa2881Sschwarze } else if (NULL == np->parent->args && NULL == np->child) { 101520fa2881Sschwarze mdoc_nmsg(mdoc, np, MANDOCERR_FONTTYPE); 101620fa2881Sschwarze return(1); 101720fa2881Sschwarze } 1018769ee804Sschwarze 1019769ee804Sschwarze /* Extract argument into data. */ 1020769ee804Sschwarze 1021769ee804Sschwarze if (np->parent->args) { 1022769ee804Sschwarze arg = np->parent->args->argv[0].arg; 1023769ee804Sschwarze if (MDOC_Emphasis == arg) 10248c62fbf5Sschwarze np->norm->Bf.font = FONT_Em; 1025769ee804Sschwarze else if (MDOC_Literal == arg) 10268c62fbf5Sschwarze np->norm->Bf.font = FONT_Li; 1027769ee804Sschwarze else if (MDOC_Symbolic == arg) 10288c62fbf5Sschwarze np->norm->Bf.font = FONT_Sy; 1029769ee804Sschwarze else 1030769ee804Sschwarze abort(); 1031769ee804Sschwarze return(1); 1032769ee804Sschwarze } 1033769ee804Sschwarze 1034769ee804Sschwarze /* Extract parameter into data. */ 1035769ee804Sschwarze 1036769ee804Sschwarze if (0 == strcmp(np->child->string, "Em")) 10378c62fbf5Sschwarze np->norm->Bf.font = FONT_Em; 1038769ee804Sschwarze else if (0 == strcmp(np->child->string, "Li")) 10398c62fbf5Sschwarze np->norm->Bf.font = FONT_Li; 1040769ee804Sschwarze else if (0 == strcmp(np->child->string, "Sy")) 10418c62fbf5Sschwarze np->norm->Bf.font = FONT_Sy; 104220fa2881Sschwarze else 104320fa2881Sschwarze mdoc_nmsg(mdoc, np, MANDOCERR_FONTTYPE); 1044769ee804Sschwarze 1045769ee804Sschwarze return(1); 1046f73abda9Skristaps } 1047f73abda9Skristaps 1048f73abda9Skristaps static int 104971719887Sschwarze post_lb(POST_ARGS) 105071719887Sschwarze { 105120fa2881Sschwarze const char *p; 105220fa2881Sschwarze char *buf; 105320fa2881Sschwarze size_t sz; 105471719887Sschwarze 1055bb648afaSschwarze check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 1); 1056bb648afaSschwarze 105720fa2881Sschwarze assert(mdoc->last->child); 105820fa2881Sschwarze assert(MDOC_TEXT == mdoc->last->child->type); 105920fa2881Sschwarze 106020fa2881Sschwarze p = mdoc_a2lib(mdoc->last->child->string); 106120fa2881Sschwarze 106220fa2881Sschwarze /* If lookup ok, replace with table value. */ 106320fa2881Sschwarze 106420fa2881Sschwarze if (p) { 106520fa2881Sschwarze free(mdoc->last->child->string); 106620fa2881Sschwarze mdoc->last->child->string = mandoc_strdup(p); 106771719887Sschwarze return(1); 106871719887Sschwarze } 106971719887Sschwarze 107020fa2881Sschwarze /* If not, use "library ``xxxx''. */ 107120fa2881Sschwarze 107220fa2881Sschwarze sz = strlen(mdoc->last->child->string) + 107320fa2881Sschwarze 2 + strlen("\\(lqlibrary\\(rq"); 107420fa2881Sschwarze buf = mandoc_malloc(sz); 107520fa2881Sschwarze snprintf(buf, sz, "library \\(lq%s\\(rq", 107620fa2881Sschwarze mdoc->last->child->string); 107720fa2881Sschwarze free(mdoc->last->child->string); 107820fa2881Sschwarze mdoc->last->child->string = buf; 107920fa2881Sschwarze return(1); 108020fa2881Sschwarze } 108171719887Sschwarze 108271719887Sschwarze static int 1083b31af00dSschwarze post_eoln(POST_ARGS) 1084b31af00dSschwarze { 1085b31af00dSschwarze 108620fa2881Sschwarze if (mdoc->last->child) 108720fa2881Sschwarze mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_ARGSLOST); 1088b31af00dSschwarze return(1); 1089b31af00dSschwarze } 1090b31af00dSschwarze 1091b31af00dSschwarze 1092b31af00dSschwarze static int 10938521b0bcSschwarze post_vt(POST_ARGS) 10948521b0bcSschwarze { 10958521b0bcSschwarze const struct mdoc_node *n; 10968521b0bcSschwarze 10978521b0bcSschwarze /* 10988521b0bcSschwarze * The Vt macro comes in both ELEM and BLOCK form, both of which 10998521b0bcSschwarze * have different syntaxes (yet more context-sensitive 1100e7a93ef3Sschwarze * behaviour). ELEM types must have a child, which is already 1101e7a93ef3Sschwarze * guaranteed by the in_line parsing routine; BLOCK types, 11028521b0bcSschwarze * specifically the BODY, should only have TEXT children. 11038521b0bcSschwarze */ 11048521b0bcSschwarze 11058521b0bcSschwarze if (MDOC_BODY != mdoc->last->type) 11068521b0bcSschwarze return(1); 11078521b0bcSschwarze 11088521b0bcSschwarze for (n = mdoc->last->child; n; n = n->next) 1109bc49dbe1Sschwarze if (MDOC_TEXT != n->type) 111020fa2881Sschwarze mdoc_nmsg(mdoc, n, MANDOCERR_CHILD); 11118521b0bcSschwarze 11128521b0bcSschwarze return(1); 11138521b0bcSschwarze } 11148521b0bcSschwarze 11158521b0bcSschwarze 11168521b0bcSschwarze static int 1117f73abda9Skristaps post_nm(POST_ARGS) 1118f73abda9Skristaps { 111920fa2881Sschwarze char buf[BUFSIZ]; 112004e980cbSschwarze int c; 112120fa2881Sschwarze 1122160ac481Sschwarze if (NULL != mdoc->meta.name) 112320fa2881Sschwarze return(1); 112420fa2881Sschwarze 1125160ac481Sschwarze /* Try to use our children for setting the meta name. */ 112620fa2881Sschwarze 1127160ac481Sschwarze if (NULL != mdoc->last->child) { 112804e980cbSschwarze buf[0] = '\0'; 1129160ac481Sschwarze c = concat(buf, mdoc->last->child, BUFSIZ); 1130160ac481Sschwarze } else 1131160ac481Sschwarze c = 0; 1132160ac481Sschwarze 1133160ac481Sschwarze switch (c) { 1134160ac481Sschwarze case (-1): 113504e980cbSschwarze mdoc_nmsg(mdoc, mdoc->last->child, MANDOCERR_MEM); 113620fa2881Sschwarze return(0); 1137160ac481Sschwarze case (0): 1138160ac481Sschwarze mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NONAME); 1139160ac481Sschwarze mdoc->meta.name = mandoc_strdup("UNKNOWN"); 1140160ac481Sschwarze break; 1141160ac481Sschwarze default: 114220fa2881Sschwarze mdoc->meta.name = mandoc_strdup(buf); 1143160ac481Sschwarze break; 1144160ac481Sschwarze } 114520fa2881Sschwarze return(1); 114620fa2881Sschwarze } 114720fa2881Sschwarze 114820fa2881Sschwarze static int 114920fa2881Sschwarze post_literal(POST_ARGS) 115020fa2881Sschwarze { 115120fa2881Sschwarze 115220fa2881Sschwarze /* 115320fa2881Sschwarze * The `Dl' (note "el" not "one") and `Bd' macros unset the 115420fa2881Sschwarze * MDOC_LITERAL flag as they leave. Note that `Bd' only sets 115520fa2881Sschwarze * this in literal mode, but it doesn't hurt to just switch it 115620fa2881Sschwarze * off in general since displays can't be nested. 115720fa2881Sschwarze */ 115820fa2881Sschwarze 115920fa2881Sschwarze if (MDOC_BODY == mdoc->last->type) 116020fa2881Sschwarze mdoc->flags &= ~MDOC_LITERAL; 116120fa2881Sschwarze 116220fa2881Sschwarze return(1); 116320fa2881Sschwarze } 116420fa2881Sschwarze 116520fa2881Sschwarze static int 116620fa2881Sschwarze post_defaults(POST_ARGS) 116720fa2881Sschwarze { 116820fa2881Sschwarze struct mdoc_node *nn; 116920fa2881Sschwarze 117020fa2881Sschwarze /* 117120fa2881Sschwarze * The `Ar' defaults to "file ..." if no value is provided as an 117220fa2881Sschwarze * argument; the `Mt' and `Pa' macros use "~"; the `Li' just 117320fa2881Sschwarze * gets an empty string. 117420fa2881Sschwarze */ 1175f73abda9Skristaps 1176f73abda9Skristaps if (mdoc->last->child) 1177f73abda9Skristaps return(1); 117820fa2881Sschwarze 117920fa2881Sschwarze nn = mdoc->last; 118020fa2881Sschwarze mdoc->next = MDOC_NEXT_CHILD; 118120fa2881Sschwarze 118220fa2881Sschwarze switch (nn->tok) { 118320fa2881Sschwarze case (MDOC_Ar): 118420fa2881Sschwarze if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "file")) 118520fa2881Sschwarze return(0); 118620fa2881Sschwarze if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "...")) 118720fa2881Sschwarze return(0); 118820fa2881Sschwarze break; 118920fa2881Sschwarze case (MDOC_At): 119020fa2881Sschwarze if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "AT&T")) 119120fa2881Sschwarze return(0); 119220fa2881Sschwarze if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "UNIX")) 119320fa2881Sschwarze return(0); 119420fa2881Sschwarze break; 119520fa2881Sschwarze case (MDOC_Li): 119620fa2881Sschwarze if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "")) 119720fa2881Sschwarze return(0); 119820fa2881Sschwarze break; 119920fa2881Sschwarze case (MDOC_Pa): 120020fa2881Sschwarze /* FALLTHROUGH */ 120120fa2881Sschwarze case (MDOC_Mt): 120220fa2881Sschwarze if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "~")) 120320fa2881Sschwarze return(0); 120420fa2881Sschwarze break; 120520fa2881Sschwarze default: 120620fa2881Sschwarze abort(); 120720fa2881Sschwarze /* NOTREACHED */ 1208f73abda9Skristaps } 1209f73abda9Skristaps 121020fa2881Sschwarze mdoc->last = nn; 121120fa2881Sschwarze return(1); 121220fa2881Sschwarze } 1213f73abda9Skristaps 1214f73abda9Skristaps static int 1215f73abda9Skristaps post_at(POST_ARGS) 1216f73abda9Skristaps { 121720fa2881Sschwarze const char *p, *q; 121820fa2881Sschwarze char *buf; 121920fa2881Sschwarze size_t sz; 122020fa2881Sschwarze 122120fa2881Sschwarze /* 122220fa2881Sschwarze * If we have a child, look it up in the standard keys. If a 122320fa2881Sschwarze * key exist, use that instead of the child; if it doesn't, 122420fa2881Sschwarze * prefix "AT&T UNIX " to the existing data. 122520fa2881Sschwarze */ 1226f73abda9Skristaps 1227f73abda9Skristaps if (NULL == mdoc->last->child) 1228f73abda9Skristaps return(1); 122920fa2881Sschwarze 12306e03d529Sschwarze assert(MDOC_TEXT == mdoc->last->child->type); 123120fa2881Sschwarze p = mdoc_a2att(mdoc->last->child->string); 123220fa2881Sschwarze 123320fa2881Sschwarze if (p) { 123420fa2881Sschwarze free(mdoc->last->child->string); 123520fa2881Sschwarze mdoc->last->child->string = mandoc_strdup(p); 123620fa2881Sschwarze } else { 123720fa2881Sschwarze mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADATT); 123820fa2881Sschwarze p = "AT&T UNIX "; 123920fa2881Sschwarze q = mdoc->last->child->string; 124020fa2881Sschwarze sz = strlen(p) + strlen(q) + 1; 124120fa2881Sschwarze buf = mandoc_malloc(sz); 124220fa2881Sschwarze strlcpy(buf, p, sz); 124320fa2881Sschwarze strlcat(buf, q, sz); 124420fa2881Sschwarze free(mdoc->last->child->string); 124520fa2881Sschwarze mdoc->last->child->string = buf; 1246f73abda9Skristaps } 1247f73abda9Skristaps 124820fa2881Sschwarze return(1); 124920fa2881Sschwarze } 1250f73abda9Skristaps 1251f73abda9Skristaps static int 1252f73abda9Skristaps post_an(POST_ARGS) 1253f73abda9Skristaps { 1254769ee804Sschwarze struct mdoc_node *np; 1255f73abda9Skristaps 1256769ee804Sschwarze np = mdoc->last; 1257e7a93ef3Sschwarze if (AUTH__NONE == np->norm->An.auth) { 1258e7a93ef3Sschwarze if (0 == np->child) 1259e7a93ef3Sschwarze check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_GT, 0); 1260e7a93ef3Sschwarze } else if (np->child) 1261bb648afaSschwarze check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 0); 126220fa2881Sschwarze 126320fa2881Sschwarze return(1); 1264f73abda9Skristaps } 1265f73abda9Skristaps 1266f73abda9Skristaps 1267f73abda9Skristaps static int 1268f73abda9Skristaps post_it(POST_ARGS) 1269f73abda9Skristaps { 127019a69263Sschwarze int i, cols; 12716093755cSschwarze enum mdoc_list lt; 1272f73abda9Skristaps struct mdoc_node *n, *c; 12736093755cSschwarze enum mandocerr er; 1274f73abda9Skristaps 1275f73abda9Skristaps if (MDOC_BLOCK != mdoc->last->type) 1276f73abda9Skristaps return(1); 1277f73abda9Skristaps 1278f73abda9Skristaps n = mdoc->last->parent->parent; 12798c62fbf5Sschwarze lt = n->norm->Bl.type; 12806093755cSschwarze 12816093755cSschwarze if (LIST__NONE == lt) { 12826e03d529Sschwarze mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_LISTTYPE); 128320fa2881Sschwarze return(1); 12846e03d529Sschwarze } 1285f73abda9Skristaps 12866093755cSschwarze switch (lt) { 12876093755cSschwarze case (LIST_tag): 12886093755cSschwarze if (mdoc->last->head->child) 1289f73abda9Skristaps break; 12906093755cSschwarze /* FIXME: give this a dummy value. */ 129120fa2881Sschwarze mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOARGS); 1292f73abda9Skristaps break; 12936093755cSschwarze case (LIST_hang): 1294f73abda9Skristaps /* FALLTHROUGH */ 12956093755cSschwarze case (LIST_ohang): 1296f73abda9Skristaps /* FALLTHROUGH */ 12976093755cSschwarze case (LIST_inset): 1298f73abda9Skristaps /* FALLTHROUGH */ 12996093755cSschwarze case (LIST_diag): 1300f73abda9Skristaps if (NULL == mdoc->last->head->child) 130120fa2881Sschwarze mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOARGS); 1302f73abda9Skristaps break; 13036093755cSschwarze case (LIST_bullet): 1304f73abda9Skristaps /* FALLTHROUGH */ 13056093755cSschwarze case (LIST_dash): 1306f73abda9Skristaps /* FALLTHROUGH */ 13076093755cSschwarze case (LIST_enum): 1308f73abda9Skristaps /* FALLTHROUGH */ 13096093755cSschwarze case (LIST_hyphen): 13109f373962Sschwarze if (NULL == mdoc->last->body->child) 131120fa2881Sschwarze mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOBODY); 1312f73abda9Skristaps /* FALLTHROUGH */ 13136093755cSschwarze case (LIST_item): 1314f73abda9Skristaps if (mdoc->last->head->child) 131520fa2881Sschwarze mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_ARGSLOST); 1316f73abda9Skristaps break; 13176093755cSschwarze case (LIST_column): 13188c62fbf5Sschwarze cols = (int)n->norm->Bl.ncols; 13196093755cSschwarze 13206093755cSschwarze assert(NULL == mdoc->last->head->child); 13216093755cSschwarze 13226093755cSschwarze if (NULL == mdoc->last->body->child) 132320fa2881Sschwarze mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOBODY); 13246093755cSschwarze 13256093755cSschwarze for (i = 0, c = mdoc->last->child; c; c = c->next) 13266093755cSschwarze if (MDOC_BODY == c->type) 1327f73abda9Skristaps i++; 132853292e81Sschwarze 13296093755cSschwarze if (i < cols) 13306093755cSschwarze er = MANDOCERR_ARGCOUNT; 13316093755cSschwarze else if (i == cols || i == cols + 1) 1332f73abda9Skristaps break; 13336093755cSschwarze else 13346093755cSschwarze er = MANDOCERR_SYNTARGCOUNT; 133553292e81Sschwarze 1336a35fc07aSschwarze mandoc_vmsg(er, mdoc->parse, mdoc->last->line, 1337a35fc07aSschwarze mdoc->last->pos, 13386e03d529Sschwarze "columns == %d (have %d)", cols, i); 133919a69263Sschwarze return(MANDOCERR_ARGCOUNT == er); 1340f73abda9Skristaps default: 1341f73abda9Skristaps break; 1342f73abda9Skristaps } 1343f73abda9Skristaps 1344f73abda9Skristaps return(1); 1345f73abda9Skristaps } 1346f73abda9Skristaps 134720fa2881Sschwarze static int 134820fa2881Sschwarze post_bl_block(POST_ARGS) 134920fa2881Sschwarze { 1350bb99f0faSschwarze struct mdoc_node *n, *ni, *nc; 135120fa2881Sschwarze 135220fa2881Sschwarze /* 135320fa2881Sschwarze * These are fairly complicated, so we've broken them into two 135420fa2881Sschwarze * functions. post_bl_block_tag() is called when a -tag is 135520fa2881Sschwarze * specified, but no -width (it must be guessed). The second 135620fa2881Sschwarze * when a -width is specified (macro indicators must be 135720fa2881Sschwarze * rewritten into real lengths). 135820fa2881Sschwarze */ 135920fa2881Sschwarze 136020fa2881Sschwarze n = mdoc->last; 136120fa2881Sschwarze 13628c62fbf5Sschwarze if (LIST_tag == n->norm->Bl.type && 13638c62fbf5Sschwarze NULL == n->norm->Bl.width) { 136420fa2881Sschwarze if ( ! post_bl_block_tag(mdoc)) 136520fa2881Sschwarze return(0); 1366bb99f0faSschwarze assert(n->norm->Bl.width); 13678c62fbf5Sschwarze } else if (NULL != n->norm->Bl.width) { 136820fa2881Sschwarze if ( ! post_bl_block_width(mdoc)) 136920fa2881Sschwarze return(0); 13708c62fbf5Sschwarze assert(n->norm->Bl.width); 1371bb99f0faSschwarze } 1372bb99f0faSschwarze 1373bb99f0faSschwarze for (ni = n->body->child; ni; ni = ni->next) { 1374bb99f0faSschwarze if (NULL == ni->body) 1375bb99f0faSschwarze continue; 1376bb99f0faSschwarze nc = ni->body->last; 1377bb99f0faSschwarze while (NULL != nc) { 1378bb99f0faSschwarze switch (nc->tok) { 1379bb99f0faSschwarze case (MDOC_Pp): 1380bb99f0faSschwarze /* FALLTHROUGH */ 1381bb99f0faSschwarze case (MDOC_Lp): 1382bb99f0faSschwarze /* FALLTHROUGH */ 1383bb99f0faSschwarze case (MDOC_br): 1384bb99f0faSschwarze break; 1385bb99f0faSschwarze default: 1386bb99f0faSschwarze nc = NULL; 1387bb99f0faSschwarze continue; 1388bb99f0faSschwarze } 1389bb99f0faSschwarze if (NULL == ni->next) { 1390bb99f0faSschwarze mdoc_nmsg(mdoc, nc, MANDOCERR_MOVEPAR); 1391bb99f0faSschwarze if ( ! mdoc_node_relink(mdoc, nc)) 1392bb99f0faSschwarze return(0); 1393bb99f0faSschwarze } else if (0 == n->norm->Bl.comp && 1394bb99f0faSschwarze LIST_column != n->norm->Bl.type) { 1395bb99f0faSschwarze mdoc_nmsg(mdoc, nc, MANDOCERR_IGNPAR); 1396bb99f0faSschwarze mdoc_node_delete(mdoc, nc); 1397bb99f0faSschwarze } else 1398bb99f0faSschwarze break; 1399bb99f0faSschwarze nc = ni->body->last; 1400bb99f0faSschwarze } 1401bb99f0faSschwarze } 140220fa2881Sschwarze return(1); 140320fa2881Sschwarze } 140420fa2881Sschwarze 140520fa2881Sschwarze static int 140620fa2881Sschwarze post_bl_block_width(POST_ARGS) 140720fa2881Sschwarze { 140820fa2881Sschwarze size_t width; 140920fa2881Sschwarze int i; 141020fa2881Sschwarze enum mdoct tok; 141120fa2881Sschwarze struct mdoc_node *n; 141220fa2881Sschwarze char buf[NUMSIZ]; 141320fa2881Sschwarze 141420fa2881Sschwarze n = mdoc->last; 141520fa2881Sschwarze 141620fa2881Sschwarze /* 141720fa2881Sschwarze * Calculate the real width of a list from the -width string, 141820fa2881Sschwarze * which may contain a macro (with a known default width), a 141920fa2881Sschwarze * literal string, or a scaling width. 142020fa2881Sschwarze * 142120fa2881Sschwarze * If the value to -width is a macro, then we re-write it to be 142220fa2881Sschwarze * the macro's width as set in share/tmac/mdoc/doc-common. 142320fa2881Sschwarze */ 142420fa2881Sschwarze 14258c62fbf5Sschwarze if (0 == strcmp(n->norm->Bl.width, "Ds")) 142620fa2881Sschwarze width = 6; 14278c62fbf5Sschwarze else if (MDOC_MAX == (tok = mdoc_hash_find(n->norm->Bl.width))) 142820fa2881Sschwarze return(1); 142919a69263Sschwarze else if (0 == (width = macro2len(tok))) { 143020fa2881Sschwarze mdoc_nmsg(mdoc, n, MANDOCERR_BADWIDTH); 143120fa2881Sschwarze return(1); 143220fa2881Sschwarze } 143320fa2881Sschwarze 143420fa2881Sschwarze /* The value already exists: free and reallocate it. */ 143520fa2881Sschwarze 143620fa2881Sschwarze assert(n->args); 143720fa2881Sschwarze 143820fa2881Sschwarze for (i = 0; i < (int)n->args->argc; i++) 143920fa2881Sschwarze if (MDOC_Width == n->args->argv[i].arg) 144020fa2881Sschwarze break; 144120fa2881Sschwarze 144220fa2881Sschwarze assert(i < (int)n->args->argc); 144320fa2881Sschwarze 144404e980cbSschwarze snprintf(buf, NUMSIZ, "%un", (unsigned int)width); 144520fa2881Sschwarze free(n->args->argv[i].value[0]); 144620fa2881Sschwarze n->args->argv[i].value[0] = mandoc_strdup(buf); 144720fa2881Sschwarze 144820fa2881Sschwarze /* Set our width! */ 14498c62fbf5Sschwarze n->norm->Bl.width = n->args->argv[i].value[0]; 145020fa2881Sschwarze return(1); 145120fa2881Sschwarze } 145220fa2881Sschwarze 145320fa2881Sschwarze static int 145420fa2881Sschwarze post_bl_block_tag(POST_ARGS) 145520fa2881Sschwarze { 145620fa2881Sschwarze struct mdoc_node *n, *nn; 145720fa2881Sschwarze size_t sz, ssz; 145820fa2881Sschwarze int i; 145920fa2881Sschwarze char buf[NUMSIZ]; 146020fa2881Sschwarze 146120fa2881Sschwarze /* 146220fa2881Sschwarze * Calculate the -width for a `Bl -tag' list if it hasn't been 146320fa2881Sschwarze * provided. Uses the first head macro. NOTE AGAIN: this is 146420fa2881Sschwarze * ONLY if the -width argument has NOT been provided. See 146520fa2881Sschwarze * post_bl_block_width() for converting the -width string. 146620fa2881Sschwarze */ 146720fa2881Sschwarze 146820fa2881Sschwarze sz = 10; 146920fa2881Sschwarze n = mdoc->last; 147020fa2881Sschwarze 147120fa2881Sschwarze for (nn = n->body->child; nn; nn = nn->next) { 147220fa2881Sschwarze if (MDOC_It != nn->tok) 147320fa2881Sschwarze continue; 147420fa2881Sschwarze 147520fa2881Sschwarze assert(MDOC_BLOCK == nn->type); 147620fa2881Sschwarze nn = nn->head->child; 147720fa2881Sschwarze 147820fa2881Sschwarze if (nn == NULL) 147920fa2881Sschwarze break; 148020fa2881Sschwarze 148120fa2881Sschwarze if (MDOC_TEXT == nn->type) { 148220fa2881Sschwarze sz = strlen(nn->string) + 1; 148320fa2881Sschwarze break; 148420fa2881Sschwarze } 148520fa2881Sschwarze 148619a69263Sschwarze if (0 != (ssz = macro2len(nn->tok))) 148720fa2881Sschwarze sz = ssz; 148820fa2881Sschwarze 148920fa2881Sschwarze break; 149020fa2881Sschwarze } 149120fa2881Sschwarze 149220fa2881Sschwarze /* Defaults to ten ens. */ 149320fa2881Sschwarze 149404e980cbSschwarze snprintf(buf, NUMSIZ, "%un", (unsigned int)sz); 149520fa2881Sschwarze 149620fa2881Sschwarze /* 149720fa2881Sschwarze * We have to dynamically add this to the macro's argument list. 149820fa2881Sschwarze * We're guaranteed that a MDOC_Width doesn't already exist. 149920fa2881Sschwarze */ 150020fa2881Sschwarze 150120fa2881Sschwarze assert(n->args); 150220fa2881Sschwarze i = (int)(n->args->argc)++; 150320fa2881Sschwarze 150420fa2881Sschwarze n->args->argv = mandoc_realloc(n->args->argv, 150520fa2881Sschwarze n->args->argc * sizeof(struct mdoc_argv)); 150620fa2881Sschwarze 150720fa2881Sschwarze n->args->argv[i].arg = MDOC_Width; 150820fa2881Sschwarze n->args->argv[i].line = n->line; 150920fa2881Sschwarze n->args->argv[i].pos = n->pos; 151020fa2881Sschwarze n->args->argv[i].sz = 1; 151120fa2881Sschwarze n->args->argv[i].value = mandoc_malloc(sizeof(char *)); 151220fa2881Sschwarze n->args->argv[i].value[0] = mandoc_strdup(buf); 151320fa2881Sschwarze 151420fa2881Sschwarze /* Set our width! */ 15158c62fbf5Sschwarze n->norm->Bl.width = n->args->argv[i].value[0]; 151620fa2881Sschwarze return(1); 151720fa2881Sschwarze } 151820fa2881Sschwarze 1519f73abda9Skristaps 1520f73abda9Skristaps static int 1521395185ccSschwarze post_bl_head(POST_ARGS) 1522395185ccSschwarze { 152320fa2881Sschwarze struct mdoc_node *np, *nn, *nnp; 152420fa2881Sschwarze int i, j; 1525395185ccSschwarze 15268c62fbf5Sschwarze if (LIST_column != mdoc->last->norm->Bl.type) 152720fa2881Sschwarze /* FIXME: this should be ERROR class... */ 152820fa2881Sschwarze return(hwarn_eq0(mdoc)); 1529395185ccSschwarze 153020fa2881Sschwarze /* 153120fa2881Sschwarze * Convert old-style lists, where the column width specifiers 153220fa2881Sschwarze * trail as macro parameters, to the new-style ("normal-form") 153320fa2881Sschwarze * lists where they're argument values following -column. 153420fa2881Sschwarze */ 153520fa2881Sschwarze 153620fa2881Sschwarze /* First, disallow both types and allow normal-form. */ 153720fa2881Sschwarze 153820fa2881Sschwarze /* 153920fa2881Sschwarze * TODO: technically, we can accept both and just merge the two 154020fa2881Sschwarze * lists, but I'll leave that for another day. 154120fa2881Sschwarze */ 154220fa2881Sschwarze 15438c62fbf5Sschwarze if (mdoc->last->norm->Bl.ncols && mdoc->last->nchild) { 154420fa2881Sschwarze mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_COLUMNS); 15456093755cSschwarze return(0); 154620fa2881Sschwarze } else if (NULL == mdoc->last->child) 154720fa2881Sschwarze return(1); 154820fa2881Sschwarze 154920fa2881Sschwarze np = mdoc->last->parent; 155020fa2881Sschwarze assert(np->args); 155120fa2881Sschwarze 155220fa2881Sschwarze for (j = 0; j < (int)np->args->argc; j++) 155320fa2881Sschwarze if (MDOC_Column == np->args->argv[j].arg) 155420fa2881Sschwarze break; 155520fa2881Sschwarze 155620fa2881Sschwarze assert(j < (int)np->args->argc); 155720fa2881Sschwarze assert(0 == np->args->argv[j].sz); 155820fa2881Sschwarze 155920fa2881Sschwarze /* 1560a5e11edeSschwarze * Accommodate for new-style groff column syntax. Shuffle the 156120fa2881Sschwarze * child nodes, all of which must be TEXT, as arguments for the 156220fa2881Sschwarze * column field. Then, delete the head children. 156320fa2881Sschwarze */ 156420fa2881Sschwarze 156520fa2881Sschwarze np->args->argv[j].sz = (size_t)mdoc->last->nchild; 156620fa2881Sschwarze np->args->argv[j].value = mandoc_malloc 156720fa2881Sschwarze ((size_t)mdoc->last->nchild * sizeof(char *)); 156820fa2881Sschwarze 15698c62fbf5Sschwarze mdoc->last->norm->Bl.ncols = np->args->argv[j].sz; 157004e980cbSschwarze mdoc->last->norm->Bl.cols = (void *)np->args->argv[j].value; 157120fa2881Sschwarze 157220fa2881Sschwarze for (i = 0, nn = mdoc->last->child; nn; i++) { 157320fa2881Sschwarze np->args->argv[j].value[i] = nn->string; 157420fa2881Sschwarze nn->string = NULL; 157520fa2881Sschwarze nnp = nn; 157620fa2881Sschwarze nn = nn->next; 157720fa2881Sschwarze mdoc_node_delete(NULL, nnp); 1578395185ccSschwarze } 157920fa2881Sschwarze 158020fa2881Sschwarze mdoc->last->nchild = 0; 158120fa2881Sschwarze mdoc->last->child = NULL; 158220fa2881Sschwarze 15836093755cSschwarze return(1); 1584b16e7ddfSschwarze } 1585b16e7ddfSschwarze 1586395185ccSschwarze static int 1587f73abda9Skristaps post_bl(POST_ARGS) 1588f73abda9Skristaps { 1589*2a427d60Sschwarze struct mdoc_node *nparent, *nprev; /* of the Bl block */ 1590*2a427d60Sschwarze struct mdoc_node *nblock, *nbody; /* of the Bl */ 1591*2a427d60Sschwarze struct mdoc_node *nchild, *nnext; /* of the Bl body */ 1592f73abda9Skristaps 1593*2a427d60Sschwarze nbody = mdoc->last; 1594*2a427d60Sschwarze switch (nbody->type) { 1595*2a427d60Sschwarze case (MDOC_BLOCK): 159620fa2881Sschwarze return(post_bl_block(mdoc)); 1597*2a427d60Sschwarze case (MDOC_HEAD): 1598*2a427d60Sschwarze return(post_bl_head(mdoc)); 1599*2a427d60Sschwarze case (MDOC_BODY): 1600f6127a73Sschwarze break; 1601*2a427d60Sschwarze default: 1602*2a427d60Sschwarze return(1); 1603f6127a73Sschwarze } 1604f6127a73Sschwarze 1605*2a427d60Sschwarze nchild = nbody->child; 1606*2a427d60Sschwarze while (NULL != nchild) { 1607*2a427d60Sschwarze if (MDOC_It == nchild->tok || MDOC_Sm == nchild->tok) { 1608*2a427d60Sschwarze nchild = nchild->next; 1609*2a427d60Sschwarze continue; 1610*2a427d60Sschwarze } 1611*2a427d60Sschwarze 1612*2a427d60Sschwarze mdoc_nmsg(mdoc, nchild, MANDOCERR_CHILD); 1613*2a427d60Sschwarze 1614*2a427d60Sschwarze /* 1615*2a427d60Sschwarze * Move the node out of the Bl block. 1616*2a427d60Sschwarze * First, collect all required node pointers. 1617*2a427d60Sschwarze */ 1618*2a427d60Sschwarze 1619*2a427d60Sschwarze nblock = nbody->parent; 1620*2a427d60Sschwarze nprev = nblock->prev; 1621*2a427d60Sschwarze nparent = nblock->parent; 1622*2a427d60Sschwarze nnext = nchild->next; 1623*2a427d60Sschwarze 1624*2a427d60Sschwarze /* 1625*2a427d60Sschwarze * Unlink this child. 1626*2a427d60Sschwarze */ 1627*2a427d60Sschwarze 1628*2a427d60Sschwarze assert(NULL == nchild->prev); 1629*2a427d60Sschwarze if (0 == --nbody->nchild) { 1630*2a427d60Sschwarze nbody->child = NULL; 1631*2a427d60Sschwarze nbody->last = NULL; 1632*2a427d60Sschwarze assert(NULL == nnext); 1633*2a427d60Sschwarze } else { 1634*2a427d60Sschwarze nbody->child = nnext; 1635*2a427d60Sschwarze nnext->prev = NULL; 1636*2a427d60Sschwarze } 1637*2a427d60Sschwarze 1638*2a427d60Sschwarze /* 1639*2a427d60Sschwarze * Relink this child. 1640*2a427d60Sschwarze */ 1641*2a427d60Sschwarze 1642*2a427d60Sschwarze nchild->parent = nparent; 1643*2a427d60Sschwarze nchild->prev = nprev; 1644*2a427d60Sschwarze nchild->next = nblock; 1645*2a427d60Sschwarze 1646*2a427d60Sschwarze nblock->prev = nchild; 1647*2a427d60Sschwarze nparent->nchild++; 1648*2a427d60Sschwarze if (NULL == nprev) 1649*2a427d60Sschwarze nparent->child = nchild; 1650*2a427d60Sschwarze else 1651*2a427d60Sschwarze nprev->next = nchild; 1652*2a427d60Sschwarze 1653*2a427d60Sschwarze nchild = nnext; 1654f73abda9Skristaps } 1655f73abda9Skristaps 1656f73abda9Skristaps return(1); 1657f73abda9Skristaps } 1658f73abda9Skristaps 1659f73abda9Skristaps static int 1660f73abda9Skristaps ebool(struct mdoc *mdoc) 1661f73abda9Skristaps { 1662f73abda9Skristaps 1663bb648afaSschwarze if (NULL == mdoc->last->child) { 1664bb648afaSschwarze mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_MACROEMPTY); 1665bb648afaSschwarze mdoc_node_delete(mdoc, mdoc->last); 1666f73abda9Skristaps return(1); 1667bb648afaSschwarze } 1668bb648afaSschwarze check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 1); 1669f73abda9Skristaps 167020fa2881Sschwarze assert(MDOC_TEXT == mdoc->last->child->type); 167120fa2881Sschwarze 167220fa2881Sschwarze if (0 == strcmp(mdoc->last->child->string, "on")) 167320fa2881Sschwarze return(1); 167420fa2881Sschwarze if (0 == strcmp(mdoc->last->child->string, "off")) 167520fa2881Sschwarze return(1); 167620fa2881Sschwarze 167720fa2881Sschwarze mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADBOOL); 167820fa2881Sschwarze return(1); 167920fa2881Sschwarze } 1680f73abda9Skristaps 1681f73abda9Skristaps static int 1682f73abda9Skristaps post_root(POST_ARGS) 1683f73abda9Skristaps { 168420fa2881Sschwarze int erc; 168520fa2881Sschwarze struct mdoc_node *n; 1686f73abda9Skristaps 168720fa2881Sschwarze erc = 0; 168820fa2881Sschwarze 168920fa2881Sschwarze /* Check that we have a finished prologue. */ 169020fa2881Sschwarze 169120fa2881Sschwarze if ( ! (MDOC_PBODY & mdoc->flags)) { 169220fa2881Sschwarze erc++; 16936e03d529Sschwarze mdoc_nmsg(mdoc, mdoc->first, MANDOCERR_NODOCPROLOG); 1694f73abda9Skristaps } 1695f73abda9Skristaps 169620fa2881Sschwarze n = mdoc->first; 169720fa2881Sschwarze assert(n); 169820fa2881Sschwarze 169920fa2881Sschwarze /* Check that we begin with a proper `Sh'. */ 170020fa2881Sschwarze 170120fa2881Sschwarze if (NULL == n->child) { 170220fa2881Sschwarze erc++; 170320fa2881Sschwarze mdoc_nmsg(mdoc, n, MANDOCERR_NODOCBODY); 170420fa2881Sschwarze } else if (MDOC_BLOCK != n->child->type || 170520fa2881Sschwarze MDOC_Sh != n->child->tok) { 170620fa2881Sschwarze erc++; 170720fa2881Sschwarze /* Can this be lifted? See rxdebug.1 for example. */ 170820fa2881Sschwarze mdoc_nmsg(mdoc, n, MANDOCERR_NODOCBODY); 170920fa2881Sschwarze } 171020fa2881Sschwarze 171120fa2881Sschwarze return(erc ? 0 : 1); 171220fa2881Sschwarze } 1713f73abda9Skristaps 1714f73abda9Skristaps static int 1715f73abda9Skristaps post_st(POST_ARGS) 1716f73abda9Skristaps { 1717bb648afaSschwarze struct mdoc_node *ch; 171820fa2881Sschwarze const char *p; 1719f73abda9Skristaps 1720bb648afaSschwarze if (NULL == (ch = mdoc->last->child)) { 1721bb648afaSschwarze mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_MACROEMPTY); 1722bb648afaSschwarze mdoc_node_delete(mdoc, mdoc->last); 1723bb648afaSschwarze return(1); 1724bb648afaSschwarze } 172520fa2881Sschwarze 1726bb648afaSschwarze assert(MDOC_TEXT == ch->type); 172720fa2881Sschwarze 1728bb648afaSschwarze if (NULL == (p = mdoc_a2st(ch->string))) { 172920fa2881Sschwarze mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADSTANDARD); 173020fa2881Sschwarze mdoc_node_delete(mdoc, mdoc->last); 173120fa2881Sschwarze } else { 1732bb648afaSschwarze free(ch->string); 1733bb648afaSschwarze ch->string = mandoc_strdup(p); 1734f73abda9Skristaps } 1735f73abda9Skristaps 173620fa2881Sschwarze return(1); 173720fa2881Sschwarze } 1738f73abda9Skristaps 1739f73abda9Skristaps static int 1740011fe33bSschwarze post_rs(POST_ARGS) 1741011fe33bSschwarze { 174220fa2881Sschwarze struct mdoc_node *nn, *next, *prev; 174320fa2881Sschwarze int i, j; 1744011fe33bSschwarze 1745bb648afaSschwarze switch (mdoc->last->type) { 1746bb648afaSschwarze case (MDOC_HEAD): 1747bb648afaSschwarze check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_EQ, 0); 1748011fe33bSschwarze return(1); 1749bb648afaSschwarze case (MDOC_BODY): 1750bb648afaSschwarze if (mdoc->last->child) 1751bb648afaSschwarze break; 1752bb648afaSschwarze check_count(mdoc, MDOC_BODY, CHECK_WARN, CHECK_GT, 0); 1753bb648afaSschwarze return(1); 1754bb648afaSschwarze default: 1755bb648afaSschwarze return(1); 1756bb648afaSschwarze } 1757011fe33bSschwarze 175820fa2881Sschwarze /* 175920fa2881Sschwarze * Make sure only certain types of nodes are allowed within the 176020fa2881Sschwarze * the `Rs' body. Delete offending nodes and raise a warning. 176120fa2881Sschwarze * Do this before re-ordering for the sake of clarity. 176220fa2881Sschwarze */ 176320fa2881Sschwarze 176420fa2881Sschwarze next = NULL; 176520fa2881Sschwarze for (nn = mdoc->last->child; nn; nn = next) { 176620fa2881Sschwarze for (i = 0; i < RSORD_MAX; i++) 176720fa2881Sschwarze if (nn->tok == rsord[i]) 1768011fe33bSschwarze break; 176920fa2881Sschwarze 177020fa2881Sschwarze if (i < RSORD_MAX) { 17715d273f35Sschwarze if (MDOC__J == rsord[i] || MDOC__B == rsord[i]) 17725d273f35Sschwarze mdoc->last->norm->Rs.quote_T++; 177320fa2881Sschwarze next = nn->next; 177420fa2881Sschwarze continue; 177520fa2881Sschwarze } 177620fa2881Sschwarze 177720fa2881Sschwarze next = nn->next; 177820fa2881Sschwarze mdoc_nmsg(mdoc, nn, MANDOCERR_CHILD); 177920fa2881Sschwarze mdoc_node_delete(mdoc, nn); 178020fa2881Sschwarze } 178120fa2881Sschwarze 178220fa2881Sschwarze /* 1783c6176538Sschwarze * Nothing to sort if only invalid nodes were found 1784c6176538Sschwarze * inside the `Rs' body. 1785c6176538Sschwarze */ 1786c6176538Sschwarze 1787c6176538Sschwarze if (NULL == mdoc->last->child) 1788c6176538Sschwarze return(1); 1789c6176538Sschwarze 1790c6176538Sschwarze /* 179120fa2881Sschwarze * The full `Rs' block needs special handling to order the 179220fa2881Sschwarze * sub-elements according to `rsord'. Pick through each element 179320fa2881Sschwarze * and correctly order it. This is a insertion sort. 179420fa2881Sschwarze */ 179520fa2881Sschwarze 179620fa2881Sschwarze next = NULL; 179720fa2881Sschwarze for (nn = mdoc->last->child->next; nn; nn = next) { 179820fa2881Sschwarze /* Determine order of `nn'. */ 179920fa2881Sschwarze for (i = 0; i < RSORD_MAX; i++) 180020fa2881Sschwarze if (rsord[i] == nn->tok) 180120fa2881Sschwarze break; 180220fa2881Sschwarze 180320fa2881Sschwarze /* 180420fa2881Sschwarze * Remove `nn' from the chain. This somewhat 180520fa2881Sschwarze * repeats mdoc_node_unlink(), but since we're 180620fa2881Sschwarze * just re-ordering, there's no need for the 180720fa2881Sschwarze * full unlink process. 180820fa2881Sschwarze */ 180920fa2881Sschwarze 181020fa2881Sschwarze if (NULL != (next = nn->next)) 181120fa2881Sschwarze next->prev = nn->prev; 181220fa2881Sschwarze 181320fa2881Sschwarze if (NULL != (prev = nn->prev)) 181420fa2881Sschwarze prev->next = nn->next; 181520fa2881Sschwarze 181620fa2881Sschwarze nn->prev = nn->next = NULL; 181720fa2881Sschwarze 181820fa2881Sschwarze /* 181920fa2881Sschwarze * Scan back until we reach a node that's 182020fa2881Sschwarze * ordered before `nn'. 182120fa2881Sschwarze */ 182220fa2881Sschwarze 182320fa2881Sschwarze for ( ; prev ; prev = prev->prev) { 182420fa2881Sschwarze /* Determine order of `prev'. */ 182520fa2881Sschwarze for (j = 0; j < RSORD_MAX; j++) 182620fa2881Sschwarze if (rsord[j] == prev->tok) 182720fa2881Sschwarze break; 182820fa2881Sschwarze 182920fa2881Sschwarze if (j <= i) 183020fa2881Sschwarze break; 183120fa2881Sschwarze } 183220fa2881Sschwarze 183320fa2881Sschwarze /* 183420fa2881Sschwarze * Set `nn' back into its correct place in front 183520fa2881Sschwarze * of the `prev' node. 183620fa2881Sschwarze */ 183720fa2881Sschwarze 183820fa2881Sschwarze nn->prev = prev; 183920fa2881Sschwarze 184020fa2881Sschwarze if (prev) { 184120fa2881Sschwarze if (prev->next) 184220fa2881Sschwarze prev->next->prev = nn; 184320fa2881Sschwarze nn->next = prev->next; 184420fa2881Sschwarze prev->next = nn; 184520fa2881Sschwarze } else { 184620fa2881Sschwarze mdoc->last->child->prev = nn; 184720fa2881Sschwarze nn->next = mdoc->last->child; 184820fa2881Sschwarze mdoc->last->child = nn; 184920fa2881Sschwarze } 1850011fe33bSschwarze } 1851011fe33bSschwarze 1852011fe33bSschwarze return(1); 1853011fe33bSschwarze } 1854011fe33bSschwarze 1855011fe33bSschwarze static int 1856af216717Sschwarze post_ns(POST_ARGS) 1857af216717Sschwarze { 1858af216717Sschwarze 1859af216717Sschwarze if (MDOC_LINE & mdoc->last->flags) 1860af216717Sschwarze mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_IGNNS); 1861af216717Sschwarze return(1); 1862af216717Sschwarze } 1863af216717Sschwarze 1864af216717Sschwarze static int 1865f73abda9Skristaps post_sh(POST_ARGS) 1866f73abda9Skristaps { 1867f73abda9Skristaps 1868f73abda9Skristaps if (MDOC_HEAD == mdoc->last->type) 1869f73abda9Skristaps return(post_sh_head(mdoc)); 1870f73abda9Skristaps if (MDOC_BODY == mdoc->last->type) 1871f73abda9Skristaps return(post_sh_body(mdoc)); 1872f73abda9Skristaps 1873f73abda9Skristaps return(1); 1874f73abda9Skristaps } 1875f73abda9Skristaps 1876f73abda9Skristaps static int 1877f73abda9Skristaps post_sh_body(POST_ARGS) 1878f73abda9Skristaps { 1879f73abda9Skristaps struct mdoc_node *n; 1880f73abda9Skristaps 1881f8c9d6f2Sschwarze if (SEC_NAME != mdoc->lastsec) 1882f73abda9Skristaps return(1); 1883f73abda9Skristaps 1884f73abda9Skristaps /* 1885f73abda9Skristaps * Warn if the NAME section doesn't contain the `Nm' and `Nd' 1886f73abda9Skristaps * macros (can have multiple `Nm' and one `Nd'). Note that the 1887f73abda9Skristaps * children of the BODY declaration can also be "text". 1888f73abda9Skristaps */ 1889f73abda9Skristaps 189020fa2881Sschwarze if (NULL == (n = mdoc->last->child)) { 189120fa2881Sschwarze mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADNAMESEC); 189220fa2881Sschwarze return(1); 189320fa2881Sschwarze } 1894f73abda9Skristaps 1895f73abda9Skristaps for ( ; n && n->next; n = n->next) { 1896f73abda9Skristaps if (MDOC_ELEM == n->type && MDOC_Nm == n->tok) 1897f73abda9Skristaps continue; 1898f73abda9Skristaps if (MDOC_TEXT == n->type) 1899f73abda9Skristaps continue; 190020fa2881Sschwarze mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADNAMESEC); 1901f73abda9Skristaps } 1902f73abda9Skristaps 190349d529b5Sschwarze assert(n); 19044602e85cSschwarze if (MDOC_BLOCK == n->type && MDOC_Nd == n->tok) 1905f73abda9Skristaps return(1); 1906f73abda9Skristaps 190720fa2881Sschwarze mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADNAMESEC); 190820fa2881Sschwarze return(1); 190920fa2881Sschwarze } 1910f73abda9Skristaps 1911f73abda9Skristaps static int 1912f73abda9Skristaps post_sh_head(POST_ARGS) 1913f73abda9Skristaps { 19143216dddfSschwarze char buf[BUFSIZ]; 1915a2cff342Sschwarze struct mdoc_node *n; 1916f73abda9Skristaps enum mdoc_sec sec; 191704e980cbSschwarze int c; 1918f73abda9Skristaps 1919f73abda9Skristaps /* 1920f73abda9Skristaps * Process a new section. Sections are either "named" or 192120fa2881Sschwarze * "custom". Custom sections are user-defined, while named ones 192220fa2881Sschwarze * follow a conventional order and may only appear in certain 192320fa2881Sschwarze * manual sections. 1924f73abda9Skristaps */ 1925f73abda9Skristaps 192604e980cbSschwarze sec = SEC_CUSTOM; 192704e980cbSschwarze buf[0] = '\0'; 192804e980cbSschwarze if (-1 == (c = concat(buf, mdoc->last->child, BUFSIZ))) { 192904e980cbSschwarze mdoc_nmsg(mdoc, mdoc->last->child, MANDOCERR_MEM); 19306e03d529Sschwarze return(0); 193104e980cbSschwarze } else if (1 == c) 193219a69263Sschwarze sec = a2sec(buf); 1933f73abda9Skristaps 193420fa2881Sschwarze /* The NAME should be first. */ 1935f73abda9Skristaps 1936fccfce9dSschwarze if (SEC_NAME != sec && SEC_NONE == mdoc->lastnamed) 193720fa2881Sschwarze mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NAMESECFIRST); 193820fa2881Sschwarze 193920fa2881Sschwarze /* The SYNOPSIS gets special attention in other areas. */ 194020fa2881Sschwarze 194122881299Sschwarze if (SEC_SYNOPSIS == sec) { 194222881299Sschwarze roff_setreg(mdoc->roff, "nS", 1); 194320fa2881Sschwarze mdoc->flags |= MDOC_SYNOPSIS; 194422881299Sschwarze } else { 194522881299Sschwarze roff_setreg(mdoc->roff, "nS", 0); 194620fa2881Sschwarze mdoc->flags &= ~MDOC_SYNOPSIS; 194722881299Sschwarze } 194820fa2881Sschwarze 194920fa2881Sschwarze /* Mark our last section. */ 195020fa2881Sschwarze 195120fa2881Sschwarze mdoc->lastsec = sec; 19521eccdf28Sschwarze 19531eccdf28Sschwarze /* 19541eccdf28Sschwarze * Set the section attribute for the current HEAD, for its 19551eccdf28Sschwarze * parent BLOCK, and for the HEAD children; the latter can 19561eccdf28Sschwarze * only be TEXT nodes, so no recursion is needed. 19571eccdf28Sschwarze * For other blocks and elements, including .Sh BODY, this is 19581eccdf28Sschwarze * done when allocating the node data structures, but for .Sh 19591eccdf28Sschwarze * BLOCK and HEAD, the section is still unknown at that time. 19601eccdf28Sschwarze */ 19611eccdf28Sschwarze 1962a2cff342Sschwarze mdoc->last->parent->sec = sec; 1963a2cff342Sschwarze mdoc->last->sec = sec; 1964a2cff342Sschwarze for (n = mdoc->last->child; n; n = n->next) 1965a2cff342Sschwarze n->sec = sec; 196620fa2881Sschwarze 196720fa2881Sschwarze /* We don't care about custom sections after this. */ 1968fccfce9dSschwarze 1969f73abda9Skristaps if (SEC_CUSTOM == sec) 1970f73abda9Skristaps return(1); 1971fccfce9dSschwarze 19726be99f77Sschwarze /* 197320fa2881Sschwarze * Check whether our non-custom section is being repeated or is 197420fa2881Sschwarze * out of order. 19756be99f77Sschwarze */ 1976f73abda9Skristaps 197720fa2881Sschwarze if (sec == mdoc->lastnamed) 197820fa2881Sschwarze mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_SECREP); 197920fa2881Sschwarze 198020fa2881Sschwarze if (sec < mdoc->lastnamed) 198120fa2881Sschwarze mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_SECOOO); 198220fa2881Sschwarze 198320fa2881Sschwarze /* Mark the last named section. */ 198420fa2881Sschwarze 198520fa2881Sschwarze mdoc->lastnamed = sec; 198620fa2881Sschwarze 198720fa2881Sschwarze /* Check particular section/manual conventions. */ 198820fa2881Sschwarze 198992c0ca7fSschwarze assert(mdoc->meta.msec); 199020fa2881Sschwarze 199120fa2881Sschwarze switch (sec) { 199220fa2881Sschwarze case (SEC_RETURN_VALUES): 199320fa2881Sschwarze /* FALLTHROUGH */ 199420fa2881Sschwarze case (SEC_ERRORS): 199520fa2881Sschwarze /* FALLTHROUGH */ 199620fa2881Sschwarze case (SEC_LIBRARY): 199792c0ca7fSschwarze if (*mdoc->meta.msec == '2') 1998f73abda9Skristaps break; 199992c0ca7fSschwarze if (*mdoc->meta.msec == '3') 200092c0ca7fSschwarze break; 200192c0ca7fSschwarze if (*mdoc->meta.msec == '9') 200292c0ca7fSschwarze break; 2003c645d318Sschwarze mandoc_msg(MANDOCERR_SECMSEC, mdoc->parse, 2004c645d318Sschwarze mdoc->last->line, mdoc->last->pos, buf); 200520fa2881Sschwarze break; 2006f73abda9Skristaps default: 2007f73abda9Skristaps break; 2008f73abda9Skristaps } 2009f73abda9Skristaps 2010f73abda9Skristaps return(1); 2011f73abda9Skristaps } 2012d39b9a9cSschwarze 201320fa2881Sschwarze static int 2014f6127a73Sschwarze post_ignpar(POST_ARGS) 2015f6127a73Sschwarze { 2016f6127a73Sschwarze struct mdoc_node *np; 2017f6127a73Sschwarze 2018f6127a73Sschwarze if (MDOC_BODY != mdoc->last->type) 2019f6127a73Sschwarze return(1); 2020f6127a73Sschwarze 2021f6127a73Sschwarze if (NULL != (np = mdoc->last->child)) 2022f6127a73Sschwarze if (MDOC_Pp == np->tok || MDOC_Lp == np->tok) { 2023f6127a73Sschwarze mdoc_nmsg(mdoc, np, MANDOCERR_IGNPAR); 2024f6127a73Sschwarze mdoc_node_delete(mdoc, np); 2025f6127a73Sschwarze } 2026f6127a73Sschwarze 2027f6127a73Sschwarze if (NULL != (np = mdoc->last->last)) 2028f6127a73Sschwarze if (MDOC_Pp == np->tok || MDOC_Lp == np->tok) { 2029f6127a73Sschwarze mdoc_nmsg(mdoc, np, MANDOCERR_IGNPAR); 2030f6127a73Sschwarze mdoc_node_delete(mdoc, np); 2031f6127a73Sschwarze } 2032f6127a73Sschwarze 2033f6127a73Sschwarze return(1); 2034f6127a73Sschwarze } 2035f6127a73Sschwarze 2036f6127a73Sschwarze static int 203720fa2881Sschwarze pre_par(PRE_ARGS) 2038d39b9a9cSschwarze { 2039d39b9a9cSschwarze 2040d39b9a9cSschwarze if (NULL == mdoc->last) 2041d39b9a9cSschwarze return(1); 2042f6127a73Sschwarze if (MDOC_ELEM != n->type && MDOC_BLOCK != n->type) 2043f6127a73Sschwarze return(1); 2044d39b9a9cSschwarze 204520fa2881Sschwarze /* 204620fa2881Sschwarze * Don't allow prior `Lp' or `Pp' prior to a paragraph-type 204720fa2881Sschwarze * block: `Lp', `Pp', or non-compact `Bd' or `Bl'. 204820fa2881Sschwarze */ 2049d39b9a9cSschwarze 2050e0dd4c9cSschwarze if (MDOC_Pp != mdoc->last->tok && 2051e0dd4c9cSschwarze MDOC_Lp != mdoc->last->tok && 2052e0dd4c9cSschwarze MDOC_br != mdoc->last->tok) 2053d39b9a9cSschwarze return(1); 20548c62fbf5Sschwarze if (MDOC_Bl == n->tok && n->norm->Bl.comp) 2055d39b9a9cSschwarze return(1); 20568c62fbf5Sschwarze if (MDOC_Bd == n->tok && n->norm->Bd.comp) 2057d39b9a9cSschwarze return(1); 20588c62fbf5Sschwarze if (MDOC_It == n->tok && n->parent->norm->Bl.comp) 2059f6127a73Sschwarze return(1); 2060d39b9a9cSschwarze 2061d39b9a9cSschwarze mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_IGNPAR); 2062d39b9a9cSschwarze mdoc_node_delete(mdoc, mdoc->last); 2063d39b9a9cSschwarze return(1); 2064d39b9a9cSschwarze } 206520fa2881Sschwarze 206620fa2881Sschwarze static int 2067e0dd4c9cSschwarze post_par(POST_ARGS) 2068e0dd4c9cSschwarze { 2069e0dd4c9cSschwarze 2070e0dd4c9cSschwarze if (MDOC_ELEM != mdoc->last->type && 2071e0dd4c9cSschwarze MDOC_BLOCK != mdoc->last->type) 2072e0dd4c9cSschwarze return(1); 2073e0dd4c9cSschwarze 2074e0dd4c9cSschwarze if (NULL == mdoc->last->prev) { 2075e0dd4c9cSschwarze if (MDOC_Sh != mdoc->last->parent->tok && 2076e0dd4c9cSschwarze MDOC_Ss != mdoc->last->parent->tok) 2077e0dd4c9cSschwarze return(1); 2078e0dd4c9cSschwarze } else { 2079e0dd4c9cSschwarze if (MDOC_Pp != mdoc->last->prev->tok && 2080e0dd4c9cSschwarze MDOC_Lp != mdoc->last->prev->tok && 2081e0dd4c9cSschwarze (MDOC_br != mdoc->last->tok || 2082e0dd4c9cSschwarze (MDOC_sp != mdoc->last->prev->tok && 2083e0dd4c9cSschwarze MDOC_br != mdoc->last->prev->tok))) 2084e0dd4c9cSschwarze return(1); 2085e0dd4c9cSschwarze } 2086e0dd4c9cSschwarze 2087e0dd4c9cSschwarze mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_IGNPAR); 2088e0dd4c9cSschwarze mdoc_node_delete(mdoc, mdoc->last); 2089e0dd4c9cSschwarze return(1); 2090e0dd4c9cSschwarze } 2091e0dd4c9cSschwarze 2092e0dd4c9cSschwarze static int 209320fa2881Sschwarze pre_literal(PRE_ARGS) 209420fa2881Sschwarze { 209520fa2881Sschwarze 209620fa2881Sschwarze if (MDOC_BODY != n->type) 209720fa2881Sschwarze return(1); 209820fa2881Sschwarze 209920fa2881Sschwarze /* 210020fa2881Sschwarze * The `Dl' (note "el" not "one") and `Bd -literal' and `Bd 210120fa2881Sschwarze * -unfilled' macros set MDOC_LITERAL on entrance to the body. 210220fa2881Sschwarze */ 210320fa2881Sschwarze 210420fa2881Sschwarze switch (n->tok) { 210520fa2881Sschwarze case (MDOC_Dl): 210620fa2881Sschwarze mdoc->flags |= MDOC_LITERAL; 210720fa2881Sschwarze break; 210820fa2881Sschwarze case (MDOC_Bd): 21098c62fbf5Sschwarze if (DISP_literal == n->norm->Bd.type) 211020fa2881Sschwarze mdoc->flags |= MDOC_LITERAL; 21118c62fbf5Sschwarze if (DISP_unfilled == n->norm->Bd.type) 211220fa2881Sschwarze mdoc->flags |= MDOC_LITERAL; 211320fa2881Sschwarze break; 211420fa2881Sschwarze default: 211520fa2881Sschwarze abort(); 211620fa2881Sschwarze /* NOTREACHED */ 211720fa2881Sschwarze } 211820fa2881Sschwarze 211920fa2881Sschwarze return(1); 212020fa2881Sschwarze } 212120fa2881Sschwarze 212220fa2881Sschwarze static int 212320fa2881Sschwarze post_dd(POST_ARGS) 212420fa2881Sschwarze { 212520fa2881Sschwarze char buf[DATESIZE]; 212620fa2881Sschwarze struct mdoc_node *n; 212704e980cbSschwarze int c; 212820fa2881Sschwarze 2129b058e777Sschwarze if (mdoc->meta.date) 2130b058e777Sschwarze free(mdoc->meta.date); 213120fa2881Sschwarze 2132b058e777Sschwarze n = mdoc->last; 2133b058e777Sschwarze if (NULL == n->child || '\0' == n->child->string[0]) { 2134a35fc07aSschwarze mdoc->meta.date = mandoc_normdate 2135a35fc07aSschwarze (mdoc->parse, NULL, n->line, n->pos); 213620fa2881Sschwarze return(1); 213720fa2881Sschwarze } 213820fa2881Sschwarze 213904e980cbSschwarze buf[0] = '\0'; 214004e980cbSschwarze if (-1 == (c = concat(buf, n->child, DATESIZE))) { 214104e980cbSschwarze mdoc_nmsg(mdoc, n->child, MANDOCERR_MEM); 214220fa2881Sschwarze return(0); 214304e980cbSschwarze } 214420fa2881Sschwarze 214504e980cbSschwarze assert(c); 2146a35fc07aSschwarze mdoc->meta.date = mandoc_normdate 2147a35fc07aSschwarze (mdoc->parse, buf, n->line, n->pos); 214820fa2881Sschwarze 214920fa2881Sschwarze return(1); 215020fa2881Sschwarze } 215120fa2881Sschwarze 215220fa2881Sschwarze static int 215320fa2881Sschwarze post_dt(POST_ARGS) 215420fa2881Sschwarze { 215520fa2881Sschwarze struct mdoc_node *nn, *n; 215620fa2881Sschwarze const char *cp; 215720fa2881Sschwarze char *p; 215820fa2881Sschwarze 215920fa2881Sschwarze n = mdoc->last; 216020fa2881Sschwarze 216120fa2881Sschwarze if (mdoc->meta.title) 216220fa2881Sschwarze free(mdoc->meta.title); 216320fa2881Sschwarze if (mdoc->meta.vol) 216420fa2881Sschwarze free(mdoc->meta.vol); 216520fa2881Sschwarze if (mdoc->meta.arch) 216620fa2881Sschwarze free(mdoc->meta.arch); 216720fa2881Sschwarze 216820fa2881Sschwarze mdoc->meta.title = mdoc->meta.vol = mdoc->meta.arch = NULL; 216920fa2881Sschwarze 217020fa2881Sschwarze /* First make all characters uppercase. */ 217120fa2881Sschwarze 217220fa2881Sschwarze if (NULL != (nn = n->child)) 217320fa2881Sschwarze for (p = nn->string; *p; p++) { 217404e980cbSschwarze if (toupper((unsigned char)*p) == *p) 217520fa2881Sschwarze continue; 217620fa2881Sschwarze 217720fa2881Sschwarze /* 217820fa2881Sschwarze * FIXME: don't be lazy: have this make all 217920fa2881Sschwarze * characters be uppercase and just warn once. 218020fa2881Sschwarze */ 218120fa2881Sschwarze mdoc_nmsg(mdoc, nn, MANDOCERR_UPPERCASE); 218220fa2881Sschwarze break; 218320fa2881Sschwarze } 218420fa2881Sschwarze 218520fa2881Sschwarze /* Handles: `.Dt' 218620fa2881Sschwarze * --> title = unknown, volume = local, msec = 0, arch = NULL 218720fa2881Sschwarze */ 218820fa2881Sschwarze 218920fa2881Sschwarze if (NULL == (nn = n->child)) { 219020fa2881Sschwarze /* XXX: make these macro values. */ 219120fa2881Sschwarze /* FIXME: warn about missing values. */ 219220fa2881Sschwarze mdoc->meta.title = mandoc_strdup("UNKNOWN"); 219320fa2881Sschwarze mdoc->meta.vol = mandoc_strdup("LOCAL"); 219420fa2881Sschwarze mdoc->meta.msec = mandoc_strdup("1"); 219520fa2881Sschwarze return(1); 219620fa2881Sschwarze } 219720fa2881Sschwarze 219820fa2881Sschwarze /* Handles: `.Dt TITLE' 219920fa2881Sschwarze * --> title = TITLE, volume = local, msec = 0, arch = NULL 220020fa2881Sschwarze */ 220120fa2881Sschwarze 220220fa2881Sschwarze mdoc->meta.title = mandoc_strdup 220320fa2881Sschwarze ('\0' == nn->string[0] ? "UNKNOWN" : nn->string); 220420fa2881Sschwarze 220520fa2881Sschwarze if (NULL == (nn = nn->next)) { 220620fa2881Sschwarze /* FIXME: warn about missing msec. */ 220720fa2881Sschwarze /* XXX: make this a macro value. */ 220820fa2881Sschwarze mdoc->meta.vol = mandoc_strdup("LOCAL"); 220920fa2881Sschwarze mdoc->meta.msec = mandoc_strdup("1"); 221020fa2881Sschwarze return(1); 221120fa2881Sschwarze } 221220fa2881Sschwarze 221320fa2881Sschwarze /* Handles: `.Dt TITLE SEC' 221420fa2881Sschwarze * --> title = TITLE, volume = SEC is msec ? 221520fa2881Sschwarze * format(msec) : SEC, 221620fa2881Sschwarze * msec = SEC is msec ? atoi(msec) : 0, 221720fa2881Sschwarze * arch = NULL 221820fa2881Sschwarze */ 221920fa2881Sschwarze 222088ec69e3Sschwarze cp = mandoc_a2msec(nn->string); 222120fa2881Sschwarze if (cp) { 222220fa2881Sschwarze mdoc->meta.vol = mandoc_strdup(cp); 222320fa2881Sschwarze mdoc->meta.msec = mandoc_strdup(nn->string); 222420fa2881Sschwarze } else { 222520fa2881Sschwarze mdoc_nmsg(mdoc, n, MANDOCERR_BADMSEC); 222620fa2881Sschwarze mdoc->meta.vol = mandoc_strdup(nn->string); 222720fa2881Sschwarze mdoc->meta.msec = mandoc_strdup(nn->string); 222820fa2881Sschwarze } 222920fa2881Sschwarze 223020fa2881Sschwarze if (NULL == (nn = nn->next)) 223120fa2881Sschwarze return(1); 223220fa2881Sschwarze 223320fa2881Sschwarze /* Handles: `.Dt TITLE SEC VOL' 223420fa2881Sschwarze * --> title = TITLE, volume = VOL is vol ? 223520fa2881Sschwarze * format(VOL) : 223620fa2881Sschwarze * VOL is arch ? format(arch) : 223720fa2881Sschwarze * VOL 223820fa2881Sschwarze */ 223920fa2881Sschwarze 224020fa2881Sschwarze cp = mdoc_a2vol(nn->string); 224120fa2881Sschwarze if (cp) { 224220fa2881Sschwarze free(mdoc->meta.vol); 224320fa2881Sschwarze mdoc->meta.vol = mandoc_strdup(cp); 224420fa2881Sschwarze } else { 224520fa2881Sschwarze cp = mdoc_a2arch(nn->string); 224620fa2881Sschwarze if (NULL == cp) { 224755818fdcSschwarze mdoc_nmsg(mdoc, nn, MANDOCERR_BADVOLARCH); 224820fa2881Sschwarze free(mdoc->meta.vol); 224920fa2881Sschwarze mdoc->meta.vol = mandoc_strdup(nn->string); 225020fa2881Sschwarze } else 225120fa2881Sschwarze mdoc->meta.arch = mandoc_strdup(cp); 225220fa2881Sschwarze } 225320fa2881Sschwarze 225420fa2881Sschwarze /* Ignore any subsequent parameters... */ 225520fa2881Sschwarze /* FIXME: warn about subsequent parameters. */ 225620fa2881Sschwarze 225720fa2881Sschwarze return(1); 225820fa2881Sschwarze } 225920fa2881Sschwarze 226020fa2881Sschwarze static int 226120fa2881Sschwarze post_prol(POST_ARGS) 226220fa2881Sschwarze { 226320fa2881Sschwarze /* 226420fa2881Sschwarze * Remove prologue macros from the document after they're 226520fa2881Sschwarze * processed. The final document uses mdoc_meta for these 226620fa2881Sschwarze * values and discards the originals. 226720fa2881Sschwarze */ 226820fa2881Sschwarze 226920fa2881Sschwarze mdoc_node_delete(mdoc, mdoc->last); 227020fa2881Sschwarze if (mdoc->meta.title && mdoc->meta.date && mdoc->meta.os) 227120fa2881Sschwarze mdoc->flags |= MDOC_PBODY; 227220fa2881Sschwarze 227320fa2881Sschwarze return(1); 227420fa2881Sschwarze } 227520fa2881Sschwarze 227620fa2881Sschwarze static int 2277992063deSschwarze post_bx(POST_ARGS) 2278992063deSschwarze { 2279992063deSschwarze struct mdoc_node *n; 2280992063deSschwarze 2281992063deSschwarze /* 2282992063deSschwarze * Make `Bx's second argument always start with an uppercase 2283992063deSschwarze * letter. Groff checks if it's an "accepted" term, but we just 2284992063deSschwarze * uppercase blindly. 2285992063deSschwarze */ 2286992063deSschwarze 2287992063deSschwarze n = mdoc->last->child; 2288992063deSschwarze if (n && NULL != (n = n->next)) 228919a69263Sschwarze *n->string = (char)toupper 229019a69263Sschwarze ((unsigned char)*n->string); 2291992063deSschwarze 2292992063deSschwarze return(1); 2293992063deSschwarze } 2294992063deSschwarze 2295992063deSschwarze static int 229620fa2881Sschwarze post_os(POST_ARGS) 229720fa2881Sschwarze { 229820fa2881Sschwarze struct mdoc_node *n; 229920fa2881Sschwarze char buf[BUFSIZ]; 230004e980cbSschwarze int c; 230120fa2881Sschwarze #ifndef OSNAME 230220fa2881Sschwarze struct utsname utsname; 230320fa2881Sschwarze #endif 230420fa2881Sschwarze 230520fa2881Sschwarze n = mdoc->last; 230620fa2881Sschwarze 230720fa2881Sschwarze /* 2308353fa9ecSschwarze * Set the operating system by way of the `Os' macro. 2309353fa9ecSschwarze * The order of precedence is: 2310353fa9ecSschwarze * 1. the argument of the `Os' macro, unless empty 2311353fa9ecSschwarze * 2. the -Ios=foo command line argument, if provided 2312353fa9ecSschwarze * 3. -DOSNAME="\"foo\"", if provided during compilation 2313353fa9ecSschwarze * 4. "sysname release" from uname(3) 231420fa2881Sschwarze */ 231520fa2881Sschwarze 231620fa2881Sschwarze free(mdoc->meta.os); 231720fa2881Sschwarze 231804e980cbSschwarze buf[0] = '\0'; 231904e980cbSschwarze if (-1 == (c = concat(buf, n->child, BUFSIZ))) { 232004e980cbSschwarze mdoc_nmsg(mdoc, n->child, MANDOCERR_MEM); 232120fa2881Sschwarze return(0); 232204e980cbSschwarze } 232304e980cbSschwarze 232404e980cbSschwarze assert(c); 232520fa2881Sschwarze 232620fa2881Sschwarze if ('\0' == buf[0]) { 2327353fa9ecSschwarze if (mdoc->defos) { 2328353fa9ecSschwarze mdoc->meta.os = mandoc_strdup(mdoc->defos); 2329353fa9ecSschwarze return(1); 2330353fa9ecSschwarze } 233120fa2881Sschwarze #ifdef OSNAME 233220fa2881Sschwarze if (strlcat(buf, OSNAME, BUFSIZ) >= BUFSIZ) { 233320fa2881Sschwarze mdoc_nmsg(mdoc, n, MANDOCERR_MEM); 233420fa2881Sschwarze return(0); 233520fa2881Sschwarze } 233620fa2881Sschwarze #else /*!OSNAME */ 2337a35fc07aSschwarze if (-1 == uname(&utsname)) { 233820fa2881Sschwarze mdoc_nmsg(mdoc, n, MANDOCERR_UNAME); 233920fa2881Sschwarze mdoc->meta.os = mandoc_strdup("UNKNOWN"); 234020fa2881Sschwarze return(post_prol(mdoc)); 234120fa2881Sschwarze } 234220fa2881Sschwarze 234320fa2881Sschwarze if (strlcat(buf, utsname.sysname, BUFSIZ) >= BUFSIZ) { 234420fa2881Sschwarze mdoc_nmsg(mdoc, n, MANDOCERR_MEM); 234520fa2881Sschwarze return(0); 234620fa2881Sschwarze } 234720fa2881Sschwarze if (strlcat(buf, " ", BUFSIZ) >= BUFSIZ) { 234820fa2881Sschwarze mdoc_nmsg(mdoc, n, MANDOCERR_MEM); 234920fa2881Sschwarze return(0); 235020fa2881Sschwarze } 235120fa2881Sschwarze if (strlcat(buf, utsname.release, BUFSIZ) >= BUFSIZ) { 235220fa2881Sschwarze mdoc_nmsg(mdoc, n, MANDOCERR_MEM); 235320fa2881Sschwarze return(0); 235420fa2881Sschwarze } 235520fa2881Sschwarze #endif /*!OSNAME*/ 235620fa2881Sschwarze } 235720fa2881Sschwarze 235820fa2881Sschwarze mdoc->meta.os = mandoc_strdup(buf); 235920fa2881Sschwarze return(1); 236020fa2881Sschwarze } 236120fa2881Sschwarze 236220fa2881Sschwarze static int 236320fa2881Sschwarze post_std(POST_ARGS) 236420fa2881Sschwarze { 236520fa2881Sschwarze struct mdoc_node *nn, *n; 236620fa2881Sschwarze 236720fa2881Sschwarze n = mdoc->last; 236820fa2881Sschwarze 236920fa2881Sschwarze /* 237020fa2881Sschwarze * Macros accepting `-std' as an argument have the name of the 237120fa2881Sschwarze * current document (`Nm') filled in as the argument if it's not 237220fa2881Sschwarze * provided. 237320fa2881Sschwarze */ 237420fa2881Sschwarze 237520fa2881Sschwarze if (n->child) 237620fa2881Sschwarze return(1); 237720fa2881Sschwarze 237820fa2881Sschwarze if (NULL == mdoc->meta.name) 237920fa2881Sschwarze return(1); 238020fa2881Sschwarze 238120fa2881Sschwarze nn = n; 238220fa2881Sschwarze mdoc->next = MDOC_NEXT_CHILD; 238320fa2881Sschwarze 238420fa2881Sschwarze if ( ! mdoc_word_alloc(mdoc, n->line, n->pos, mdoc->meta.name)) 238520fa2881Sschwarze return(0); 238620fa2881Sschwarze 238720fa2881Sschwarze mdoc->last = nn; 238820fa2881Sschwarze return(1); 238920fa2881Sschwarze } 239020fa2881Sschwarze 239104e980cbSschwarze /* 239204e980cbSschwarze * Concatenate a node, stopping at the first non-text. 239304e980cbSschwarze * Concatenation is separated by a single whitespace. 239404e980cbSschwarze * Returns -1 on fatal (string overrun) error, 0 if child nodes were 239504e980cbSschwarze * encountered, 1 otherwise. 239604e980cbSschwarze */ 239720fa2881Sschwarze static int 239804e980cbSschwarze concat(char *p, const struct mdoc_node *n, size_t sz) 239920fa2881Sschwarze { 240020fa2881Sschwarze 240104e980cbSschwarze for ( ; NULL != n; n = n->next) { 240204e980cbSschwarze if (MDOC_TEXT != n->type) 240320fa2881Sschwarze return(0); 240404e980cbSschwarze if ('\0' != p[0] && strlcat(p, " ", sz) >= sz) 240504e980cbSschwarze return(-1); 240604e980cbSschwarze if (strlcat(p, n->string, sz) >= sz) 240704e980cbSschwarze return(-1); 240804e980cbSschwarze concat(p, n->child, sz); 240920fa2881Sschwarze } 241020fa2881Sschwarze 241120fa2881Sschwarze return(1); 241220fa2881Sschwarze } 241320fa2881Sschwarze 241419a69263Sschwarze static enum mdoc_sec 241519a69263Sschwarze a2sec(const char *p) 241619a69263Sschwarze { 241719a69263Sschwarze int i; 241819a69263Sschwarze 241919a69263Sschwarze for (i = 0; i < (int)SEC__MAX; i++) 242019a69263Sschwarze if (secnames[i] && 0 == strcmp(p, secnames[i])) 242119a69263Sschwarze return((enum mdoc_sec)i); 242219a69263Sschwarze 242319a69263Sschwarze return(SEC_CUSTOM); 242419a69263Sschwarze } 242519a69263Sschwarze 242619a69263Sschwarze static size_t 242719a69263Sschwarze macro2len(enum mdoct macro) 242819a69263Sschwarze { 242919a69263Sschwarze 243019a69263Sschwarze switch (macro) { 243119a69263Sschwarze case(MDOC_Ad): 243219a69263Sschwarze return(12); 243319a69263Sschwarze case(MDOC_Ao): 243419a69263Sschwarze return(12); 243519a69263Sschwarze case(MDOC_An): 243619a69263Sschwarze return(12); 243719a69263Sschwarze case(MDOC_Aq): 243819a69263Sschwarze return(12); 243919a69263Sschwarze case(MDOC_Ar): 244019a69263Sschwarze return(12); 244119a69263Sschwarze case(MDOC_Bo): 244219a69263Sschwarze return(12); 244319a69263Sschwarze case(MDOC_Bq): 244419a69263Sschwarze return(12); 244519a69263Sschwarze case(MDOC_Cd): 244619a69263Sschwarze return(12); 244719a69263Sschwarze case(MDOC_Cm): 244819a69263Sschwarze return(10); 244919a69263Sschwarze case(MDOC_Do): 245019a69263Sschwarze return(10); 245119a69263Sschwarze case(MDOC_Dq): 245219a69263Sschwarze return(12); 245319a69263Sschwarze case(MDOC_Dv): 245419a69263Sschwarze return(12); 245519a69263Sschwarze case(MDOC_Eo): 245619a69263Sschwarze return(12); 245719a69263Sschwarze case(MDOC_Em): 245819a69263Sschwarze return(10); 245919a69263Sschwarze case(MDOC_Er): 246019a69263Sschwarze return(17); 246119a69263Sschwarze case(MDOC_Ev): 246219a69263Sschwarze return(15); 246319a69263Sschwarze case(MDOC_Fa): 246419a69263Sschwarze return(12); 246519a69263Sschwarze case(MDOC_Fl): 246619a69263Sschwarze return(10); 246719a69263Sschwarze case(MDOC_Fo): 246819a69263Sschwarze return(16); 246919a69263Sschwarze case(MDOC_Fn): 247019a69263Sschwarze return(16); 247119a69263Sschwarze case(MDOC_Ic): 247219a69263Sschwarze return(10); 247319a69263Sschwarze case(MDOC_Li): 247419a69263Sschwarze return(16); 247519a69263Sschwarze case(MDOC_Ms): 247619a69263Sschwarze return(6); 247719a69263Sschwarze case(MDOC_Nm): 247819a69263Sschwarze return(10); 247919a69263Sschwarze case(MDOC_No): 248019a69263Sschwarze return(12); 248119a69263Sschwarze case(MDOC_Oo): 248219a69263Sschwarze return(10); 248319a69263Sschwarze case(MDOC_Op): 248419a69263Sschwarze return(14); 248519a69263Sschwarze case(MDOC_Pa): 248619a69263Sschwarze return(32); 248719a69263Sschwarze case(MDOC_Pf): 248819a69263Sschwarze return(12); 248919a69263Sschwarze case(MDOC_Po): 249019a69263Sschwarze return(12); 249119a69263Sschwarze case(MDOC_Pq): 249219a69263Sschwarze return(12); 249319a69263Sschwarze case(MDOC_Ql): 249419a69263Sschwarze return(16); 249519a69263Sschwarze case(MDOC_Qo): 249619a69263Sschwarze return(12); 249719a69263Sschwarze case(MDOC_So): 249819a69263Sschwarze return(12); 249919a69263Sschwarze case(MDOC_Sq): 250019a69263Sschwarze return(12); 250119a69263Sschwarze case(MDOC_Sy): 250219a69263Sschwarze return(6); 250319a69263Sschwarze case(MDOC_Sx): 250419a69263Sschwarze return(16); 250519a69263Sschwarze case(MDOC_Tn): 250619a69263Sschwarze return(10); 250719a69263Sschwarze case(MDOC_Va): 250819a69263Sschwarze return(12); 250919a69263Sschwarze case(MDOC_Vt): 251019a69263Sschwarze return(12); 251119a69263Sschwarze case(MDOC_Xr): 251219a69263Sschwarze return(10); 251319a69263Sschwarze default: 251419a69263Sschwarze break; 251519a69263Sschwarze }; 251619a69263Sschwarze return(0); 251719a69263Sschwarze } 2518