1*f5174743Sschwarze /* $Id: mdoc_validate.c,v 1.155 2014/08/08 15:42:39 schwarze Exp $ */ 2f73abda9Skristaps /* 322972b14Sschwarze * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv> 4231c7061Sschwarze * Copyright (c) 2010-2014 Ingo Schwarze <schwarze@openbsd.org> 539c2a57eSschwarze * Copyright (c) 2010 Joerg Sonnenberger <joerg@netbsd.org> 6f73abda9Skristaps * 7f73abda9Skristaps * Permission to use, copy, modify, and distribute this software for any 8a6464425Sschwarze * purpose with or without fee is hereby granted, provided that the above 9a6464425Sschwarze * copyright notice and this permission notice appear in all copies. 10f73abda9Skristaps * 11a6464425Sschwarze * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12a6464425Sschwarze * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13a6464425Sschwarze * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14a6464425Sschwarze * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15a6464425Sschwarze * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16a6464425Sschwarze * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17a6464425Sschwarze * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18f73abda9Skristaps */ 1920fa2881Sschwarze #ifndef OSNAME 2020fa2881Sschwarze #include <sys/utsname.h> 2120fa2881Sschwarze #endif 2220fa2881Sschwarze 23f73abda9Skristaps #include <sys/types.h> 24f73abda9Skristaps 25f73abda9Skristaps #include <assert.h> 26f73abda9Skristaps #include <ctype.h> 27d92dc4efSschwarze #include <limits.h> 283216dddfSschwarze #include <stdio.h> 29f73abda9Skristaps #include <stdlib.h> 30f73abda9Skristaps #include <string.h> 3120fa2881Sschwarze #include <time.h> 32f73abda9Skristaps 33a35fc07aSschwarze #include "mdoc.h" 346e03d529Sschwarze #include "mandoc.h" 354f4f7972Sschwarze #include "mandoc_aux.h" 36f73abda9Skristaps #include "libmdoc.h" 37f6854d5cSschwarze #include "libmandoc.h" 38f73abda9Skristaps 39f73abda9Skristaps /* FIXME: .Bl -diag can't have non-text children in HEAD. */ 40f73abda9Skristaps 416093755cSschwarze #define PRE_ARGS struct mdoc *mdoc, struct mdoc_node *n 42f73abda9Skristaps #define POST_ARGS struct mdoc *mdoc 43f73abda9Skristaps 447c2be9f8Sschwarze enum check_ineq { 457c2be9f8Sschwarze CHECK_LT, 467c2be9f8Sschwarze CHECK_GT, 477c2be9f8Sschwarze CHECK_EQ 487c2be9f8Sschwarze }; 497c2be9f8Sschwarze 507c2be9f8Sschwarze enum check_lvl { 517c2be9f8Sschwarze CHECK_WARN, 527c2be9f8Sschwarze CHECK_ERROR, 537c2be9f8Sschwarze }; 547c2be9f8Sschwarze 55f73abda9Skristaps typedef int (*v_pre)(PRE_ARGS); 56f73abda9Skristaps typedef int (*v_post)(POST_ARGS); 57f73abda9Skristaps 58f73abda9Skristaps struct valids { 59f73abda9Skristaps v_pre *pre; 60f73abda9Skristaps v_post *post; 61f73abda9Skristaps }; 62f73abda9Skristaps 637c2be9f8Sschwarze static int check_count(struct mdoc *, enum mdoc_type, 647c2be9f8Sschwarze enum check_lvl, enum check_ineq, int); 6520fa2881Sschwarze static void check_text(struct mdoc *, int, int, char *); 6620fa2881Sschwarze static void check_argv(struct mdoc *, 6731e23753Sschwarze struct mdoc_node *, struct mdoc_argv *); 6820fa2881Sschwarze static void check_args(struct mdoc *, struct mdoc_node *); 6919a69263Sschwarze static enum mdoc_sec a2sec(const char *); 7019a69263Sschwarze static size_t macro2len(enum mdoct); 7167c719adSschwarze 727c2be9f8Sschwarze static int ebool(POST_ARGS); 7367c719adSschwarze static int berr_ge1(POST_ARGS); 7467c719adSschwarze static int bwarn_ge1(POST_ARGS); 75da272f5eSschwarze static int ewarn_eq0(POST_ARGS); 76bb648afaSschwarze static int ewarn_eq1(POST_ARGS); 7767c719adSschwarze static int ewarn_ge1(POST_ARGS); 78bb648afaSschwarze static int ewarn_le1(POST_ARGS); 79b16e7ddfSschwarze static int hwarn_eq0(POST_ARGS); 807c2be9f8Sschwarze static int hwarn_eq1(POST_ARGS); 81bb648afaSschwarze static int hwarn_ge1(POST_ARGS); 8267c719adSschwarze 8367c719adSschwarze static int post_an(POST_ARGS); 8467c719adSschwarze static int post_at(POST_ARGS); 8567c719adSschwarze static int post_bf(POST_ARGS); 8667c719adSschwarze static int post_bl(POST_ARGS); 8720fa2881Sschwarze static int post_bl_block(POST_ARGS); 8820fa2881Sschwarze static int post_bl_block_width(POST_ARGS); 8920fa2881Sschwarze static int post_bl_block_tag(POST_ARGS); 9067c719adSschwarze static int post_bl_head(POST_ARGS); 91992063deSschwarze static int post_bx(POST_ARGS); 924039b21cSschwarze static int post_defaults(POST_ARGS); 9320fa2881Sschwarze static int post_dd(POST_ARGS); 946093755cSschwarze static int post_dt(POST_ARGS); 95551cd4a8Sschwarze static int post_en(POST_ARGS); 96551cd4a8Sschwarze static int post_es(POST_ARGS); 9720fa2881Sschwarze static int post_eoln(POST_ARGS); 98e214f641Sschwarze static int post_ex(POST_ARGS); 994039b21cSschwarze static int post_hyph(POST_ARGS); 1004039b21cSschwarze static int post_ignpar(POST_ARGS); 10167c719adSschwarze static int post_it(POST_ARGS); 10267c719adSschwarze static int post_lb(POST_ARGS); 1034039b21cSschwarze static int post_literal(POST_ARGS); 10467c719adSschwarze static int post_nm(POST_ARGS); 105af216717Sschwarze static int post_ns(POST_ARGS); 10620fa2881Sschwarze static int post_os(POST_ARGS); 107e0dd4c9cSschwarze static int post_par(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); 1158521b0bcSschwarze static int post_vt(POST_ARGS); 116f73abda9Skristaps static int pre_an(PRE_ARGS); 117f73abda9Skristaps static int pre_bd(PRE_ARGS); 118f73abda9Skristaps static int pre_bl(PRE_ARGS); 119f73abda9Skristaps static int pre_dd(PRE_ARGS); 120f73abda9Skristaps static int pre_display(PRE_ARGS); 121f73abda9Skristaps static int pre_dt(PRE_ARGS); 12220fa2881Sschwarze static int pre_literal(PRE_ARGS); 123551cd4a8Sschwarze static int pre_obsolete(PRE_ARGS); 124f73abda9Skristaps static int pre_os(PRE_ARGS); 12520fa2881Sschwarze static int pre_par(PRE_ARGS); 12620fa2881Sschwarze static int pre_std(PRE_ARGS); 127f73abda9Skristaps 12867c719adSschwarze static v_post posts_an[] = { post_an, NULL }; 12920fa2881Sschwarze static v_post posts_at[] = { post_at, post_defaults, NULL }; 13020fa2881Sschwarze static v_post posts_bd[] = { post_literal, hwarn_eq0, bwarn_ge1, NULL }; 131ecb10c32Sschwarze static v_post posts_bf[] = { post_bf, NULL }; 13220fa2881Sschwarze static v_post posts_bk[] = { hwarn_eq0, bwarn_ge1, NULL }; 13367c719adSschwarze static v_post posts_bl[] = { bwarn_ge1, post_bl, NULL }; 134992063deSschwarze static v_post posts_bx[] = { post_bx, NULL }; 135bb648afaSschwarze static v_post posts_bool[] = { ebool, NULL }; 136b31af00dSschwarze static v_post posts_eoln[] = { post_eoln, NULL }; 13720fa2881Sschwarze static v_post posts_defaults[] = { post_defaults, NULL }; 1384039b21cSschwarze static v_post posts_d1[] = { bwarn_ge1, post_hyph, NULL }; 139b058e777Sschwarze static v_post posts_dd[] = { post_dd, post_prol, NULL }; 140bb648afaSschwarze static v_post posts_dl[] = { post_literal, bwarn_ge1, NULL }; 14120fa2881Sschwarze static v_post posts_dt[] = { post_dt, post_prol, NULL }; 142551cd4a8Sschwarze static v_post posts_en[] = { post_en, NULL }; 143551cd4a8Sschwarze static v_post posts_es[] = { post_es, NULL }; 144e214f641Sschwarze static v_post posts_ex[] = { post_ex, NULL }; 14567c719adSschwarze static v_post posts_fo[] = { hwarn_eq1, bwarn_ge1, NULL }; 1464039b21cSschwarze static v_post posts_hyph[] = { post_hyph, NULL }; 1474039b21cSschwarze static v_post posts_hyphtext[] = { ewarn_ge1, post_hyph, NULL }; 14867c719adSschwarze static v_post posts_it[] = { post_it, NULL }; 149bb648afaSschwarze static v_post posts_lb[] = { post_lb, NULL }; 1504039b21cSschwarze static v_post posts_nd[] = { berr_ge1, post_hyph, NULL }; 15167c719adSschwarze static v_post posts_nm[] = { post_nm, NULL }; 152da272f5eSschwarze static v_post posts_notext[] = { ewarn_eq0, NULL }; 153af216717Sschwarze static v_post posts_ns[] = { post_ns, NULL }; 15420fa2881Sschwarze static v_post posts_os[] = { post_os, post_prol, NULL }; 155e0dd4c9cSschwarze static v_post posts_pp[] = { post_par, ewarn_eq0, NULL }; 156bb648afaSschwarze static v_post posts_rs[] = { post_rs, NULL }; 1574039b21cSschwarze static v_post posts_sh[] = { post_ignpar,hwarn_ge1,post_sh,post_hyph,NULL }; 158e0dd4c9cSschwarze static v_post posts_sp[] = { post_par, ewarn_le1, NULL }; 1594039b21cSschwarze static v_post posts_ss[] = { post_ignpar, hwarn_ge1, post_hyph, NULL }; 160bb648afaSschwarze static v_post posts_st[] = { post_st, NULL }; 161e7a93ef3Sschwarze static v_post posts_text[] = { ewarn_ge1, NULL }; 162bb648afaSschwarze static v_post posts_text1[] = { ewarn_eq1, NULL }; 1638521b0bcSschwarze static v_post posts_vt[] = { post_vt, NULL }; 164f73abda9Skristaps static v_pre pres_an[] = { pre_an, NULL }; 16520fa2881Sschwarze static v_pre pres_bd[] = { pre_display, pre_bd, pre_literal, pre_par, NULL }; 16620fa2881Sschwarze static v_pre pres_bl[] = { pre_bl, pre_par, NULL }; 167f73abda9Skristaps static v_pre pres_d1[] = { pre_display, NULL }; 16820fa2881Sschwarze static v_pre pres_dl[] = { pre_literal, pre_display, NULL }; 16967c719adSschwarze static v_pre pres_dd[] = { pre_dd, NULL }; 1706be99f77Sschwarze static v_pre pres_dt[] = { pre_dt, NULL }; 1718d5916b5Sschwarze static v_pre pres_it[] = { pre_par, NULL }; 172551cd4a8Sschwarze static v_pre pres_obsolete[] = { pre_obsolete, NULL }; 1736be99f77Sschwarze static v_pre pres_os[] = { pre_os, NULL }; 17420fa2881Sschwarze static v_pre pres_pp[] = { pre_par, NULL }; 17520fa2881Sschwarze static v_pre pres_std[] = { pre_std, NULL }; 176f73abda9Skristaps 17719a69263Sschwarze static const struct valids mdoc_valids[MDOC_MAX] = { 178099cfa7eSschwarze { NULL, NULL }, /* Ap */ 17920fa2881Sschwarze { pres_dd, posts_dd }, /* Dd */ 1806093755cSschwarze { pres_dt, posts_dt }, /* Dt */ 18120fa2881Sschwarze { pres_os, posts_os }, /* Os */ 1828d5916b5Sschwarze { NULL, posts_sh }, /* Sh */ 1838d5916b5Sschwarze { NULL, posts_ss }, /* Ss */ 184e0dd4c9cSschwarze { pres_pp, posts_pp }, /* Pp */ 1854039b21cSschwarze { pres_d1, posts_d1 }, /* D1 */ 18620fa2881Sschwarze { pres_dl, posts_dl }, /* Dl */ 18720fa2881Sschwarze { pres_bd, posts_bd }, /* Bd */ 188f73abda9Skristaps { NULL, NULL }, /* Ed */ 189f73abda9Skristaps { pres_bl, posts_bl }, /* Bl */ 190f73abda9Skristaps { NULL, NULL }, /* El */ 191f73abda9Skristaps { pres_it, posts_it }, /* It */ 192e7a93ef3Sschwarze { NULL, NULL }, /* Ad */ 193f73abda9Skristaps { pres_an, posts_an }, /* An */ 19420fa2881Sschwarze { NULL, posts_defaults }, /* Ar */ 195e7a93ef3Sschwarze { NULL, NULL }, /* Cd */ 196f73abda9Skristaps { NULL, NULL }, /* Cm */ 197f73abda9Skristaps { NULL, NULL }, /* Dv */ 1984039b21cSschwarze { NULL, NULL }, /* Er */ 199f73abda9Skristaps { NULL, NULL }, /* Ev */ 200e214f641Sschwarze { pres_std, posts_ex }, /* Ex */ 201f73abda9Skristaps { NULL, NULL }, /* Fa */ 2024039b21cSschwarze { NULL, posts_text }, /* Fd */ 203f73abda9Skristaps { NULL, NULL }, /* Fl */ 204e7a93ef3Sschwarze { NULL, NULL }, /* Fn */ 205e7a93ef3Sschwarze { NULL, NULL }, /* Ft */ 206e7a93ef3Sschwarze { NULL, NULL }, /* Ic */ 207b822ca0dSschwarze { NULL, posts_text1 }, /* In */ 20820fa2881Sschwarze { NULL, posts_defaults }, /* Li */ 2094602e85cSschwarze { NULL, posts_nd }, /* Nd */ 210f73abda9Skristaps { NULL, posts_nm }, /* Nm */ 211bca76d61Sschwarze { NULL, NULL }, /* Op */ 212551cd4a8Sschwarze { pres_obsolete, NULL }, /* Ot */ 21320fa2881Sschwarze { NULL, posts_defaults }, /* Pa */ 214e214f641Sschwarze { pres_std, NULL }, /* Rv */ 215f73abda9Skristaps { NULL, posts_st }, /* St */ 216f73abda9Skristaps { NULL, NULL }, /* Va */ 2178521b0bcSschwarze { NULL, posts_vt }, /* Vt */ 218e7a93ef3Sschwarze { NULL, posts_text }, /* Xr */ 219f73abda9Skristaps { NULL, posts_text }, /* %A */ 2204039b21cSschwarze { NULL, posts_hyphtext }, /* %B */ /* FIXME: can be used outside Rs/Re. */ 221b058e777Sschwarze { NULL, posts_text }, /* %D */ 222f73abda9Skristaps { NULL, posts_text }, /* %I */ 223f73abda9Skristaps { NULL, posts_text }, /* %J */ 2244039b21cSschwarze { NULL, posts_hyphtext }, /* %N */ 2254039b21cSschwarze { NULL, posts_hyphtext }, /* %O */ 226f73abda9Skristaps { NULL, posts_text }, /* %P */ 2274039b21cSschwarze { NULL, posts_hyphtext }, /* %R */ 2284039b21cSschwarze { NULL, posts_hyphtext }, /* %T */ /* FIXME: can be used outside Rs/Re. */ 229f73abda9Skristaps { NULL, posts_text }, /* %V */ 230f73abda9Skristaps { NULL, NULL }, /* Ac */ 231f73abda9Skristaps { NULL, NULL }, /* Ao */ 232bca76d61Sschwarze { NULL, NULL }, /* Aq */ 233f73abda9Skristaps { NULL, posts_at }, /* At */ 234f73abda9Skristaps { NULL, NULL }, /* Bc */ 235f73abda9Skristaps { NULL, posts_bf }, /* Bf */ 236f73abda9Skristaps { NULL, NULL }, /* Bo */ 237bca76d61Sschwarze { NULL, NULL }, /* Bq */ 238f73abda9Skristaps { NULL, NULL }, /* Bsx */ 239992063deSschwarze { NULL, posts_bx }, /* Bx */ 240f73abda9Skristaps { NULL, posts_bool }, /* Db */ 241f73abda9Skristaps { NULL, NULL }, /* Dc */ 242f73abda9Skristaps { NULL, NULL }, /* Do */ 243bca76d61Sschwarze { NULL, NULL }, /* Dq */ 244f73abda9Skristaps { NULL, NULL }, /* Ec */ 245f73abda9Skristaps { NULL, NULL }, /* Ef */ 246f73abda9Skristaps { NULL, NULL }, /* Em */ 247f73abda9Skristaps { NULL, NULL }, /* Eo */ 248f73abda9Skristaps { NULL, NULL }, /* Fx */ 249e7a93ef3Sschwarze { NULL, NULL }, /* Ms */ 250f73abda9Skristaps { NULL, posts_notext }, /* No */ 251af216717Sschwarze { NULL, posts_ns }, /* Ns */ 252f73abda9Skristaps { NULL, NULL }, /* Nx */ 253f73abda9Skristaps { NULL, NULL }, /* Ox */ 254f73abda9Skristaps { NULL, NULL }, /* Pc */ 255b822ca0dSschwarze { NULL, posts_text1 }, /* Pf */ 256f73abda9Skristaps { NULL, NULL }, /* Po */ 257bca76d61Sschwarze { NULL, NULL }, /* Pq */ 258f73abda9Skristaps { NULL, NULL }, /* Qc */ 259bca76d61Sschwarze { NULL, NULL }, /* Ql */ 260f73abda9Skristaps { NULL, NULL }, /* Qo */ 261bca76d61Sschwarze { NULL, NULL }, /* Qq */ 262f73abda9Skristaps { NULL, NULL }, /* Re */ 2638c62fbf5Sschwarze { NULL, posts_rs }, /* Rs */ 264f73abda9Skristaps { NULL, NULL }, /* Sc */ 265f73abda9Skristaps { NULL, NULL }, /* So */ 266bca76d61Sschwarze { NULL, NULL }, /* Sq */ 267f73abda9Skristaps { NULL, posts_bool }, /* Sm */ 2684039b21cSschwarze { NULL, posts_hyph }, /* Sx */ 269e7a93ef3Sschwarze { NULL, NULL }, /* Sy */ 270e7a93ef3Sschwarze { NULL, NULL }, /* Tn */ 271f73abda9Skristaps { NULL, NULL }, /* Ux */ 272f73abda9Skristaps { NULL, NULL }, /* Xc */ 273f73abda9Skristaps { NULL, NULL }, /* Xo */ 274f73abda9Skristaps { NULL, posts_fo }, /* Fo */ 275f73abda9Skristaps { NULL, NULL }, /* Fc */ 276f73abda9Skristaps { NULL, NULL }, /* Oo */ 277f73abda9Skristaps { NULL, NULL }, /* Oc */ 27820fa2881Sschwarze { NULL, posts_bk }, /* Bk */ 279f73abda9Skristaps { NULL, NULL }, /* Ek */ 280b31af00dSschwarze { NULL, posts_eoln }, /* Bt */ 281f73abda9Skristaps { NULL, NULL }, /* Hf */ 282551cd4a8Sschwarze { pres_obsolete, NULL }, /* Fr */ 283b31af00dSschwarze { NULL, posts_eoln }, /* Ud */ 284b31af00dSschwarze { NULL, posts_lb }, /* Lb */ 285e0dd4c9cSschwarze { pres_pp, posts_pp }, /* Lp */ 286e7a93ef3Sschwarze { NULL, NULL }, /* Lk */ 28720fa2881Sschwarze { NULL, posts_defaults }, /* Mt */ 288bca76d61Sschwarze { NULL, NULL }, /* Brq */ 289f73abda9Skristaps { NULL, NULL }, /* Bro */ 290f73abda9Skristaps { NULL, NULL }, /* Brc */ 291f73abda9Skristaps { NULL, posts_text }, /* %C */ 292551cd4a8Sschwarze { pres_obsolete, posts_es }, /* Es */ 293551cd4a8Sschwarze { pres_obsolete, posts_en }, /* En */ 294f73abda9Skristaps { NULL, NULL }, /* Dx */ 295f73abda9Skristaps { NULL, posts_text }, /* %Q */ 296e0dd4c9cSschwarze { NULL, posts_pp }, /* br */ 297e0dd4c9cSschwarze { NULL, posts_sp }, /* sp */ 298b822ca0dSschwarze { NULL, posts_text1 }, /* %U */ 2996093755cSschwarze { NULL, NULL }, /* Ta */ 3005281506aSschwarze { NULL, NULL }, /* ll */ 301f73abda9Skristaps }; 302f73abda9Skristaps 30320fa2881Sschwarze #define RSORD_MAX 14 /* Number of `Rs' blocks. */ 30420fa2881Sschwarze 30520fa2881Sschwarze static const enum mdoct rsord[RSORD_MAX] = { 30620fa2881Sschwarze MDOC__A, 30720fa2881Sschwarze MDOC__T, 30820fa2881Sschwarze MDOC__B, 30920fa2881Sschwarze MDOC__I, 31020fa2881Sschwarze MDOC__J, 31120fa2881Sschwarze MDOC__R, 31220fa2881Sschwarze MDOC__N, 31320fa2881Sschwarze MDOC__V, 3140397c682Sschwarze MDOC__U, 31520fa2881Sschwarze MDOC__P, 31620fa2881Sschwarze MDOC__Q, 3174e32ec8fSschwarze MDOC__C, 31820fa2881Sschwarze MDOC__D, 3194e32ec8fSschwarze MDOC__O 32020fa2881Sschwarze }; 32120fa2881Sschwarze 32219a69263Sschwarze static const char * const secnames[SEC__MAX] = { 32319a69263Sschwarze NULL, 32419a69263Sschwarze "NAME", 32519a69263Sschwarze "LIBRARY", 32619a69263Sschwarze "SYNOPSIS", 32719a69263Sschwarze "DESCRIPTION", 32803ab2f23Sdlg "CONTEXT", 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 34849aff9f8Sschwarze 349f73abda9Skristaps int 3506093755cSschwarze mdoc_valid_pre(struct mdoc *mdoc, struct mdoc_node *n) 351f73abda9Skristaps { 352f73abda9Skristaps v_pre *p; 353f73abda9Skristaps int line, pos; 35431e23753Sschwarze char *tp; 355f73abda9Skristaps 3562791bd1cSschwarze switch (n->type) { 35749aff9f8Sschwarze case MDOC_TEXT: 358f73abda9Skristaps tp = n->string; 359f73abda9Skristaps line = n->line; 360f73abda9Skristaps pos = n->pos; 36120fa2881Sschwarze check_text(mdoc, line, pos, tp); 3622791bd1cSschwarze /* FALLTHROUGH */ 36349aff9f8Sschwarze case MDOC_TBL: 3642791bd1cSschwarze /* FALLTHROUGH */ 36549aff9f8Sschwarze case MDOC_EQN: 3668d973ab1Sschwarze /* FALLTHROUGH */ 36749aff9f8Sschwarze case MDOC_ROOT: 36820fa2881Sschwarze return(1); 3692791bd1cSschwarze default: 3702791bd1cSschwarze break; 371f73abda9Skristaps } 372f73abda9Skristaps 37320fa2881Sschwarze check_args(mdoc, n); 37420fa2881Sschwarze 375f73abda9Skristaps if (NULL == mdoc_valids[n->tok].pre) 376f73abda9Skristaps return(1); 377f73abda9Skristaps for (p = mdoc_valids[n->tok].pre; *p; p++) 378f73abda9Skristaps if ( ! (*p)(mdoc, n)) 379f73abda9Skristaps return(0); 380f73abda9Skristaps return(1); 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) { 39349aff9f8Sschwarze case MDOC_TEXT: 3942791bd1cSschwarze /* FALLTHROUGH */ 39549aff9f8Sschwarze case MDOC_EQN: 3968d973ab1Sschwarze /* FALLTHROUGH */ 39749aff9f8Sschwarze case MDOC_TBL: 398f73abda9Skristaps return(1); 39949aff9f8Sschwarze 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) { 42549aff9f8Sschwarze case CHECK_LT: 4267c2be9f8Sschwarze p = "less than "; 4277ead8a4eSschwarze if (mdoc->last->nchild < val) 4287c2be9f8Sschwarze return(1); 4297c2be9f8Sschwarze break; 43049aff9f8Sschwarze case CHECK_GT: 431bb648afaSschwarze p = "more than "; 4327ead8a4eSschwarze if (mdoc->last->nchild > val) 4337c2be9f8Sschwarze return(1); 4347c2be9f8Sschwarze break; 43549aff9f8Sschwarze 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; 44649aff9f8Sschwarze mandoc_vmsg(t, mdoc->parse, mdoc->last->line, 44749aff9f8Sschwarze mdoc->last->pos, "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 50720fa2881Sschwarze static void 5087ead8a4eSschwarze check_args(struct mdoc *mdoc, struct mdoc_node *n) 509f73abda9Skristaps { 510f73abda9Skristaps int i; 511f73abda9Skristaps 512f73abda9Skristaps if (NULL == n->args) 51320fa2881Sschwarze return; 514f73abda9Skristaps 515f73abda9Skristaps assert(n->args->argc); 516f73abda9Skristaps for (i = 0; i < (int)n->args->argc; i++) 5177ead8a4eSschwarze check_argv(mdoc, n, &n->args->argv[i]); 518f73abda9Skristaps } 519f73abda9Skristaps 52020fa2881Sschwarze static void 5217ead8a4eSschwarze check_argv(struct mdoc *mdoc, struct mdoc_node *n, struct mdoc_argv *v) 522f73abda9Skristaps { 523f73abda9Skristaps int i; 524f73abda9Skristaps 525f73abda9Skristaps for (i = 0; i < (int)v->sz; i++) 5267ead8a4eSschwarze check_text(mdoc, v->line, v->pos, v->value[i]); 527f73abda9Skristaps } 528f73abda9Skristaps 52920fa2881Sschwarze static void 5307ead8a4eSschwarze check_text(struct mdoc *mdoc, int ln, int pos, char *p) 531f73abda9Skristaps { 53204e980cbSschwarze char *cp; 533769ee804Sschwarze 5347ead8a4eSschwarze if (MDOC_LITERAL & mdoc->flags) 5351cdbf331Sschwarze return; 5361cdbf331Sschwarze 5371cdbf331Sschwarze for (cp = p; NULL != (p = strchr(p, '\t')); p++) 538dd5b31c3Sschwarze mandoc_msg(MANDOCERR_FI_TAB, mdoc->parse, 539dd5b31c3Sschwarze ln, pos + (int)(p - cp), NULL); 540f73abda9Skristaps } 541f73abda9Skristaps 542f73abda9Skristaps static int 543f73abda9Skristaps pre_display(PRE_ARGS) 544f73abda9Skristaps { 545f73abda9Skristaps struct mdoc_node *node; 546f73abda9Skristaps 547f73abda9Skristaps if (MDOC_BLOCK != n->type) 548f73abda9Skristaps return(1); 549f73abda9Skristaps 550f73abda9Skristaps for (node = mdoc->last->parent; node; node = node->parent) 551f73abda9Skristaps if (MDOC_BLOCK == node->type) 552f73abda9Skristaps if (MDOC_Bd == node->tok) 553f73abda9Skristaps break; 55420fa2881Sschwarze 55505c39368Sschwarze if (node) 556b723eac2Sschwarze mandoc_vmsg(MANDOCERR_BD_NEST, 557b723eac2Sschwarze mdoc->parse, n->line, n->pos, 558b723eac2Sschwarze "%s in Bd", mdoc_macronames[n->tok]); 55905c39368Sschwarze 56005c39368Sschwarze return(1); 561f73abda9Skristaps } 562f73abda9Skristaps 563f73abda9Skristaps static int 564f73abda9Skristaps pre_bl(PRE_ARGS) 565f73abda9Skristaps { 566769ee804Sschwarze struct mdoc_node *np; 5674a9f685fSschwarze struct mdoc_argv *argv; 5684a9f685fSschwarze int i; 5694a9f685fSschwarze enum mdoc_list lt; 570f73abda9Skristaps 5716093755cSschwarze if (MDOC_BLOCK != n->type) { 572769ee804Sschwarze if (ENDBODY_NOT != n->end) { 573769ee804Sschwarze assert(n->pending); 574769ee804Sschwarze np = n->pending->parent; 575769ee804Sschwarze } else 576769ee804Sschwarze np = n->parent; 577769ee804Sschwarze 578769ee804Sschwarze assert(np); 579769ee804Sschwarze assert(MDOC_BLOCK == np->type); 580769ee804Sschwarze assert(MDOC_Bl == np->tok); 581f73abda9Skristaps return(1); 5826e03d529Sschwarze } 583f73abda9Skristaps 5846093755cSschwarze /* 5856093755cSschwarze * First figure out which kind of list to use: bind ourselves to 5866093755cSschwarze * the first mentioned list type and warn about any remaining 5876093755cSschwarze * ones. If we find no list type, we default to LIST_item. 5886093755cSschwarze */ 589f73abda9Skristaps 5906093755cSschwarze for (i = 0; n->args && i < (int)n->args->argc; i++) { 5914a9f685fSschwarze argv = n->args->argv + i; 5926093755cSschwarze lt = LIST__NONE; 5934a9f685fSschwarze switch (argv->arg) { 5946093755cSschwarze /* Set list types. */ 59549aff9f8Sschwarze case MDOC_Bullet: 5966093755cSschwarze lt = LIST_bullet; 5976093755cSschwarze break; 59849aff9f8Sschwarze case MDOC_Dash: 5996093755cSschwarze lt = LIST_dash; 6006093755cSschwarze break; 60149aff9f8Sschwarze case MDOC_Enum: 6026093755cSschwarze lt = LIST_enum; 6036093755cSschwarze break; 60449aff9f8Sschwarze case MDOC_Hyphen: 6056093755cSschwarze lt = LIST_hyphen; 6066093755cSschwarze break; 60749aff9f8Sschwarze case MDOC_Item: 6086093755cSschwarze lt = LIST_item; 6096093755cSschwarze break; 61049aff9f8Sschwarze case MDOC_Tag: 6116093755cSschwarze lt = LIST_tag; 6126093755cSschwarze break; 61349aff9f8Sschwarze case MDOC_Diag: 6146093755cSschwarze lt = LIST_diag; 6156093755cSschwarze break; 61649aff9f8Sschwarze case MDOC_Hang: 6176093755cSschwarze lt = LIST_hang; 6186093755cSschwarze break; 61949aff9f8Sschwarze case MDOC_Ohang: 6206093755cSschwarze lt = LIST_ohang; 6216093755cSschwarze break; 62249aff9f8Sschwarze case MDOC_Inset: 6236093755cSschwarze lt = LIST_inset; 6246093755cSschwarze break; 62549aff9f8Sschwarze case MDOC_Column: 6266093755cSschwarze lt = LIST_column; 62764d728e4Sschwarze break; 6286093755cSschwarze /* Set list arguments. */ 62949aff9f8Sschwarze case MDOC_Compact: 6304a9f685fSschwarze if (n->norm->Bl.comp) 6314a9f685fSschwarze mandoc_msg(MANDOCERR_ARG_REP, 6324a9f685fSschwarze mdoc->parse, argv->line, 6334a9f685fSschwarze argv->pos, "Bl -compact"); 6344a9f685fSschwarze n->norm->Bl.comp = 1; 63550e63e03Sschwarze break; 63649aff9f8Sschwarze case MDOC_Width: 6374a9f685fSschwarze if (0 == argv->sz) { 6384a9f685fSschwarze mandoc_msg(MANDOCERR_ARG_EMPTY, 6394a9f685fSschwarze mdoc->parse, argv->line, 6404a9f685fSschwarze argv->pos, "Bl -width"); 6414a9f685fSschwarze n->norm->Bl.width = "0n"; 64222972b14Sschwarze break; 64322972b14Sschwarze } 6444a9f685fSschwarze if (NULL != n->norm->Bl.width) 6454a9f685fSschwarze mandoc_vmsg(MANDOCERR_ARG_REP, 6464a9f685fSschwarze mdoc->parse, argv->line, 6474a9f685fSschwarze argv->pos, "Bl -width %s", 6484a9f685fSschwarze argv->value[0]); 6494a9f685fSschwarze n->norm->Bl.width = argv->value[0]; 65064d728e4Sschwarze break; 65149aff9f8Sschwarze case MDOC_Offset: 6524a9f685fSschwarze if (0 == argv->sz) { 6534a9f685fSschwarze mandoc_msg(MANDOCERR_ARG_EMPTY, 6544a9f685fSschwarze mdoc->parse, argv->line, 6554a9f685fSschwarze argv->pos, "Bl -offset"); 65631e23753Sschwarze break; 65731e23753Sschwarze } 6584a9f685fSschwarze if (NULL != n->norm->Bl.offs) 6594a9f685fSschwarze mandoc_vmsg(MANDOCERR_ARG_REP, 6604a9f685fSschwarze mdoc->parse, argv->line, 6614a9f685fSschwarze argv->pos, "Bl -offset %s", 6624a9f685fSschwarze argv->value[0]); 6634a9f685fSschwarze n->norm->Bl.offs = argv->value[0]; 664f73abda9Skristaps break; 665ddce0b0cSschwarze default: 666ddce0b0cSschwarze continue; 667f73abda9Skristaps } 668dc0d8bb2Sschwarze if (LIST__NONE == lt) 669dc0d8bb2Sschwarze continue; 670f73abda9Skristaps 6716093755cSschwarze /* Check: multiple list types. */ 6726093755cSschwarze 673dc0d8bb2Sschwarze if (LIST__NONE != n->norm->Bl.type) { 674dc0d8bb2Sschwarze mandoc_msg(MANDOCERR_BL_REP, 675dc0d8bb2Sschwarze mdoc->parse, n->line, n->pos, 676dc0d8bb2Sschwarze mdoc_argnames[argv->arg]); 677dc0d8bb2Sschwarze continue; 678769ee804Sschwarze } 6796093755cSschwarze 6806093755cSschwarze /* The list type should come first. */ 6816093755cSschwarze 6828c62fbf5Sschwarze if (n->norm->Bl.width || 6838c62fbf5Sschwarze n->norm->Bl.offs || 6848c62fbf5Sschwarze n->norm->Bl.comp) 68566788495Sschwarze mandoc_msg(MANDOCERR_BL_LATETYPE, 68666788495Sschwarze mdoc->parse, n->line, n->pos, 68766788495Sschwarze mdoc_argnames[n->args->argv[0].arg]); 688dc0d8bb2Sschwarze 689dc0d8bb2Sschwarze n->norm->Bl.type = lt; 690dc0d8bb2Sschwarze if (LIST_column == lt) { 691dc0d8bb2Sschwarze n->norm->Bl.ncols = argv->sz; 692dc0d8bb2Sschwarze n->norm->Bl.cols = (void *)argv->value; 693dc0d8bb2Sschwarze } 6946093755cSschwarze } 6956093755cSschwarze 6966093755cSschwarze /* Allow lists to default to LIST_item. */ 6976093755cSschwarze 6988c62fbf5Sschwarze if (LIST__NONE == n->norm->Bl.type) { 69966788495Sschwarze mdoc_nmsg(mdoc, n, MANDOCERR_BL_NOTYPE); 7008c62fbf5Sschwarze n->norm->Bl.type = LIST_item; 7016e03d529Sschwarze } 702f73abda9Skristaps 70364d728e4Sschwarze /* 70464d728e4Sschwarze * Validate the width field. Some list types don't need width 70564d728e4Sschwarze * types and should be warned about them. Others should have it 7065eced068Sschwarze * and must also be warned. Yet others have a default and need 7075eced068Sschwarze * no warning. 70864d728e4Sschwarze */ 70964d728e4Sschwarze 7108c62fbf5Sschwarze switch (n->norm->Bl.type) { 71149aff9f8Sschwarze case LIST_tag: 7125eced068Sschwarze if (NULL == n->norm->Bl.width) 713dc0d8bb2Sschwarze mdoc_nmsg(mdoc, n, MANDOCERR_BL_NOWIDTH); 714f73abda9Skristaps break; 71549aff9f8Sschwarze case LIST_column: 7166093755cSschwarze /* FALLTHROUGH */ 71749aff9f8Sschwarze case LIST_diag: 7186093755cSschwarze /* FALLTHROUGH */ 71949aff9f8Sschwarze case LIST_ohang: 7206093755cSschwarze /* FALLTHROUGH */ 72149aff9f8Sschwarze case LIST_inset: 7226093755cSschwarze /* FALLTHROUGH */ 72349aff9f8Sschwarze case LIST_item: 7248c62fbf5Sschwarze if (n->norm->Bl.width) 725817ac90bSschwarze mdoc_nmsg(mdoc, n, MANDOCERR_IGNARGV); 7266093755cSschwarze break; 72749aff9f8Sschwarze case LIST_bullet: 7285eced068Sschwarze /* FALLTHROUGH */ 72949aff9f8Sschwarze case LIST_dash: 7305eced068Sschwarze /* FALLTHROUGH */ 73149aff9f8Sschwarze case LIST_hyphen: 7325eced068Sschwarze if (NULL == n->norm->Bl.width) 7335eced068Sschwarze n->norm->Bl.width = "2n"; 7345eced068Sschwarze break; 73549aff9f8Sschwarze case LIST_enum: 7365eced068Sschwarze if (NULL == n->norm->Bl.width) 7375eced068Sschwarze n->norm->Bl.width = "3n"; 7385eced068Sschwarze break; 73964d728e4Sschwarze default: 740f73abda9Skristaps break; 74164d728e4Sschwarze } 74264d728e4Sschwarze 743f73abda9Skristaps return(1); 744f73abda9Skristaps } 745f73abda9Skristaps 746f73abda9Skristaps static int 747f73abda9Skristaps pre_bd(PRE_ARGS) 748f73abda9Skristaps { 749769ee804Sschwarze struct mdoc_node *np; 7504a9f685fSschwarze struct mdoc_argv *argv; 7514a9f685fSschwarze int i; 7524a9f685fSschwarze enum mdoc_disp dt; 753f73abda9Skristaps 75431e23753Sschwarze if (MDOC_BLOCK != n->type) { 755769ee804Sschwarze if (ENDBODY_NOT != n->end) { 756769ee804Sschwarze assert(n->pending); 757769ee804Sschwarze np = n->pending->parent; 758769ee804Sschwarze } else 759769ee804Sschwarze np = n->parent; 760769ee804Sschwarze 761769ee804Sschwarze assert(np); 762769ee804Sschwarze assert(MDOC_BLOCK == np->type); 763769ee804Sschwarze assert(MDOC_Bd == np->tok); 764f73abda9Skristaps return(1); 7656e03d529Sschwarze } 766f73abda9Skristaps 76731e23753Sschwarze for (i = 0; n->args && i < (int)n->args->argc; i++) { 7684a9f685fSschwarze argv = n->args->argv + i; 76931e23753Sschwarze dt = DISP__NONE; 77031e23753Sschwarze 7714a9f685fSschwarze switch (argv->arg) { 77249aff9f8Sschwarze case MDOC_Centred: 7732065e47aSschwarze dt = DISP_centered; 77431e23753Sschwarze break; 77549aff9f8Sschwarze case MDOC_Ragged: 77631e23753Sschwarze dt = DISP_ragged; 77731e23753Sschwarze break; 77849aff9f8Sschwarze case MDOC_Unfilled: 77931e23753Sschwarze dt = DISP_unfilled; 78031e23753Sschwarze break; 78149aff9f8Sschwarze case MDOC_Filled: 78231e23753Sschwarze dt = DISP_filled; 78331e23753Sschwarze break; 78449aff9f8Sschwarze case MDOC_Literal: 78531e23753Sschwarze dt = DISP_literal; 786f73abda9Skristaps break; 78749aff9f8Sschwarze case MDOC_File: 78831e23753Sschwarze mdoc_nmsg(mdoc, n, MANDOCERR_BADDISP); 7896e03d529Sschwarze return(0); 79049aff9f8Sschwarze case MDOC_Offset: 7914a9f685fSschwarze if (0 == argv->sz) { 7924a9f685fSschwarze mandoc_msg(MANDOCERR_ARG_EMPTY, 7934a9f685fSschwarze mdoc->parse, argv->line, 7944a9f685fSschwarze argv->pos, "Bd -offset"); 795f73abda9Skristaps break; 796f73abda9Skristaps } 7974a9f685fSschwarze if (NULL != n->norm->Bd.offs) 7984a9f685fSschwarze mandoc_vmsg(MANDOCERR_ARG_REP, 7994a9f685fSschwarze mdoc->parse, argv->line, 8004a9f685fSschwarze argv->pos, "Bd -offset %s", 8014a9f685fSschwarze argv->value[0]); 8024a9f685fSschwarze n->norm->Bd.offs = argv->value[0]; 80331e23753Sschwarze break; 80449aff9f8Sschwarze case MDOC_Compact: 8054a9f685fSschwarze if (n->norm->Bd.comp) 8064a9f685fSschwarze mandoc_msg(MANDOCERR_ARG_REP, 8074a9f685fSschwarze mdoc->parse, argv->line, 8084a9f685fSschwarze argv->pos, "Bd -compact"); 8094a9f685fSschwarze n->norm->Bd.comp = 1; 81031e23753Sschwarze break; 81131e23753Sschwarze default: 81231e23753Sschwarze abort(); 81331e23753Sschwarze /* NOTREACHED */ 81431e23753Sschwarze } 815dc0d8bb2Sschwarze if (DISP__NONE == dt) 816dc0d8bb2Sschwarze continue; 81731e23753Sschwarze 818dc0d8bb2Sschwarze if (DISP__NONE == n->norm->Bd.type) 8198c62fbf5Sschwarze n->norm->Bd.type = dt; 820dc0d8bb2Sschwarze else 821dc0d8bb2Sschwarze mandoc_msg(MANDOCERR_BD_REP, 822dc0d8bb2Sschwarze mdoc->parse, n->line, n->pos, 823dc0d8bb2Sschwarze mdoc_argnames[argv->arg]); 82431e23753Sschwarze } 82531e23753Sschwarze 8268c62fbf5Sschwarze if (DISP__NONE == n->norm->Bd.type) { 82766788495Sschwarze mdoc_nmsg(mdoc, n, MANDOCERR_BD_NOTYPE); 8288c62fbf5Sschwarze n->norm->Bd.type = DISP_ragged; 82931e23753Sschwarze } 83031e23753Sschwarze 83131e23753Sschwarze return(1); 832f73abda9Skristaps } 833f73abda9Skristaps 834f73abda9Skristaps static int 835f73abda9Skristaps pre_an(PRE_ARGS) 836f73abda9Skristaps { 8376475d5b0Sschwarze int i; 838f73abda9Skristaps 839769ee804Sschwarze if (NULL == n->args) 840f73abda9Skristaps return(1); 841769ee804Sschwarze 8426475d5b0Sschwarze for (i = 1; i < (int)n->args->argc; i++) 84320fa2881Sschwarze mdoc_pmsg(mdoc, n->args->argv[i].line, 84420fa2881Sschwarze n->args->argv[i].pos, MANDOCERR_IGNARGV); 8457c2be9f8Sschwarze 846769ee804Sschwarze if (MDOC_Split == n->args->argv[0].arg) 8478c62fbf5Sschwarze n->norm->An.auth = AUTH_split; 848769ee804Sschwarze else if (MDOC_Nosplit == n->args->argv[0].arg) 8498c62fbf5Sschwarze n->norm->An.auth = AUTH_nosplit; 850769ee804Sschwarze else 851769ee804Sschwarze abort(); 852769ee804Sschwarze 853769ee804Sschwarze return(1); 854f73abda9Skristaps } 855f73abda9Skristaps 856f73abda9Skristaps static int 85720fa2881Sschwarze pre_std(PRE_ARGS) 858f73abda9Skristaps { 859f73abda9Skristaps 86020fa2881Sschwarze if (n->args && 1 == n->args->argc) 86120fa2881Sschwarze if (MDOC_Std == n->args->argv[0].arg) 86220fa2881Sschwarze return(1); 863f73abda9Skristaps 86466788495Sschwarze mandoc_msg(MANDOCERR_ARG_STD, mdoc->parse, 86566788495Sschwarze n->line, n->pos, mdoc_macronames[n->tok]); 8666093755cSschwarze return(1); 8676093755cSschwarze } 8686093755cSschwarze 8696093755cSschwarze static int 870551cd4a8Sschwarze pre_obsolete(PRE_ARGS) 871551cd4a8Sschwarze { 872551cd4a8Sschwarze 873551cd4a8Sschwarze if (MDOC_ELEM == n->type || MDOC_BLOCK == n->type) 874551cd4a8Sschwarze mandoc_msg(MANDOCERR_MACRO_OBS, mdoc->parse, 875551cd4a8Sschwarze n->line, n->pos, mdoc_macronames[n->tok]); 876551cd4a8Sschwarze return(1); 877551cd4a8Sschwarze } 878551cd4a8Sschwarze 879551cd4a8Sschwarze static int 880f73abda9Skristaps pre_dt(PRE_ARGS) 881f73abda9Skristaps { 882f73abda9Skristaps 883b058e777Sschwarze if (NULL == mdoc->meta.date || mdoc->meta.os) 88451fcab2fSschwarze mandoc_msg(MANDOCERR_PROLOG_ORDER, mdoc->parse, 88551fcab2fSschwarze n->line, n->pos, "Dt"); 88620fa2881Sschwarze 887f73abda9Skristaps if (mdoc->meta.title) 88851fcab2fSschwarze mandoc_msg(MANDOCERR_PROLOG_REP, mdoc->parse, 88951fcab2fSschwarze n->line, n->pos, "Dt"); 89020fa2881Sschwarze 891f73abda9Skristaps return(1); 892f73abda9Skristaps } 893f73abda9Skristaps 894f73abda9Skristaps static int 895f73abda9Skristaps pre_os(PRE_ARGS) 896f73abda9Skristaps { 897f73abda9Skristaps 898b058e777Sschwarze if (NULL == mdoc->meta.title || NULL == mdoc->meta.date) 89951fcab2fSschwarze mandoc_msg(MANDOCERR_PROLOG_ORDER, mdoc->parse, 90051fcab2fSschwarze n->line, n->pos, "Os"); 90120fa2881Sschwarze 902f73abda9Skristaps if (mdoc->meta.os) 90351fcab2fSschwarze mandoc_msg(MANDOCERR_PROLOG_REP, mdoc->parse, 90451fcab2fSschwarze n->line, n->pos, "Os"); 90520fa2881Sschwarze 906f73abda9Skristaps return(1); 907f73abda9Skristaps } 908f73abda9Skristaps 909f73abda9Skristaps static int 910f73abda9Skristaps pre_dd(PRE_ARGS) 911f73abda9Skristaps { 912f73abda9Skristaps 913f73abda9Skristaps if (mdoc->meta.title || mdoc->meta.os) 91451fcab2fSschwarze mandoc_msg(MANDOCERR_PROLOG_ORDER, mdoc->parse, 91551fcab2fSschwarze n->line, n->pos, "Dd"); 91620fa2881Sschwarze 917f73abda9Skristaps if (mdoc->meta.date) 91851fcab2fSschwarze mandoc_msg(MANDOCERR_PROLOG_REP, mdoc->parse, 91951fcab2fSschwarze n->line, n->pos, "Dd"); 92020fa2881Sschwarze 921f73abda9Skristaps return(1); 922f73abda9Skristaps } 923f73abda9Skristaps 924f73abda9Skristaps static int 925f73abda9Skristaps post_bf(POST_ARGS) 926f73abda9Skristaps { 927ecb10c32Sschwarze struct mdoc_node *np, *nch; 928ddce0b0cSschwarze enum mdocargt arg; 929f73abda9Skristaps 930769ee804Sschwarze /* 931769ee804Sschwarze * Unlike other data pointers, these are "housed" by the HEAD 932769ee804Sschwarze * element, which contains the goods. 933769ee804Sschwarze */ 934769ee804Sschwarze 935769ee804Sschwarze if (MDOC_HEAD != mdoc->last->type) { 936769ee804Sschwarze if (ENDBODY_NOT != mdoc->last->end) { 937769ee804Sschwarze assert(mdoc->last->pending); 938769ee804Sschwarze np = mdoc->last->pending->parent->head; 939769ee804Sschwarze } else if (MDOC_BLOCK != mdoc->last->type) { 940769ee804Sschwarze np = mdoc->last->parent->head; 941769ee804Sschwarze } else 942769ee804Sschwarze np = mdoc->last->head; 943769ee804Sschwarze 944769ee804Sschwarze assert(np); 945769ee804Sschwarze assert(MDOC_HEAD == np->type); 946769ee804Sschwarze assert(MDOC_Bf == np->tok); 947f73abda9Skristaps return(1); 9486e03d529Sschwarze } 949f73abda9Skristaps 950769ee804Sschwarze np = mdoc->last; 951769ee804Sschwarze assert(MDOC_BLOCK == np->parent->type); 952769ee804Sschwarze assert(MDOC_Bf == np->parent->tok); 95350d41253Sschwarze 954ecb10c32Sschwarze /* Check the number of arguments. */ 955f73abda9Skristaps 956ecb10c32Sschwarze nch = np->child; 957ecb10c32Sschwarze if (NULL == np->parent->args) { 958ecb10c32Sschwarze if (NULL == nch) { 959ecb10c32Sschwarze mdoc_nmsg(mdoc, np, MANDOCERR_BF_NOFONT); 96020fa2881Sschwarze return(1); 96120fa2881Sschwarze } 962ecb10c32Sschwarze nch = nch->next; 963ecb10c32Sschwarze } 964ecb10c32Sschwarze if (NULL != nch) 965ecb10c32Sschwarze mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse, 966ecb10c32Sschwarze nch->line, nch->pos, "Bf ... %s", nch->string); 967769ee804Sschwarze 968769ee804Sschwarze /* Extract argument into data. */ 969769ee804Sschwarze 970769ee804Sschwarze if (np->parent->args) { 971769ee804Sschwarze arg = np->parent->args->argv[0].arg; 972769ee804Sschwarze if (MDOC_Emphasis == arg) 9738c62fbf5Sschwarze np->norm->Bf.font = FONT_Em; 974769ee804Sschwarze else if (MDOC_Literal == arg) 9758c62fbf5Sschwarze np->norm->Bf.font = FONT_Li; 976769ee804Sschwarze else if (MDOC_Symbolic == arg) 9778c62fbf5Sschwarze np->norm->Bf.font = FONT_Sy; 978769ee804Sschwarze else 979769ee804Sschwarze abort(); 980769ee804Sschwarze return(1); 981769ee804Sschwarze } 982769ee804Sschwarze 983769ee804Sschwarze /* Extract parameter into data. */ 984769ee804Sschwarze 985769ee804Sschwarze if (0 == strcmp(np->child->string, "Em")) 9868c62fbf5Sschwarze np->norm->Bf.font = FONT_Em; 987769ee804Sschwarze else if (0 == strcmp(np->child->string, "Li")) 9888c62fbf5Sschwarze np->norm->Bf.font = FONT_Li; 989769ee804Sschwarze else if (0 == strcmp(np->child->string, "Sy")) 9908c62fbf5Sschwarze np->norm->Bf.font = FONT_Sy; 99120fa2881Sschwarze else 992ecb10c32Sschwarze mandoc_vmsg(MANDOCERR_BF_BADFONT, mdoc->parse, 993ecb10c32Sschwarze np->child->line, np->child->pos, 994ecb10c32Sschwarze "Bf %s", np->child->string); 995769ee804Sschwarze 996769ee804Sschwarze return(1); 997f73abda9Skristaps } 998f73abda9Skristaps 999f73abda9Skristaps static int 100071719887Sschwarze post_lb(POST_ARGS) 100171719887Sschwarze { 100277e000ffSschwarze struct mdoc_node *n; 100377e000ffSschwarze const char *stdlibname; 100477e000ffSschwarze char *libname; 100571719887Sschwarze 1006bb648afaSschwarze check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 1); 1007bb648afaSschwarze 100877e000ffSschwarze n = mdoc->last->child; 100920fa2881Sschwarze 101077e000ffSschwarze assert(n); 101177e000ffSschwarze assert(MDOC_TEXT == n->type); 101220fa2881Sschwarze 101377e000ffSschwarze if (NULL == (stdlibname = mdoc_a2lib(n->string))) 101477e000ffSschwarze mandoc_asprintf(&libname, 101577e000ffSschwarze "library \\(lq%s\\(rq", n->string); 101677e000ffSschwarze else 101777e000ffSschwarze libname = mandoc_strdup(stdlibname); 101820fa2881Sschwarze 101977e000ffSschwarze free(n->string); 102077e000ffSschwarze n->string = libname; 102120fa2881Sschwarze return(1); 102220fa2881Sschwarze } 102371719887Sschwarze 102471719887Sschwarze static int 1025b31af00dSschwarze post_eoln(POST_ARGS) 1026b31af00dSschwarze { 1027ecb10c32Sschwarze const struct mdoc_node *n; 1028b31af00dSschwarze 1029ecb10c32Sschwarze n = mdoc->last; 1030ecb10c32Sschwarze if (n->child) 1031ecb10c32Sschwarze mandoc_vmsg(MANDOCERR_ARG_SKIP, 1032ecb10c32Sschwarze mdoc->parse, n->line, n->pos, 1033ecb10c32Sschwarze "%s %s", mdoc_macronames[n->tok], 1034ecb10c32Sschwarze n->child->string); 1035b31af00dSschwarze return(1); 1036b31af00dSschwarze } 1037b31af00dSschwarze 1038b31af00dSschwarze static int 10398521b0bcSschwarze post_vt(POST_ARGS) 10408521b0bcSschwarze { 10418521b0bcSschwarze const struct mdoc_node *n; 10428521b0bcSschwarze 10438521b0bcSschwarze /* 10448521b0bcSschwarze * The Vt macro comes in both ELEM and BLOCK form, both of which 10458521b0bcSschwarze * have different syntaxes (yet more context-sensitive 1046e7a93ef3Sschwarze * behaviour). ELEM types must have a child, which is already 1047e7a93ef3Sschwarze * guaranteed by the in_line parsing routine; BLOCK types, 10488521b0bcSschwarze * specifically the BODY, should only have TEXT children. 10498521b0bcSschwarze */ 10508521b0bcSschwarze 10518521b0bcSschwarze if (MDOC_BODY != mdoc->last->type) 10528521b0bcSschwarze return(1); 10538521b0bcSschwarze 10548521b0bcSschwarze for (n = mdoc->last->child; n; n = n->next) 1055bc49dbe1Sschwarze if (MDOC_TEXT != n->type) 1056dd25b57cSschwarze mandoc_msg(MANDOCERR_VT_CHILD, mdoc->parse, 1057dd25b57cSschwarze n->line, n->pos, mdoc_macronames[n->tok]); 10588521b0bcSschwarze 10598521b0bcSschwarze return(1); 10608521b0bcSschwarze } 10618521b0bcSschwarze 10628521b0bcSschwarze static int 1063f73abda9Skristaps post_nm(POST_ARGS) 1064f73abda9Skristaps { 106520fa2881Sschwarze 1066160ac481Sschwarze if (NULL != mdoc->meta.name) 106720fa2881Sschwarze return(1); 106820fa2881Sschwarze 106983af2bccSschwarze mdoc_deroff(&mdoc->meta.name, mdoc->last); 107020fa2881Sschwarze 1071e214f641Sschwarze if (NULL == mdoc->meta.name) 1072e214f641Sschwarze mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NM_NONAME); 107320fa2881Sschwarze return(1); 107420fa2881Sschwarze } 107520fa2881Sschwarze 107620fa2881Sschwarze static int 107720fa2881Sschwarze post_literal(POST_ARGS) 107820fa2881Sschwarze { 107920fa2881Sschwarze 108020fa2881Sschwarze /* 108120fa2881Sschwarze * The `Dl' (note "el" not "one") and `Bd' macros unset the 108220fa2881Sschwarze * MDOC_LITERAL flag as they leave. Note that `Bd' only sets 108320fa2881Sschwarze * this in literal mode, but it doesn't hurt to just switch it 108420fa2881Sschwarze * off in general since displays can't be nested. 108520fa2881Sschwarze */ 108620fa2881Sschwarze 108720fa2881Sschwarze if (MDOC_BODY == mdoc->last->type) 108820fa2881Sschwarze mdoc->flags &= ~MDOC_LITERAL; 108920fa2881Sschwarze 109020fa2881Sschwarze return(1); 109120fa2881Sschwarze } 109220fa2881Sschwarze 109320fa2881Sschwarze static int 109420fa2881Sschwarze post_defaults(POST_ARGS) 109520fa2881Sschwarze { 109620fa2881Sschwarze struct mdoc_node *nn; 109720fa2881Sschwarze 109820fa2881Sschwarze /* 109920fa2881Sschwarze * The `Ar' defaults to "file ..." if no value is provided as an 110020fa2881Sschwarze * argument; the `Mt' and `Pa' macros use "~"; the `Li' just 110120fa2881Sschwarze * gets an empty string. 110220fa2881Sschwarze */ 1103f73abda9Skristaps 1104f73abda9Skristaps if (mdoc->last->child) 1105f73abda9Skristaps return(1); 110620fa2881Sschwarze 110720fa2881Sschwarze nn = mdoc->last; 110820fa2881Sschwarze mdoc->next = MDOC_NEXT_CHILD; 110920fa2881Sschwarze 111020fa2881Sschwarze switch (nn->tok) { 111149aff9f8Sschwarze case MDOC_Ar: 111220fa2881Sschwarze if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "file")) 111320fa2881Sschwarze return(0); 111420fa2881Sschwarze if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "...")) 111520fa2881Sschwarze return(0); 111620fa2881Sschwarze break; 111749aff9f8Sschwarze case MDOC_At: 111820fa2881Sschwarze if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "AT&T")) 111920fa2881Sschwarze return(0); 112020fa2881Sschwarze if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "UNIX")) 112120fa2881Sschwarze return(0); 112220fa2881Sschwarze break; 112349aff9f8Sschwarze case MDOC_Li: 112420fa2881Sschwarze if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "")) 112520fa2881Sschwarze return(0); 112620fa2881Sschwarze break; 112749aff9f8Sschwarze case MDOC_Pa: 112820fa2881Sschwarze /* FALLTHROUGH */ 112949aff9f8Sschwarze case MDOC_Mt: 113020fa2881Sschwarze if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "~")) 113120fa2881Sschwarze return(0); 113220fa2881Sschwarze break; 113320fa2881Sschwarze default: 113420fa2881Sschwarze abort(); 113520fa2881Sschwarze /* NOTREACHED */ 1136f73abda9Skristaps } 1137f73abda9Skristaps 113820fa2881Sschwarze mdoc->last = nn; 113920fa2881Sschwarze return(1); 114020fa2881Sschwarze } 1141f73abda9Skristaps 1142f73abda9Skristaps static int 1143f73abda9Skristaps post_at(POST_ARGS) 1144f73abda9Skristaps { 11450b2f1307Sschwarze struct mdoc_node *n; 11460b2f1307Sschwarze const char *std_att; 11470b2f1307Sschwarze char *att; 114820fa2881Sschwarze 114920fa2881Sschwarze /* 115020fa2881Sschwarze * If we have a child, look it up in the standard keys. If a 115120fa2881Sschwarze * key exist, use that instead of the child; if it doesn't, 115220fa2881Sschwarze * prefix "AT&T UNIX " to the existing data. 115320fa2881Sschwarze */ 1154f73abda9Skristaps 11550b2f1307Sschwarze if (NULL == (n = mdoc->last->child)) 1156f73abda9Skristaps return(1); 115720fa2881Sschwarze 11580b2f1307Sschwarze assert(MDOC_TEXT == n->type); 11590b2f1307Sschwarze if (NULL == (std_att = mdoc_a2att(n->string))) { 1160dc0d8bb2Sschwarze mandoc_msg(MANDOCERR_AT_BAD, mdoc->parse, 1161dc0d8bb2Sschwarze n->line, n->pos, n->string); 11620b2f1307Sschwarze mandoc_asprintf(&att, "AT&T UNIX %s", n->string); 11630b2f1307Sschwarze } else 11640b2f1307Sschwarze att = mandoc_strdup(std_att); 1165f73abda9Skristaps 11660b2f1307Sschwarze free(n->string); 11670b2f1307Sschwarze n->string = att; 116820fa2881Sschwarze return(1); 116920fa2881Sschwarze } 1170f73abda9Skristaps 1171f73abda9Skristaps static int 1172f73abda9Skristaps post_an(POST_ARGS) 1173f73abda9Skristaps { 1174769ee804Sschwarze struct mdoc_node *np; 1175f73abda9Skristaps 1176769ee804Sschwarze np = mdoc->last; 1177e7a93ef3Sschwarze if (AUTH__NONE == np->norm->An.auth) { 1178e7a93ef3Sschwarze if (0 == np->child) 1179e7a93ef3Sschwarze check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_GT, 0); 1180e7a93ef3Sschwarze } else if (np->child) 1181bb648afaSschwarze check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 0); 118220fa2881Sschwarze 118320fa2881Sschwarze return(1); 1184f73abda9Skristaps } 1185f73abda9Skristaps 1186f73abda9Skristaps static int 1187551cd4a8Sschwarze post_en(POST_ARGS) 1188551cd4a8Sschwarze { 1189551cd4a8Sschwarze 1190551cd4a8Sschwarze if (MDOC_BLOCK == mdoc->last->type) 1191551cd4a8Sschwarze mdoc->last->norm->Es = mdoc->last_es; 1192551cd4a8Sschwarze return(1); 1193551cd4a8Sschwarze } 1194551cd4a8Sschwarze 1195551cd4a8Sschwarze static int 1196551cd4a8Sschwarze post_es(POST_ARGS) 1197551cd4a8Sschwarze { 1198551cd4a8Sschwarze 1199551cd4a8Sschwarze mdoc->last_es = mdoc->last; 1200551cd4a8Sschwarze return(1); 1201551cd4a8Sschwarze } 1202551cd4a8Sschwarze 1203551cd4a8Sschwarze static int 1204f73abda9Skristaps post_it(POST_ARGS) 1205f73abda9Skristaps { 120619a69263Sschwarze int i, cols; 12076093755cSschwarze enum mdoc_list lt; 12089530682eSschwarze struct mdoc_node *nbl, *nit, *nch; 1209f73abda9Skristaps 12109530682eSschwarze nit = mdoc->last; 12119530682eSschwarze if (MDOC_BLOCK != nit->type) 1212f73abda9Skristaps return(1); 1213f73abda9Skristaps 12149530682eSschwarze nbl = nit->parent->parent; 12159530682eSschwarze lt = nbl->norm->Bl.type; 12166093755cSschwarze 12176093755cSschwarze switch (lt) { 121849aff9f8Sschwarze case LIST_tag: 12199530682eSschwarze /* FALLTHROUGH */ 122049aff9f8Sschwarze case LIST_hang: 1221f73abda9Skristaps /* FALLTHROUGH */ 122249aff9f8Sschwarze case LIST_ohang: 1223f73abda9Skristaps /* FALLTHROUGH */ 122449aff9f8Sschwarze case LIST_inset: 1225f73abda9Skristaps /* FALLTHROUGH */ 122649aff9f8Sschwarze case LIST_diag: 12279530682eSschwarze if (NULL == nit->head->child) 12289530682eSschwarze mandoc_msg(MANDOCERR_IT_NOHEAD, 12299530682eSschwarze mdoc->parse, nit->line, nit->pos, 12309530682eSschwarze mdoc_argnames[nbl->args->argv[0].arg]); 1231f73abda9Skristaps break; 123249aff9f8Sschwarze case LIST_bullet: 1233f73abda9Skristaps /* FALLTHROUGH */ 123449aff9f8Sschwarze case LIST_dash: 1235f73abda9Skristaps /* FALLTHROUGH */ 123649aff9f8Sschwarze case LIST_enum: 1237f73abda9Skristaps /* FALLTHROUGH */ 123849aff9f8Sschwarze case LIST_hyphen: 12399530682eSschwarze if (NULL == nit->body->child) 124066788495Sschwarze mandoc_msg(MANDOCERR_IT_NOBODY, 124166788495Sschwarze mdoc->parse, nit->line, nit->pos, 124266788495Sschwarze mdoc_argnames[nbl->args->argv[0].arg]); 1243f73abda9Skristaps /* FALLTHROUGH */ 124449aff9f8Sschwarze case LIST_item: 12459530682eSschwarze if (NULL != nit->head->child) 1246ecb10c32Sschwarze mandoc_vmsg(MANDOCERR_ARG_SKIP, 1247ecb10c32Sschwarze mdoc->parse, nit->line, nit->pos, 1248ecb10c32Sschwarze "It %s", nit->head->child->string); 1249f73abda9Skristaps break; 125049aff9f8Sschwarze case LIST_column: 12519530682eSschwarze cols = (int)nbl->norm->Bl.ncols; 12526093755cSschwarze 12539530682eSschwarze assert(NULL == nit->head->child); 12546093755cSschwarze 12559530682eSschwarze for (i = 0, nch = nit->child; nch; nch = nch->next) 12569530682eSschwarze if (MDOC_BODY == nch->type) 1257f73abda9Skristaps i++; 125853292e81Sschwarze 1259e14c4c11Sschwarze if (i < cols || i > cols + 1) 1260e14c4c11Sschwarze mandoc_vmsg(MANDOCERR_ARGCOUNT, 1261e14c4c11Sschwarze mdoc->parse, nit->line, nit->pos, 12626e03d529Sschwarze "columns == %d (have %d)", cols, i); 1263e14c4c11Sschwarze break; 1264f73abda9Skristaps default: 126566788495Sschwarze abort(); 1266f73abda9Skristaps } 1267f73abda9Skristaps 1268f73abda9Skristaps return(1); 1269f73abda9Skristaps } 1270f73abda9Skristaps 127120fa2881Sschwarze static int 127220fa2881Sschwarze post_bl_block(POST_ARGS) 127320fa2881Sschwarze { 1274bb99f0faSschwarze struct mdoc_node *n, *ni, *nc; 127520fa2881Sschwarze 127620fa2881Sschwarze /* 127720fa2881Sschwarze * These are fairly complicated, so we've broken them into two 127820fa2881Sschwarze * functions. post_bl_block_tag() is called when a -tag is 127920fa2881Sschwarze * specified, but no -width (it must be guessed). The second 128020fa2881Sschwarze * when a -width is specified (macro indicators must be 128120fa2881Sschwarze * rewritten into real lengths). 128220fa2881Sschwarze */ 128320fa2881Sschwarze 128420fa2881Sschwarze n = mdoc->last; 128520fa2881Sschwarze 12868c62fbf5Sschwarze if (LIST_tag == n->norm->Bl.type && 12878c62fbf5Sschwarze NULL == n->norm->Bl.width) { 128820fa2881Sschwarze if ( ! post_bl_block_tag(mdoc)) 128920fa2881Sschwarze return(0); 1290bb99f0faSschwarze assert(n->norm->Bl.width); 12918c62fbf5Sschwarze } else if (NULL != n->norm->Bl.width) { 129220fa2881Sschwarze if ( ! post_bl_block_width(mdoc)) 129320fa2881Sschwarze return(0); 12948c62fbf5Sschwarze assert(n->norm->Bl.width); 1295bb99f0faSschwarze } 1296bb99f0faSschwarze 1297bb99f0faSschwarze for (ni = n->body->child; ni; ni = ni->next) { 1298bb99f0faSschwarze if (NULL == ni->body) 1299bb99f0faSschwarze continue; 1300bb99f0faSschwarze nc = ni->body->last; 1301bb99f0faSschwarze while (NULL != nc) { 1302bb99f0faSschwarze switch (nc->tok) { 130349aff9f8Sschwarze case MDOC_Pp: 1304bb99f0faSschwarze /* FALLTHROUGH */ 130549aff9f8Sschwarze case MDOC_Lp: 1306bb99f0faSschwarze /* FALLTHROUGH */ 130749aff9f8Sschwarze case MDOC_br: 1308bb99f0faSschwarze break; 1309bb99f0faSschwarze default: 1310bb99f0faSschwarze nc = NULL; 1311bb99f0faSschwarze continue; 1312bb99f0faSschwarze } 1313bb99f0faSschwarze if (NULL == ni->next) { 131420369664Sschwarze mandoc_msg(MANDOCERR_PAR_MOVE, 131520369664Sschwarze mdoc->parse, nc->line, nc->pos, 131620369664Sschwarze mdoc_macronames[nc->tok]); 1317bb99f0faSschwarze if ( ! mdoc_node_relink(mdoc, nc)) 1318bb99f0faSschwarze return(0); 1319bb99f0faSschwarze } else if (0 == n->norm->Bl.comp && 1320bb99f0faSschwarze LIST_column != n->norm->Bl.type) { 132120369664Sschwarze mandoc_vmsg(MANDOCERR_PAR_SKIP, 132220369664Sschwarze mdoc->parse, nc->line, nc->pos, 132320369664Sschwarze "%s before It", 132420369664Sschwarze mdoc_macronames[nc->tok]); 1325bb99f0faSschwarze mdoc_node_delete(mdoc, nc); 1326bb99f0faSschwarze } else 1327bb99f0faSschwarze break; 1328bb99f0faSschwarze nc = ni->body->last; 1329bb99f0faSschwarze } 1330bb99f0faSschwarze } 133120fa2881Sschwarze return(1); 133220fa2881Sschwarze } 133320fa2881Sschwarze 133420fa2881Sschwarze static int 133520fa2881Sschwarze post_bl_block_width(POST_ARGS) 133620fa2881Sschwarze { 133720fa2881Sschwarze size_t width; 133820fa2881Sschwarze int i; 133920fa2881Sschwarze enum mdoct tok; 134020fa2881Sschwarze struct mdoc_node *n; 134147813146Sschwarze char buf[24]; 134220fa2881Sschwarze 134320fa2881Sschwarze n = mdoc->last; 134420fa2881Sschwarze 134520fa2881Sschwarze /* 134620fa2881Sschwarze * Calculate the real width of a list from the -width string, 134720fa2881Sschwarze * which may contain a macro (with a known default width), a 134820fa2881Sschwarze * literal string, or a scaling width. 134920fa2881Sschwarze * 135020fa2881Sschwarze * If the value to -width is a macro, then we re-write it to be 135120fa2881Sschwarze * the macro's width as set in share/tmac/mdoc/doc-common. 135220fa2881Sschwarze */ 135320fa2881Sschwarze 13548c62fbf5Sschwarze if (0 == strcmp(n->norm->Bl.width, "Ds")) 135520fa2881Sschwarze width = 6; 13568c62fbf5Sschwarze else if (MDOC_MAX == (tok = mdoc_hash_find(n->norm->Bl.width))) 135720fa2881Sschwarze return(1); 1358dc0d8bb2Sschwarze else 1359dc0d8bb2Sschwarze width = macro2len(tok); 136020fa2881Sschwarze 136120fa2881Sschwarze /* The value already exists: free and reallocate it. */ 136220fa2881Sschwarze 136320fa2881Sschwarze assert(n->args); 136420fa2881Sschwarze 136520fa2881Sschwarze for (i = 0; i < (int)n->args->argc; i++) 136620fa2881Sschwarze if (MDOC_Width == n->args->argv[i].arg) 136720fa2881Sschwarze break; 136820fa2881Sschwarze 136920fa2881Sschwarze assert(i < (int)n->args->argc); 137020fa2881Sschwarze 137147813146Sschwarze (void)snprintf(buf, sizeof(buf), "%un", (unsigned int)width); 137220fa2881Sschwarze free(n->args->argv[i].value[0]); 137320fa2881Sschwarze n->args->argv[i].value[0] = mandoc_strdup(buf); 137420fa2881Sschwarze 137520fa2881Sschwarze /* Set our width! */ 13768c62fbf5Sschwarze n->norm->Bl.width = n->args->argv[i].value[0]; 137720fa2881Sschwarze return(1); 137820fa2881Sschwarze } 137920fa2881Sschwarze 138020fa2881Sschwarze static int 138120fa2881Sschwarze post_bl_block_tag(POST_ARGS) 138220fa2881Sschwarze { 138320fa2881Sschwarze struct mdoc_node *n, *nn; 138420fa2881Sschwarze size_t sz, ssz; 138520fa2881Sschwarze int i; 138647813146Sschwarze char buf[24]; 138720fa2881Sschwarze 138820fa2881Sschwarze /* 138920fa2881Sschwarze * Calculate the -width for a `Bl -tag' list if it hasn't been 139020fa2881Sschwarze * provided. Uses the first head macro. NOTE AGAIN: this is 139120fa2881Sschwarze * ONLY if the -width argument has NOT been provided. See 139220fa2881Sschwarze * post_bl_block_width() for converting the -width string. 139320fa2881Sschwarze */ 139420fa2881Sschwarze 139520fa2881Sschwarze sz = 10; 139620fa2881Sschwarze n = mdoc->last; 139720fa2881Sschwarze 139820fa2881Sschwarze for (nn = n->body->child; nn; nn = nn->next) { 139920fa2881Sschwarze if (MDOC_It != nn->tok) 140020fa2881Sschwarze continue; 140120fa2881Sschwarze 140220fa2881Sschwarze assert(MDOC_BLOCK == nn->type); 140320fa2881Sschwarze nn = nn->head->child; 140420fa2881Sschwarze 140520fa2881Sschwarze if (nn == NULL) 140620fa2881Sschwarze break; 140720fa2881Sschwarze 140820fa2881Sschwarze if (MDOC_TEXT == nn->type) { 140920fa2881Sschwarze sz = strlen(nn->string) + 1; 141020fa2881Sschwarze break; 141120fa2881Sschwarze } 141220fa2881Sschwarze 141319a69263Sschwarze if (0 != (ssz = macro2len(nn->tok))) 141420fa2881Sschwarze sz = ssz; 141520fa2881Sschwarze 141620fa2881Sschwarze break; 141720fa2881Sschwarze } 141820fa2881Sschwarze 141920fa2881Sschwarze /* Defaults to ten ens. */ 142020fa2881Sschwarze 142147813146Sschwarze (void)snprintf(buf, sizeof(buf), "%un", (unsigned int)sz); 142220fa2881Sschwarze 142320fa2881Sschwarze /* 142420fa2881Sschwarze * We have to dynamically add this to the macro's argument list. 142520fa2881Sschwarze * We're guaranteed that a MDOC_Width doesn't already exist. 142620fa2881Sschwarze */ 142720fa2881Sschwarze 142820fa2881Sschwarze assert(n->args); 142920fa2881Sschwarze i = (int)(n->args->argc)++; 143020fa2881Sschwarze 14318286bf36Sschwarze n->args->argv = mandoc_reallocarray(n->args->argv, 14328286bf36Sschwarze n->args->argc, sizeof(struct mdoc_argv)); 143320fa2881Sschwarze 143420fa2881Sschwarze n->args->argv[i].arg = MDOC_Width; 143520fa2881Sschwarze n->args->argv[i].line = n->line; 143620fa2881Sschwarze n->args->argv[i].pos = n->pos; 143720fa2881Sschwarze n->args->argv[i].sz = 1; 143820fa2881Sschwarze n->args->argv[i].value = mandoc_malloc(sizeof(char *)); 143920fa2881Sschwarze n->args->argv[i].value[0] = mandoc_strdup(buf); 144020fa2881Sschwarze 144120fa2881Sschwarze /* Set our width! */ 14428c62fbf5Sschwarze n->norm->Bl.width = n->args->argv[i].value[0]; 144320fa2881Sschwarze return(1); 144420fa2881Sschwarze } 144520fa2881Sschwarze 1446f73abda9Skristaps static int 1447395185ccSschwarze post_bl_head(POST_ARGS) 1448395185ccSschwarze { 144920fa2881Sschwarze struct mdoc_node *np, *nn, *nnp; 1450*f5174743Sschwarze struct mdoc_argv *argv; 145120fa2881Sschwarze int i, j; 1452395185ccSschwarze 14538c62fbf5Sschwarze if (LIST_column != mdoc->last->norm->Bl.type) 145420fa2881Sschwarze /* FIXME: this should be ERROR class... */ 145520fa2881Sschwarze return(hwarn_eq0(mdoc)); 1456395185ccSschwarze 145720fa2881Sschwarze /* 1458*f5174743Sschwarze * Append old-style lists, where the column width specifiers 145920fa2881Sschwarze * trail as macro parameters, to the new-style ("normal-form") 146020fa2881Sschwarze * lists where they're argument values following -column. 146120fa2881Sschwarze */ 146220fa2881Sschwarze 1463*f5174743Sschwarze if (mdoc->last->child == NULL) 146420fa2881Sschwarze return(1); 146520fa2881Sschwarze 146620fa2881Sschwarze np = mdoc->last->parent; 146720fa2881Sschwarze assert(np->args); 146820fa2881Sschwarze 146920fa2881Sschwarze for (j = 0; j < (int)np->args->argc; j++) 147020fa2881Sschwarze if (MDOC_Column == np->args->argv[j].arg) 147120fa2881Sschwarze break; 147220fa2881Sschwarze 147320fa2881Sschwarze assert(j < (int)np->args->argc); 147420fa2881Sschwarze 147520fa2881Sschwarze /* 1476a5e11edeSschwarze * Accommodate for new-style groff column syntax. Shuffle the 147720fa2881Sschwarze * child nodes, all of which must be TEXT, as arguments for the 147820fa2881Sschwarze * column field. Then, delete the head children. 147920fa2881Sschwarze */ 148020fa2881Sschwarze 1481*f5174743Sschwarze argv = np->args->argv + j; 1482*f5174743Sschwarze i = argv->sz; 1483*f5174743Sschwarze argv->sz += mdoc->last->nchild; 1484*f5174743Sschwarze argv->value = mandoc_reallocarray(argv->value, 1485*f5174743Sschwarze argv->sz, sizeof(char *)); 148620fa2881Sschwarze 1487*f5174743Sschwarze mdoc->last->norm->Bl.ncols = argv->sz; 1488*f5174743Sschwarze mdoc->last->norm->Bl.cols = (void *)argv->value; 148920fa2881Sschwarze 1490*f5174743Sschwarze for (nn = mdoc->last->child; nn; i++) { 1491*f5174743Sschwarze argv->value[i] = nn->string; 149220fa2881Sschwarze nn->string = NULL; 149320fa2881Sschwarze nnp = nn; 149420fa2881Sschwarze nn = nn->next; 149520fa2881Sschwarze mdoc_node_delete(NULL, nnp); 1496395185ccSschwarze } 149720fa2881Sschwarze 149820fa2881Sschwarze mdoc->last->nchild = 0; 149920fa2881Sschwarze mdoc->last->child = NULL; 150020fa2881Sschwarze 15016093755cSschwarze return(1); 1502b16e7ddfSschwarze } 1503b16e7ddfSschwarze 1504395185ccSschwarze static int 1505f73abda9Skristaps post_bl(POST_ARGS) 1506f73abda9Skristaps { 15072a427d60Sschwarze struct mdoc_node *nparent, *nprev; /* of the Bl block */ 15082a427d60Sschwarze struct mdoc_node *nblock, *nbody; /* of the Bl */ 15092a427d60Sschwarze struct mdoc_node *nchild, *nnext; /* of the Bl body */ 1510f73abda9Skristaps 15112a427d60Sschwarze nbody = mdoc->last; 15122a427d60Sschwarze switch (nbody->type) { 151349aff9f8Sschwarze case MDOC_BLOCK: 151420fa2881Sschwarze return(post_bl_block(mdoc)); 151549aff9f8Sschwarze case MDOC_HEAD: 15162a427d60Sschwarze return(post_bl_head(mdoc)); 151749aff9f8Sschwarze case MDOC_BODY: 1518f6127a73Sschwarze break; 15192a427d60Sschwarze default: 15202a427d60Sschwarze return(1); 1521f6127a73Sschwarze } 1522f6127a73Sschwarze 15232a427d60Sschwarze nchild = nbody->child; 15242a427d60Sschwarze while (NULL != nchild) { 15252a427d60Sschwarze if (MDOC_It == nchild->tok || MDOC_Sm == nchild->tok) { 15262a427d60Sschwarze nchild = nchild->next; 15272a427d60Sschwarze continue; 15282a427d60Sschwarze } 15292a427d60Sschwarze 1530dd25b57cSschwarze mandoc_msg(MANDOCERR_BL_MOVE, mdoc->parse, 1531dd25b57cSschwarze nchild->line, nchild->pos, 1532dd25b57cSschwarze mdoc_macronames[nchild->tok]); 15332a427d60Sschwarze 15342a427d60Sschwarze /* 15352a427d60Sschwarze * Move the node out of the Bl block. 15362a427d60Sschwarze * First, collect all required node pointers. 15372a427d60Sschwarze */ 15382a427d60Sschwarze 15392a427d60Sschwarze nblock = nbody->parent; 15402a427d60Sschwarze nprev = nblock->prev; 15412a427d60Sschwarze nparent = nblock->parent; 15422a427d60Sschwarze nnext = nchild->next; 15432a427d60Sschwarze 15442a427d60Sschwarze /* 15452a427d60Sschwarze * Unlink this child. 15462a427d60Sschwarze */ 15472a427d60Sschwarze 15482a427d60Sschwarze assert(NULL == nchild->prev); 15492a427d60Sschwarze if (0 == --nbody->nchild) { 15502a427d60Sschwarze nbody->child = NULL; 15512a427d60Sschwarze nbody->last = NULL; 15522a427d60Sschwarze assert(NULL == nnext); 15532a427d60Sschwarze } else { 15542a427d60Sschwarze nbody->child = nnext; 15552a427d60Sschwarze nnext->prev = NULL; 15562a427d60Sschwarze } 15572a427d60Sschwarze 15582a427d60Sschwarze /* 15592a427d60Sschwarze * Relink this child. 15602a427d60Sschwarze */ 15612a427d60Sschwarze 15622a427d60Sschwarze nchild->parent = nparent; 15632a427d60Sschwarze nchild->prev = nprev; 15642a427d60Sschwarze nchild->next = nblock; 15652a427d60Sschwarze 15662a427d60Sschwarze nblock->prev = nchild; 15672a427d60Sschwarze nparent->nchild++; 15682a427d60Sschwarze if (NULL == nprev) 15692a427d60Sschwarze nparent->child = nchild; 15702a427d60Sschwarze else 15712a427d60Sschwarze nprev->next = nchild; 15722a427d60Sschwarze 15732a427d60Sschwarze nchild = nnext; 1574f73abda9Skristaps } 1575f73abda9Skristaps 1576f73abda9Skristaps return(1); 1577f73abda9Skristaps } 1578f73abda9Skristaps 1579f73abda9Skristaps static int 1580f73abda9Skristaps ebool(struct mdoc *mdoc) 1581f73abda9Skristaps { 1582dc0d8bb2Sschwarze struct mdoc_node *nch; 1583dc0d8bb2Sschwarze enum mdoct tok; 1584f73abda9Skristaps 1585dc0d8bb2Sschwarze tok = mdoc->last->tok; 1586dc0d8bb2Sschwarze nch = mdoc->last->child; 1587dc0d8bb2Sschwarze 1588dc0d8bb2Sschwarze if (NULL == nch) { 1589dc0d8bb2Sschwarze if (MDOC_Sm == tok) 1590f9e7bf99Sschwarze mdoc->flags ^= MDOC_SMOFF; 1591f73abda9Skristaps return(1); 1592bb648afaSschwarze } 1593f9e7bf99Sschwarze 1594f9e7bf99Sschwarze check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_LT, 2); 1595f73abda9Skristaps 1596dc0d8bb2Sschwarze assert(MDOC_TEXT == nch->type); 159720fa2881Sschwarze 1598dc0d8bb2Sschwarze if (0 == strcmp(nch->string, "on")) { 1599dc0d8bb2Sschwarze if (MDOC_Sm == tok) 1600ec2beb53Sschwarze mdoc->flags &= ~MDOC_SMOFF; 160120fa2881Sschwarze return(1); 1602ec2beb53Sschwarze } 1603dc0d8bb2Sschwarze if (0 == strcmp(nch->string, "off")) { 1604dc0d8bb2Sschwarze if (MDOC_Sm == tok) 1605ec2beb53Sschwarze mdoc->flags |= MDOC_SMOFF; 160620fa2881Sschwarze return(1); 1607ec2beb53Sschwarze } 160820fa2881Sschwarze 1609dc0d8bb2Sschwarze mandoc_vmsg(MANDOCERR_SM_BAD, 1610dc0d8bb2Sschwarze mdoc->parse, nch->line, nch->pos, 1611dc0d8bb2Sschwarze "%s %s", mdoc_macronames[tok], nch->string); 1612dc0d8bb2Sschwarze return(mdoc_node_relink(mdoc, nch)); 161320fa2881Sschwarze } 1614f73abda9Skristaps 1615f73abda9Skristaps static int 1616f73abda9Skristaps post_root(POST_ARGS) 1617f73abda9Skristaps { 161820fa2881Sschwarze struct mdoc_node *n; 1619f73abda9Skristaps 1620ac1f49d0Sschwarze /* Add missing prologue data. */ 162120fa2881Sschwarze 162220fa2881Sschwarze if ( ! (MDOC_PBODY & mdoc->flags)) { 1623ac1f49d0Sschwarze mandoc_msg(MANDOCERR_PROLOG_BAD, mdoc->parse, 0, 0, "EOF"); 1624ac1f49d0Sschwarze if (mdoc->meta.date == NULL) 1625ac1f49d0Sschwarze mdoc->meta.date = mdoc->quick ? 1626ac1f49d0Sschwarze mandoc_strdup("") : 1627ac1f49d0Sschwarze mandoc_normdate(mdoc->parse, NULL, 0, 0); 1628ac1f49d0Sschwarze if (mdoc->meta.title == NULL) 1629ac1f49d0Sschwarze mdoc->meta.title = mandoc_strdup("UNKNOWN"); 1630ac1f49d0Sschwarze if (mdoc->meta.vol == NULL) 1631ac1f49d0Sschwarze mdoc->meta.vol = mandoc_strdup("LOCAL"); 1632ac1f49d0Sschwarze if (mdoc->meta.arch == NULL) 1633ac1f49d0Sschwarze mdoc->meta.msec = mandoc_strdup("1"); 1634ac1f49d0Sschwarze if (mdoc->meta.os == NULL) 1635ac1f49d0Sschwarze mdoc->meta.os = mandoc_strdup("UNKNOWN"); 1636f73abda9Skristaps } 1637f73abda9Skristaps 163820fa2881Sschwarze n = mdoc->first; 163920fa2881Sschwarze assert(n); 164020fa2881Sschwarze 164120fa2881Sschwarze /* Check that we begin with a proper `Sh'. */ 164220fa2881Sschwarze 164343edbcc8Sschwarze if (NULL == n->child) 164443edbcc8Sschwarze mdoc_nmsg(mdoc, n, MANDOCERR_DOC_EMPTY); 164551fcab2fSschwarze else if (MDOC_Sh != n->child->tok) 164651fcab2fSschwarze mandoc_msg(MANDOCERR_SEC_BEFORE, mdoc->parse, 164751fcab2fSschwarze n->child->line, n->child->pos, 164851fcab2fSschwarze mdoc_macronames[n->child->tok]); 164920fa2881Sschwarze 1650ac1f49d0Sschwarze return(1); 165120fa2881Sschwarze } 1652f73abda9Skristaps 1653f73abda9Skristaps static int 1654f73abda9Skristaps post_st(POST_ARGS) 1655f73abda9Skristaps { 1656dc0d8bb2Sschwarze struct mdoc_node *n, *nch; 165720fa2881Sschwarze const char *p; 1658f73abda9Skristaps 1659dc0d8bb2Sschwarze n = mdoc->last; 1660dc0d8bb2Sschwarze nch = n->child; 1661dc0d8bb2Sschwarze 1662dc0d8bb2Sschwarze if (NULL == nch) { 1663307e5a07Sschwarze mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse, 1664dc0d8bb2Sschwarze n->line, n->pos, mdoc_macronames[n->tok]); 1665dc0d8bb2Sschwarze mdoc_node_delete(mdoc, n); 1666bb648afaSschwarze return(1); 1667bb648afaSschwarze } 166820fa2881Sschwarze 1669dc0d8bb2Sschwarze assert(MDOC_TEXT == nch->type); 167020fa2881Sschwarze 1671dc0d8bb2Sschwarze if (NULL == (p = mdoc_a2st(nch->string))) { 1672dc0d8bb2Sschwarze mandoc_msg(MANDOCERR_ST_BAD, mdoc->parse, 1673dc0d8bb2Sschwarze nch->line, nch->pos, nch->string); 1674dc0d8bb2Sschwarze mdoc_node_delete(mdoc, n); 167520fa2881Sschwarze } else { 1676dc0d8bb2Sschwarze free(nch->string); 1677dc0d8bb2Sschwarze nch->string = mandoc_strdup(p); 1678f73abda9Skristaps } 1679f73abda9Skristaps 168020fa2881Sschwarze return(1); 168120fa2881Sschwarze } 1682f73abda9Skristaps 1683f73abda9Skristaps static int 1684011fe33bSschwarze post_rs(POST_ARGS) 1685011fe33bSschwarze { 168620fa2881Sschwarze struct mdoc_node *nn, *next, *prev; 168720fa2881Sschwarze int i, j; 1688011fe33bSschwarze 1689bb648afaSschwarze switch (mdoc->last->type) { 169049aff9f8Sschwarze case MDOC_HEAD: 1691bb648afaSschwarze check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_EQ, 0); 1692011fe33bSschwarze return(1); 169349aff9f8Sschwarze case MDOC_BODY: 1694bb648afaSschwarze if (mdoc->last->child) 1695bb648afaSschwarze break; 1696bb648afaSschwarze check_count(mdoc, MDOC_BODY, CHECK_WARN, CHECK_GT, 0); 1697bb648afaSschwarze return(1); 1698bb648afaSschwarze default: 1699bb648afaSschwarze return(1); 1700bb648afaSschwarze } 1701011fe33bSschwarze 170220fa2881Sschwarze /* 170320fa2881Sschwarze * The full `Rs' block needs special handling to order the 170420fa2881Sschwarze * sub-elements according to `rsord'. Pick through each element 1705b538baa5Sschwarze * and correctly order it. This is an insertion sort. 170620fa2881Sschwarze */ 170720fa2881Sschwarze 170820fa2881Sschwarze next = NULL; 170920fa2881Sschwarze for (nn = mdoc->last->child->next; nn; nn = next) { 171020fa2881Sschwarze /* Determine order of `nn'. */ 171120fa2881Sschwarze for (i = 0; i < RSORD_MAX; i++) 171220fa2881Sschwarze if (rsord[i] == nn->tok) 171320fa2881Sschwarze break; 171420fa2881Sschwarze 1715b538baa5Sschwarze if (i == RSORD_MAX) { 1716b538baa5Sschwarze mandoc_msg(MANDOCERR_RS_BAD, 1717b538baa5Sschwarze mdoc->parse, nn->line, nn->pos, 1718b538baa5Sschwarze mdoc_macronames[nn->tok]); 1719b538baa5Sschwarze i = -1; 1720b538baa5Sschwarze } else if (MDOC__J == nn->tok || MDOC__B == nn->tok) 1721b538baa5Sschwarze mdoc->last->norm->Rs.quote_T++; 1722b538baa5Sschwarze 172320fa2881Sschwarze /* 172420fa2881Sschwarze * Remove `nn' from the chain. This somewhat 172520fa2881Sschwarze * repeats mdoc_node_unlink(), but since we're 172620fa2881Sschwarze * just re-ordering, there's no need for the 172720fa2881Sschwarze * full unlink process. 172820fa2881Sschwarze */ 172920fa2881Sschwarze 173020fa2881Sschwarze if (NULL != (next = nn->next)) 173120fa2881Sschwarze next->prev = nn->prev; 173220fa2881Sschwarze 173320fa2881Sschwarze if (NULL != (prev = nn->prev)) 173420fa2881Sschwarze prev->next = nn->next; 173520fa2881Sschwarze 173620fa2881Sschwarze nn->prev = nn->next = NULL; 173720fa2881Sschwarze 173820fa2881Sschwarze /* 173920fa2881Sschwarze * Scan back until we reach a node that's 174020fa2881Sschwarze * ordered before `nn'. 174120fa2881Sschwarze */ 174220fa2881Sschwarze 174320fa2881Sschwarze for ( ; prev ; prev = prev->prev) { 174420fa2881Sschwarze /* Determine order of `prev'. */ 174520fa2881Sschwarze for (j = 0; j < RSORD_MAX; j++) 174620fa2881Sschwarze if (rsord[j] == prev->tok) 174720fa2881Sschwarze break; 1748b538baa5Sschwarze if (j == RSORD_MAX) 1749b538baa5Sschwarze j = -1; 175020fa2881Sschwarze 175120fa2881Sschwarze if (j <= i) 175220fa2881Sschwarze break; 175320fa2881Sschwarze } 175420fa2881Sschwarze 175520fa2881Sschwarze /* 175620fa2881Sschwarze * Set `nn' back into its correct place in front 175720fa2881Sschwarze * of the `prev' node. 175820fa2881Sschwarze */ 175920fa2881Sschwarze 176020fa2881Sschwarze nn->prev = prev; 176120fa2881Sschwarze 176220fa2881Sschwarze if (prev) { 176320fa2881Sschwarze if (prev->next) 176420fa2881Sschwarze prev->next->prev = nn; 176520fa2881Sschwarze nn->next = prev->next; 176620fa2881Sschwarze prev->next = nn; 176720fa2881Sschwarze } else { 176820fa2881Sschwarze mdoc->last->child->prev = nn; 176920fa2881Sschwarze nn->next = mdoc->last->child; 177020fa2881Sschwarze mdoc->last->child = nn; 177120fa2881Sschwarze } 1772011fe33bSschwarze } 1773011fe33bSschwarze 1774011fe33bSschwarze return(1); 1775011fe33bSschwarze } 1776011fe33bSschwarze 17774039b21cSschwarze /* 17784039b21cSschwarze * For some arguments of some macros, 17794039b21cSschwarze * convert all breakable hyphens into ASCII_HYPH. 17804039b21cSschwarze */ 17814039b21cSschwarze static int 17824039b21cSschwarze post_hyph(POST_ARGS) 17834039b21cSschwarze { 17844039b21cSschwarze struct mdoc_node *n, *nch; 17854039b21cSschwarze char *cp; 17864039b21cSschwarze 17874039b21cSschwarze n = mdoc->last; 17884039b21cSschwarze switch (n->type) { 178949aff9f8Sschwarze case MDOC_HEAD: 17904039b21cSschwarze if (MDOC_Sh == n->tok || MDOC_Ss == n->tok) 17914039b21cSschwarze break; 17924039b21cSschwarze return(1); 179349aff9f8Sschwarze case MDOC_BODY: 17944039b21cSschwarze if (MDOC_D1 == n->tok || MDOC_Nd == n->tok) 17954039b21cSschwarze break; 17964039b21cSschwarze return(1); 179749aff9f8Sschwarze case MDOC_ELEM: 17984039b21cSschwarze break; 17994039b21cSschwarze default: 18004039b21cSschwarze return(1); 18014039b21cSschwarze } 18024039b21cSschwarze 18034039b21cSschwarze for (nch = n->child; nch; nch = nch->next) { 18044039b21cSschwarze if (MDOC_TEXT != nch->type) 18054039b21cSschwarze continue; 18064039b21cSschwarze cp = nch->string; 1807b7e2b14eSschwarze if ('\0' == *cp) 18084039b21cSschwarze continue; 18094039b21cSschwarze while ('\0' != *(++cp)) 18104039b21cSschwarze if ('-' == *cp && 18114039b21cSschwarze isalpha((unsigned char)cp[-1]) && 18124039b21cSschwarze isalpha((unsigned char)cp[1])) 18134039b21cSschwarze *cp = ASCII_HYPH; 18144039b21cSschwarze } 18154039b21cSschwarze return(1); 18164039b21cSschwarze } 18174039b21cSschwarze 1818011fe33bSschwarze static int 1819af216717Sschwarze post_ns(POST_ARGS) 1820af216717Sschwarze { 1821af216717Sschwarze 1822af216717Sschwarze if (MDOC_LINE & mdoc->last->flags) 1823b723eac2Sschwarze mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NS_SKIP); 1824af216717Sschwarze return(1); 1825af216717Sschwarze } 1826af216717Sschwarze 1827af216717Sschwarze static int 1828f73abda9Skristaps post_sh(POST_ARGS) 1829f73abda9Skristaps { 1830f73abda9Skristaps 1831f73abda9Skristaps if (MDOC_HEAD == mdoc->last->type) 1832f73abda9Skristaps return(post_sh_head(mdoc)); 1833f73abda9Skristaps if (MDOC_BODY == mdoc->last->type) 1834f73abda9Skristaps return(post_sh_body(mdoc)); 1835f73abda9Skristaps 1836f73abda9Skristaps return(1); 1837f73abda9Skristaps } 1838f73abda9Skristaps 1839f73abda9Skristaps static int 1840f73abda9Skristaps post_sh_body(POST_ARGS) 1841f73abda9Skristaps { 1842f73abda9Skristaps struct mdoc_node *n; 1843f73abda9Skristaps 1844f8c9d6f2Sschwarze if (SEC_NAME != mdoc->lastsec) 1845f73abda9Skristaps return(1); 1846f73abda9Skristaps 1847f73abda9Skristaps /* 1848f73abda9Skristaps * Warn if the NAME section doesn't contain the `Nm' and `Nd' 1849f73abda9Skristaps * macros (can have multiple `Nm' and one `Nd'). Note that the 1850f73abda9Skristaps * children of the BODY declaration can also be "text". 1851f73abda9Skristaps */ 1852f73abda9Skristaps 185320fa2881Sschwarze if (NULL == (n = mdoc->last->child)) { 185451fcab2fSschwarze mandoc_msg(MANDOCERR_NAMESEC_BAD, mdoc->parse, 185551fcab2fSschwarze mdoc->last->line, mdoc->last->pos, "empty"); 185620fa2881Sschwarze return(1); 185720fa2881Sschwarze } 1858f73abda9Skristaps 1859f73abda9Skristaps for ( ; n && n->next; n = n->next) { 1860f73abda9Skristaps if (MDOC_ELEM == n->type && MDOC_Nm == n->tok) 1861f73abda9Skristaps continue; 1862f73abda9Skristaps if (MDOC_TEXT == n->type) 1863f73abda9Skristaps continue; 186451fcab2fSschwarze mandoc_msg(MANDOCERR_NAMESEC_BAD, mdoc->parse, 186551fcab2fSschwarze n->line, n->pos, mdoc_macronames[n->tok]); 1866f73abda9Skristaps } 1867f73abda9Skristaps 186849d529b5Sschwarze assert(n); 18694602e85cSschwarze if (MDOC_BLOCK == n->type && MDOC_Nd == n->tok) 1870f73abda9Skristaps return(1); 1871f73abda9Skristaps 187251fcab2fSschwarze mandoc_msg(MANDOCERR_NAMESEC_BAD, mdoc->parse, 187351fcab2fSschwarze n->line, n->pos, mdoc_macronames[n->tok]); 187420fa2881Sschwarze return(1); 187520fa2881Sschwarze } 1876f73abda9Skristaps 1877f73abda9Skristaps static int 1878f73abda9Skristaps post_sh_head(POST_ARGS) 1879f73abda9Skristaps { 1880a2cff342Sschwarze struct mdoc_node *n; 188151fcab2fSschwarze const char *goodsec; 188246133849Sschwarze char *secname; 1883f73abda9Skristaps enum mdoc_sec sec; 1884f73abda9Skristaps 1885f73abda9Skristaps /* 1886f73abda9Skristaps * Process a new section. Sections are either "named" or 188720fa2881Sschwarze * "custom". Custom sections are user-defined, while named ones 188820fa2881Sschwarze * follow a conventional order and may only appear in certain 188920fa2881Sschwarze * manual sections. 1890f73abda9Skristaps */ 1891f73abda9Skristaps 189283af2bccSschwarze secname = NULL; 189304e980cbSschwarze sec = SEC_CUSTOM; 189446133849Sschwarze mdoc_deroff(&secname, mdoc->last); 189546133849Sschwarze sec = NULL == secname ? SEC_CUSTOM : a2sec(secname); 1896f73abda9Skristaps 189720fa2881Sschwarze /* The NAME should be first. */ 1898f73abda9Skristaps 1899fccfce9dSschwarze if (SEC_NAME != sec && SEC_NONE == mdoc->lastnamed) 190051fcab2fSschwarze mandoc_msg(MANDOCERR_NAMESEC_FIRST, mdoc->parse, 190151fcab2fSschwarze mdoc->last->line, mdoc->last->pos, secname); 190220fa2881Sschwarze 190320fa2881Sschwarze /* The SYNOPSIS gets special attention in other areas. */ 190420fa2881Sschwarze 190522881299Sschwarze if (SEC_SYNOPSIS == sec) { 190675088a49Sschwarze roff_setreg(mdoc->roff, "nS", 1, '='); 190720fa2881Sschwarze mdoc->flags |= MDOC_SYNOPSIS; 190822881299Sschwarze } else { 190975088a49Sschwarze roff_setreg(mdoc->roff, "nS", 0, '='); 191020fa2881Sschwarze mdoc->flags &= ~MDOC_SYNOPSIS; 191122881299Sschwarze } 191220fa2881Sschwarze 191320fa2881Sschwarze /* Mark our last section. */ 191420fa2881Sschwarze 191520fa2881Sschwarze mdoc->lastsec = sec; 19161eccdf28Sschwarze 19171eccdf28Sschwarze /* 19181eccdf28Sschwarze * Set the section attribute for the current HEAD, for its 19191eccdf28Sschwarze * parent BLOCK, and for the HEAD children; the latter can 19201eccdf28Sschwarze * only be TEXT nodes, so no recursion is needed. 19211eccdf28Sschwarze * For other blocks and elements, including .Sh BODY, this is 19221eccdf28Sschwarze * done when allocating the node data structures, but for .Sh 19231eccdf28Sschwarze * BLOCK and HEAD, the section is still unknown at that time. 19241eccdf28Sschwarze */ 19251eccdf28Sschwarze 1926a2cff342Sschwarze mdoc->last->parent->sec = sec; 1927a2cff342Sschwarze mdoc->last->sec = sec; 1928a2cff342Sschwarze for (n = mdoc->last->child; n; n = n->next) 1929a2cff342Sschwarze n->sec = sec; 193020fa2881Sschwarze 193120fa2881Sschwarze /* We don't care about custom sections after this. */ 1932fccfce9dSschwarze 193346133849Sschwarze if (SEC_CUSTOM == sec) { 193446133849Sschwarze free(secname); 1935f73abda9Skristaps return(1); 193646133849Sschwarze } 1937fccfce9dSschwarze 19386be99f77Sschwarze /* 193920fa2881Sschwarze * Check whether our non-custom section is being repeated or is 194020fa2881Sschwarze * out of order. 19416be99f77Sschwarze */ 1942f73abda9Skristaps 194320fa2881Sschwarze if (sec == mdoc->lastnamed) 194451fcab2fSschwarze mandoc_msg(MANDOCERR_SEC_REP, mdoc->parse, 194551fcab2fSschwarze mdoc->last->line, mdoc->last->pos, secname); 194620fa2881Sschwarze 194720fa2881Sschwarze if (sec < mdoc->lastnamed) 194851fcab2fSschwarze mandoc_msg(MANDOCERR_SEC_ORDER, mdoc->parse, 194951fcab2fSschwarze mdoc->last->line, mdoc->last->pos, secname); 195020fa2881Sschwarze 195120fa2881Sschwarze /* Mark the last named section. */ 195220fa2881Sschwarze 195320fa2881Sschwarze mdoc->lastnamed = sec; 195420fa2881Sschwarze 195520fa2881Sschwarze /* Check particular section/manual conventions. */ 195620fa2881Sschwarze 195792c0ca7fSschwarze assert(mdoc->meta.msec); 195820fa2881Sschwarze 195951fcab2fSschwarze goodsec = NULL; 196020fa2881Sschwarze switch (sec) { 196149aff9f8Sschwarze case SEC_ERRORS: 1962be89e780Sschwarze if (*mdoc->meta.msec == '4') 1963be89e780Sschwarze break; 196451fcab2fSschwarze goodsec = "2, 3, 4, 9"; 1965be89e780Sschwarze /* FALLTHROUGH */ 196649aff9f8Sschwarze case SEC_RETURN_VALUES: 196720fa2881Sschwarze /* FALLTHROUGH */ 196849aff9f8Sschwarze case SEC_LIBRARY: 196992c0ca7fSschwarze if (*mdoc->meta.msec == '2') 1970f73abda9Skristaps break; 197192c0ca7fSschwarze if (*mdoc->meta.msec == '3') 197292c0ca7fSschwarze break; 197351fcab2fSschwarze if (NULL == goodsec) 197451fcab2fSschwarze goodsec = "2, 3, 9"; 197503ab2f23Sdlg /* FALLTHROUGH */ 197649aff9f8Sschwarze case SEC_CONTEXT: 197792c0ca7fSschwarze if (*mdoc->meta.msec == '9') 197892c0ca7fSschwarze break; 197951fcab2fSschwarze if (NULL == goodsec) 198051fcab2fSschwarze goodsec = "9"; 198151fcab2fSschwarze mandoc_vmsg(MANDOCERR_SEC_MSEC, mdoc->parse, 198251fcab2fSschwarze mdoc->last->line, mdoc->last->pos, 198351fcab2fSschwarze "%s for %s only", secname, goodsec); 198420fa2881Sschwarze break; 1985f73abda9Skristaps default: 1986f73abda9Skristaps break; 1987f73abda9Skristaps } 1988f73abda9Skristaps 198946133849Sschwarze free(secname); 1990f73abda9Skristaps return(1); 1991f73abda9Skristaps } 1992d39b9a9cSschwarze 199320fa2881Sschwarze static int 1994f6127a73Sschwarze post_ignpar(POST_ARGS) 1995f6127a73Sschwarze { 1996f6127a73Sschwarze struct mdoc_node *np; 1997f6127a73Sschwarze 1998f6127a73Sschwarze if (MDOC_BODY != mdoc->last->type) 1999f6127a73Sschwarze return(1); 2000f6127a73Sschwarze 2001f6127a73Sschwarze if (NULL != (np = mdoc->last->child)) 2002f6127a73Sschwarze if (MDOC_Pp == np->tok || MDOC_Lp == np->tok) { 200320369664Sschwarze mandoc_vmsg(MANDOCERR_PAR_SKIP, 200420369664Sschwarze mdoc->parse, np->line, np->pos, 200520369664Sschwarze "%s after %s", mdoc_macronames[np->tok], 200620369664Sschwarze mdoc_macronames[mdoc->last->tok]); 2007f6127a73Sschwarze mdoc_node_delete(mdoc, np); 2008f6127a73Sschwarze } 2009f6127a73Sschwarze 2010f6127a73Sschwarze if (NULL != (np = mdoc->last->last)) 2011f6127a73Sschwarze if (MDOC_Pp == np->tok || MDOC_Lp == np->tok) { 201220369664Sschwarze mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse, 201320369664Sschwarze np->line, np->pos, "%s at the end of %s", 201420369664Sschwarze mdoc_macronames[np->tok], 201520369664Sschwarze mdoc_macronames[mdoc->last->tok]); 2016f6127a73Sschwarze mdoc_node_delete(mdoc, np); 2017f6127a73Sschwarze } 2018f6127a73Sschwarze 2019f6127a73Sschwarze return(1); 2020f6127a73Sschwarze } 2021f6127a73Sschwarze 2022f6127a73Sschwarze static int 202320fa2881Sschwarze pre_par(PRE_ARGS) 2024d39b9a9cSschwarze { 2025d39b9a9cSschwarze 2026d39b9a9cSschwarze if (NULL == mdoc->last) 2027d39b9a9cSschwarze return(1); 2028f6127a73Sschwarze if (MDOC_ELEM != n->type && MDOC_BLOCK != n->type) 2029f6127a73Sschwarze return(1); 2030d39b9a9cSschwarze 203120fa2881Sschwarze /* 203220fa2881Sschwarze * Don't allow prior `Lp' or `Pp' prior to a paragraph-type 203320fa2881Sschwarze * block: `Lp', `Pp', or non-compact `Bd' or `Bl'. 203420fa2881Sschwarze */ 2035d39b9a9cSschwarze 2036e0dd4c9cSschwarze if (MDOC_Pp != mdoc->last->tok && 2037e0dd4c9cSschwarze MDOC_Lp != mdoc->last->tok && 2038e0dd4c9cSschwarze MDOC_br != mdoc->last->tok) 2039d39b9a9cSschwarze return(1); 20408c62fbf5Sschwarze if (MDOC_Bl == n->tok && n->norm->Bl.comp) 2041d39b9a9cSschwarze return(1); 20428c62fbf5Sschwarze if (MDOC_Bd == n->tok && n->norm->Bd.comp) 2043d39b9a9cSschwarze return(1); 20448c62fbf5Sschwarze if (MDOC_It == n->tok && n->parent->norm->Bl.comp) 2045f6127a73Sschwarze return(1); 2046d39b9a9cSschwarze 204720369664Sschwarze mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse, 204820369664Sschwarze mdoc->last->line, mdoc->last->pos, 204920369664Sschwarze "%s before %s", mdoc_macronames[mdoc->last->tok], 205020369664Sschwarze mdoc_macronames[n->tok]); 2051d39b9a9cSschwarze mdoc_node_delete(mdoc, mdoc->last); 2052d39b9a9cSschwarze return(1); 2053d39b9a9cSschwarze } 205420fa2881Sschwarze 205520fa2881Sschwarze static int 2056e0dd4c9cSschwarze post_par(POST_ARGS) 2057e0dd4c9cSschwarze { 205820369664Sschwarze struct mdoc_node *np; 2059e0dd4c9cSschwarze 2060e0dd4c9cSschwarze if (MDOC_ELEM != mdoc->last->type && 2061e0dd4c9cSschwarze MDOC_BLOCK != mdoc->last->type) 2062e0dd4c9cSschwarze return(1); 2063e0dd4c9cSschwarze 206420369664Sschwarze if (NULL == (np = mdoc->last->prev)) { 206520369664Sschwarze np = mdoc->last->parent; 206620369664Sschwarze if (MDOC_Sh != np->tok && MDOC_Ss != np->tok) 2067e0dd4c9cSschwarze return(1); 2068e0dd4c9cSschwarze } else { 206920369664Sschwarze if (MDOC_Pp != np->tok && MDOC_Lp != np->tok && 2070e0dd4c9cSschwarze (MDOC_br != mdoc->last->tok || 207120369664Sschwarze (MDOC_sp != np->tok && MDOC_br != np->tok))) 2072e0dd4c9cSschwarze return(1); 2073e0dd4c9cSschwarze } 2074e0dd4c9cSschwarze 207520369664Sschwarze mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse, 207620369664Sschwarze mdoc->last->line, mdoc->last->pos, 207720369664Sschwarze "%s after %s", mdoc_macronames[mdoc->last->tok], 207820369664Sschwarze mdoc_macronames[np->tok]); 2079e0dd4c9cSschwarze mdoc_node_delete(mdoc, mdoc->last); 2080e0dd4c9cSschwarze return(1); 2081e0dd4c9cSschwarze } 2082e0dd4c9cSschwarze 2083e0dd4c9cSschwarze static int 208420fa2881Sschwarze pre_literal(PRE_ARGS) 208520fa2881Sschwarze { 208620fa2881Sschwarze 208720fa2881Sschwarze if (MDOC_BODY != n->type) 208820fa2881Sschwarze return(1); 208920fa2881Sschwarze 209020fa2881Sschwarze /* 209120fa2881Sschwarze * The `Dl' (note "el" not "one") and `Bd -literal' and `Bd 209220fa2881Sschwarze * -unfilled' macros set MDOC_LITERAL on entrance to the body. 209320fa2881Sschwarze */ 209420fa2881Sschwarze 209520fa2881Sschwarze switch (n->tok) { 209649aff9f8Sschwarze case MDOC_Dl: 209720fa2881Sschwarze mdoc->flags |= MDOC_LITERAL; 209820fa2881Sschwarze break; 209949aff9f8Sschwarze case MDOC_Bd: 21008c62fbf5Sschwarze if (DISP_literal == n->norm->Bd.type) 210120fa2881Sschwarze mdoc->flags |= MDOC_LITERAL; 21028c62fbf5Sschwarze if (DISP_unfilled == n->norm->Bd.type) 210320fa2881Sschwarze mdoc->flags |= MDOC_LITERAL; 210420fa2881Sschwarze break; 210520fa2881Sschwarze default: 210620fa2881Sschwarze abort(); 210720fa2881Sschwarze /* NOTREACHED */ 210820fa2881Sschwarze } 210920fa2881Sschwarze 211020fa2881Sschwarze return(1); 211120fa2881Sschwarze } 211220fa2881Sschwarze 211320fa2881Sschwarze static int 211420fa2881Sschwarze post_dd(POST_ARGS) 211520fa2881Sschwarze { 211620fa2881Sschwarze struct mdoc_node *n; 211783af2bccSschwarze char *datestr; 211820fa2881Sschwarze 2119b058e777Sschwarze if (mdoc->meta.date) 2120b058e777Sschwarze free(mdoc->meta.date); 212120fa2881Sschwarze 2122b058e777Sschwarze n = mdoc->last; 2123b058e777Sschwarze if (NULL == n->child || '\0' == n->child->string[0]) { 2124231c7061Sschwarze mdoc->meta.date = mdoc->quick ? mandoc_strdup("") : 2125231c7061Sschwarze mandoc_normdate(mdoc->parse, NULL, n->line, n->pos); 212620fa2881Sschwarze return(1); 212720fa2881Sschwarze } 212820fa2881Sschwarze 212983af2bccSschwarze datestr = NULL; 213083af2bccSschwarze mdoc_deroff(&datestr, n); 213183af2bccSschwarze if (mdoc->quick) 213283af2bccSschwarze mdoc->meta.date = datestr; 213383af2bccSschwarze else { 213483af2bccSschwarze mdoc->meta.date = mandoc_normdate(mdoc->parse, 213583af2bccSschwarze datestr, n->line, n->pos); 213683af2bccSschwarze free(datestr); 213704e980cbSschwarze } 213820fa2881Sschwarze return(1); 213920fa2881Sschwarze } 214020fa2881Sschwarze 214120fa2881Sschwarze static int 214220fa2881Sschwarze post_dt(POST_ARGS) 214320fa2881Sschwarze { 214420fa2881Sschwarze struct mdoc_node *nn, *n; 214520fa2881Sschwarze const char *cp; 214620fa2881Sschwarze char *p; 214720fa2881Sschwarze 214820fa2881Sschwarze n = mdoc->last; 214920fa2881Sschwarze 215020fa2881Sschwarze if (mdoc->meta.title) 215120fa2881Sschwarze free(mdoc->meta.title); 215220fa2881Sschwarze if (mdoc->meta.vol) 215320fa2881Sschwarze free(mdoc->meta.vol); 215420fa2881Sschwarze if (mdoc->meta.arch) 215520fa2881Sschwarze free(mdoc->meta.arch); 215620fa2881Sschwarze 215720fa2881Sschwarze mdoc->meta.title = mdoc->meta.vol = mdoc->meta.arch = NULL; 215820fa2881Sschwarze 215951fcab2fSschwarze /* First check that all characters are uppercase. */ 216020fa2881Sschwarze 216120fa2881Sschwarze if (NULL != (nn = n->child)) 216220fa2881Sschwarze for (p = nn->string; *p; p++) { 216304e980cbSschwarze if (toupper((unsigned char)*p) == *p) 216420fa2881Sschwarze continue; 216551fcab2fSschwarze mandoc_msg(MANDOCERR_TITLE_CASE, 216651fcab2fSschwarze mdoc->parse, nn->line, 216751fcab2fSschwarze nn->pos + (p - nn->string), 216851fcab2fSschwarze nn->string); 216920fa2881Sschwarze break; 217020fa2881Sschwarze } 217120fa2881Sschwarze 217220fa2881Sschwarze /* Handles: `.Dt' 217349aff9f8Sschwarze * title = unknown, volume = local, msec = 0, arch = NULL 217420fa2881Sschwarze */ 217520fa2881Sschwarze 217620fa2881Sschwarze if (NULL == (nn = n->child)) { 217720fa2881Sschwarze /* XXX: make these macro values. */ 217820fa2881Sschwarze /* FIXME: warn about missing values. */ 217920fa2881Sschwarze mdoc->meta.title = mandoc_strdup("UNKNOWN"); 218020fa2881Sschwarze mdoc->meta.vol = mandoc_strdup("LOCAL"); 218120fa2881Sschwarze mdoc->meta.msec = mandoc_strdup("1"); 218220fa2881Sschwarze return(1); 218320fa2881Sschwarze } 218420fa2881Sschwarze 218520fa2881Sschwarze /* Handles: `.Dt TITLE' 218649aff9f8Sschwarze * title = TITLE, volume = local, msec = 0, arch = NULL 218720fa2881Sschwarze */ 218820fa2881Sschwarze 218949aff9f8Sschwarze mdoc->meta.title = mandoc_strdup( 219049aff9f8Sschwarze '\0' == nn->string[0] ? "UNKNOWN" : nn->string); 219120fa2881Sschwarze 219220fa2881Sschwarze if (NULL == (nn = nn->next)) { 219320fa2881Sschwarze /* FIXME: warn about missing msec. */ 219420fa2881Sschwarze /* XXX: make this a macro value. */ 219520fa2881Sschwarze mdoc->meta.vol = mandoc_strdup("LOCAL"); 219620fa2881Sschwarze mdoc->meta.msec = mandoc_strdup("1"); 219720fa2881Sschwarze return(1); 219820fa2881Sschwarze } 219920fa2881Sschwarze 220020fa2881Sschwarze /* Handles: `.Dt TITLE SEC' 220149aff9f8Sschwarze * title = TITLE, 220249aff9f8Sschwarze * volume = SEC is msec ? format(msec) : SEC, 220320fa2881Sschwarze * msec = SEC is msec ? atoi(msec) : 0, 220420fa2881Sschwarze * arch = NULL 220520fa2881Sschwarze */ 220620fa2881Sschwarze 220788ec69e3Sschwarze cp = mandoc_a2msec(nn->string); 220820fa2881Sschwarze if (cp) { 220920fa2881Sschwarze mdoc->meta.vol = mandoc_strdup(cp); 221020fa2881Sschwarze mdoc->meta.msec = mandoc_strdup(nn->string); 221120fa2881Sschwarze } else { 221251fcab2fSschwarze mandoc_msg(MANDOCERR_MSEC_BAD, mdoc->parse, 221351fcab2fSschwarze nn->line, nn->pos, nn->string); 221420fa2881Sschwarze mdoc->meta.vol = mandoc_strdup(nn->string); 221520fa2881Sschwarze mdoc->meta.msec = mandoc_strdup(nn->string); 221620fa2881Sschwarze } 221720fa2881Sschwarze 221820fa2881Sschwarze if (NULL == (nn = nn->next)) 221920fa2881Sschwarze return(1); 222020fa2881Sschwarze 222120fa2881Sschwarze /* Handles: `.Dt TITLE SEC VOL' 222249aff9f8Sschwarze * title = TITLE, 222349aff9f8Sschwarze * volume = VOL is vol ? format(VOL) : 222420fa2881Sschwarze * VOL is arch ? format(arch) : 222520fa2881Sschwarze * VOL 222620fa2881Sschwarze */ 222720fa2881Sschwarze 222820fa2881Sschwarze cp = mdoc_a2vol(nn->string); 222920fa2881Sschwarze if (cp) { 223020fa2881Sschwarze free(mdoc->meta.vol); 223120fa2881Sschwarze mdoc->meta.vol = mandoc_strdup(cp); 223220fa2881Sschwarze } else { 223320fa2881Sschwarze cp = mdoc_a2arch(nn->string); 223420fa2881Sschwarze if (NULL == cp) { 223551fcab2fSschwarze mandoc_msg(MANDOCERR_ARCH_BAD, mdoc->parse, 223651fcab2fSschwarze nn->line, nn->pos, nn->string); 223720fa2881Sschwarze free(mdoc->meta.vol); 223820fa2881Sschwarze mdoc->meta.vol = mandoc_strdup(nn->string); 223920fa2881Sschwarze } else 224020fa2881Sschwarze mdoc->meta.arch = mandoc_strdup(cp); 224120fa2881Sschwarze } 224220fa2881Sschwarze 224320fa2881Sschwarze /* Ignore any subsequent parameters... */ 224420fa2881Sschwarze /* FIXME: warn about subsequent parameters. */ 224520fa2881Sschwarze 224620fa2881Sschwarze return(1); 224720fa2881Sschwarze } 224820fa2881Sschwarze 224920fa2881Sschwarze static int 225020fa2881Sschwarze post_prol(POST_ARGS) 225120fa2881Sschwarze { 225220fa2881Sschwarze /* 225320fa2881Sschwarze * Remove prologue macros from the document after they're 225420fa2881Sschwarze * processed. The final document uses mdoc_meta for these 225520fa2881Sschwarze * values and discards the originals. 225620fa2881Sschwarze */ 225720fa2881Sschwarze 225820fa2881Sschwarze mdoc_node_delete(mdoc, mdoc->last); 225920fa2881Sschwarze if (mdoc->meta.title && mdoc->meta.date && mdoc->meta.os) 226020fa2881Sschwarze mdoc->flags |= MDOC_PBODY; 226120fa2881Sschwarze 226220fa2881Sschwarze return(1); 226320fa2881Sschwarze } 226420fa2881Sschwarze 226520fa2881Sschwarze static int 2266992063deSschwarze post_bx(POST_ARGS) 2267992063deSschwarze { 2268992063deSschwarze struct mdoc_node *n; 2269992063deSschwarze 2270992063deSschwarze /* 2271992063deSschwarze * Make `Bx's second argument always start with an uppercase 2272992063deSschwarze * letter. Groff checks if it's an "accepted" term, but we just 2273992063deSschwarze * uppercase blindly. 2274992063deSschwarze */ 2275992063deSschwarze 2276992063deSschwarze n = mdoc->last->child; 2277992063deSschwarze if (n && NULL != (n = n->next)) 227849aff9f8Sschwarze *n->string = (char)toupper((unsigned char)*n->string); 2279992063deSschwarze 2280992063deSschwarze return(1); 2281992063deSschwarze } 2282992063deSschwarze 2283992063deSschwarze static int 228420fa2881Sschwarze post_os(POST_ARGS) 228520fa2881Sschwarze { 228620fa2881Sschwarze #ifndef OSNAME 228720fa2881Sschwarze struct utsname utsname; 22884c468128Sschwarze static char *defbuf; 228920fa2881Sschwarze #endif 22904c468128Sschwarze struct mdoc_node *n; 229120fa2881Sschwarze 229220fa2881Sschwarze n = mdoc->last; 229320fa2881Sschwarze 229420fa2881Sschwarze /* 2295353fa9ecSschwarze * Set the operating system by way of the `Os' macro. 2296353fa9ecSschwarze * The order of precedence is: 2297353fa9ecSschwarze * 1. the argument of the `Os' macro, unless empty 2298353fa9ecSschwarze * 2. the -Ios=foo command line argument, if provided 2299353fa9ecSschwarze * 3. -DOSNAME="\"foo\"", if provided during compilation 2300353fa9ecSschwarze * 4. "sysname release" from uname(3) 230120fa2881Sschwarze */ 230220fa2881Sschwarze 230320fa2881Sschwarze free(mdoc->meta.os); 230483af2bccSschwarze mdoc->meta.os = NULL; 230583af2bccSschwarze mdoc_deroff(&mdoc->meta.os, n); 230683af2bccSschwarze if (mdoc->meta.os) 23074c468128Sschwarze return(1); 23084c468128Sschwarze 2309353fa9ecSschwarze if (mdoc->defos) { 2310353fa9ecSschwarze mdoc->meta.os = mandoc_strdup(mdoc->defos); 2311353fa9ecSschwarze return(1); 2312353fa9ecSschwarze } 23134c468128Sschwarze 231420fa2881Sschwarze #ifdef OSNAME 23154c468128Sschwarze mdoc->meta.os = mandoc_strdup(OSNAME); 231620fa2881Sschwarze #else /*!OSNAME */ 23174c468128Sschwarze if (NULL == defbuf) { 2318a35fc07aSschwarze if (-1 == uname(&utsname)) { 2319f79e7afeSschwarze mandoc_msg(MANDOCERR_OS_UNAME, mdoc->parse, 2320f79e7afeSschwarze n->line, n->pos, "Os"); 23214c468128Sschwarze defbuf = mandoc_strdup("UNKNOWN"); 2322a450f7c4Sschwarze } else 2323a450f7c4Sschwarze mandoc_asprintf(&defbuf, "%s %s", 2324a450f7c4Sschwarze utsname.sysname, utsname.release); 232520fa2881Sschwarze } 23264c468128Sschwarze mdoc->meta.os = mandoc_strdup(defbuf); 232720fa2881Sschwarze #endif /*!OSNAME*/ 232820fa2881Sschwarze return(1); 232920fa2881Sschwarze } 233020fa2881Sschwarze 2331e214f641Sschwarze /* 2332e214f641Sschwarze * If no argument is provided, 2333e214f641Sschwarze * fill in the name of the current manual page. 2334e214f641Sschwarze */ 233520fa2881Sschwarze static int 2336e214f641Sschwarze post_ex(POST_ARGS) 233720fa2881Sschwarze { 2338e214f641Sschwarze struct mdoc_node *n; 233920fa2881Sschwarze 234020fa2881Sschwarze n = mdoc->last; 234120fa2881Sschwarze 234220fa2881Sschwarze if (n->child) 234320fa2881Sschwarze return(1); 234420fa2881Sschwarze 2345e214f641Sschwarze if (mdoc->meta.name == NULL) { 2346e214f641Sschwarze mdoc_nmsg(mdoc, n, MANDOCERR_EX_NONAME); 234720fa2881Sschwarze return(1); 2348e214f641Sschwarze } 234920fa2881Sschwarze 235020fa2881Sschwarze mdoc->next = MDOC_NEXT_CHILD; 235120fa2881Sschwarze 235220fa2881Sschwarze if ( ! mdoc_word_alloc(mdoc, n->line, n->pos, mdoc->meta.name)) 235320fa2881Sschwarze return(0); 235420fa2881Sschwarze 2355e214f641Sschwarze mdoc->last = n; 235620fa2881Sschwarze return(1); 235720fa2881Sschwarze } 235820fa2881Sschwarze 235919a69263Sschwarze static enum mdoc_sec 236019a69263Sschwarze a2sec(const char *p) 236119a69263Sschwarze { 236219a69263Sschwarze int i; 236319a69263Sschwarze 236419a69263Sschwarze for (i = 0; i < (int)SEC__MAX; i++) 236519a69263Sschwarze if (secnames[i] && 0 == strcmp(p, secnames[i])) 236619a69263Sschwarze return((enum mdoc_sec)i); 236719a69263Sschwarze 236819a69263Sschwarze return(SEC_CUSTOM); 236919a69263Sschwarze } 237019a69263Sschwarze 237119a69263Sschwarze static size_t 237219a69263Sschwarze macro2len(enum mdoct macro) 237319a69263Sschwarze { 237419a69263Sschwarze 237519a69263Sschwarze switch (macro) { 237649aff9f8Sschwarze case MDOC_Ad: 237719a69263Sschwarze return(12); 237849aff9f8Sschwarze case MDOC_Ao: 237919a69263Sschwarze return(12); 238049aff9f8Sschwarze case MDOC_An: 238119a69263Sschwarze return(12); 238249aff9f8Sschwarze case MDOC_Aq: 238319a69263Sschwarze return(12); 238449aff9f8Sschwarze case MDOC_Ar: 238519a69263Sschwarze return(12); 238649aff9f8Sschwarze case MDOC_Bo: 238719a69263Sschwarze return(12); 238849aff9f8Sschwarze case MDOC_Bq: 238919a69263Sschwarze return(12); 239049aff9f8Sschwarze case MDOC_Cd: 239119a69263Sschwarze return(12); 239249aff9f8Sschwarze case MDOC_Cm: 239319a69263Sschwarze return(10); 239449aff9f8Sschwarze case MDOC_Do: 239519a69263Sschwarze return(10); 239649aff9f8Sschwarze case MDOC_Dq: 239719a69263Sschwarze return(12); 239849aff9f8Sschwarze case MDOC_Dv: 239919a69263Sschwarze return(12); 240049aff9f8Sschwarze case MDOC_Eo: 240119a69263Sschwarze return(12); 240249aff9f8Sschwarze case MDOC_Em: 240319a69263Sschwarze return(10); 240449aff9f8Sschwarze case MDOC_Er: 240519a69263Sschwarze return(17); 240649aff9f8Sschwarze case MDOC_Ev: 240719a69263Sschwarze return(15); 240849aff9f8Sschwarze case MDOC_Fa: 240919a69263Sschwarze return(12); 241049aff9f8Sschwarze case MDOC_Fl: 241119a69263Sschwarze return(10); 241249aff9f8Sschwarze case MDOC_Fo: 241319a69263Sschwarze return(16); 241449aff9f8Sschwarze case MDOC_Fn: 241519a69263Sschwarze return(16); 241649aff9f8Sschwarze case MDOC_Ic: 241719a69263Sschwarze return(10); 241849aff9f8Sschwarze case MDOC_Li: 241919a69263Sschwarze return(16); 242049aff9f8Sschwarze case MDOC_Ms: 242119a69263Sschwarze return(6); 242249aff9f8Sschwarze case MDOC_Nm: 242319a69263Sschwarze return(10); 242449aff9f8Sschwarze case MDOC_No: 242519a69263Sschwarze return(12); 242649aff9f8Sschwarze case MDOC_Oo: 242719a69263Sschwarze return(10); 242849aff9f8Sschwarze case MDOC_Op: 242919a69263Sschwarze return(14); 243049aff9f8Sschwarze case MDOC_Pa: 243119a69263Sschwarze return(32); 243249aff9f8Sschwarze case MDOC_Pf: 243319a69263Sschwarze return(12); 243449aff9f8Sschwarze case MDOC_Po: 243519a69263Sschwarze return(12); 243649aff9f8Sschwarze case MDOC_Pq: 243719a69263Sschwarze return(12); 243849aff9f8Sschwarze case MDOC_Ql: 243919a69263Sschwarze return(16); 244049aff9f8Sschwarze case MDOC_Qo: 244119a69263Sschwarze return(12); 244249aff9f8Sschwarze case MDOC_So: 244319a69263Sschwarze return(12); 244449aff9f8Sschwarze case MDOC_Sq: 244519a69263Sschwarze return(12); 244649aff9f8Sschwarze case MDOC_Sy: 244719a69263Sschwarze return(6); 244849aff9f8Sschwarze case MDOC_Sx: 244919a69263Sschwarze return(16); 245049aff9f8Sschwarze case MDOC_Tn: 245119a69263Sschwarze return(10); 245249aff9f8Sschwarze case MDOC_Va: 245319a69263Sschwarze return(12); 245449aff9f8Sschwarze case MDOC_Vt: 245519a69263Sschwarze return(12); 245649aff9f8Sschwarze case MDOC_Xr: 245719a69263Sschwarze return(10); 245819a69263Sschwarze default: 245919a69263Sschwarze break; 246019a69263Sschwarze }; 246119a69263Sschwarze return(0); 246219a69263Sschwarze } 2463