1*4a9f685fSschwarze /* $Id: mdoc_validate.c,v 1.145 2014/07/05 01:11:33 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); 65dd94fa3aSschwarze static int check_parent(PRE_ARGS, enum mdoct, enum mdoc_type); 6620fa2881Sschwarze static void check_text(struct mdoc *, int, int, char *); 6720fa2881Sschwarze static void check_argv(struct mdoc *, 6831e23753Sschwarze struct mdoc_node *, struct mdoc_argv *); 6920fa2881Sschwarze static void check_args(struct mdoc *, struct mdoc_node *); 7019a69263Sschwarze static enum mdoc_sec a2sec(const char *); 7119a69263Sschwarze static size_t macro2len(enum mdoct); 7267c719adSschwarze 737c2be9f8Sschwarze static int ebool(POST_ARGS); 7467c719adSschwarze static int berr_ge1(POST_ARGS); 7567c719adSschwarze static int bwarn_ge1(POST_ARGS); 76da272f5eSschwarze static int ewarn_eq0(POST_ARGS); 77bb648afaSschwarze static int ewarn_eq1(POST_ARGS); 7867c719adSschwarze static int ewarn_ge1(POST_ARGS); 79bb648afaSschwarze static int ewarn_le1(POST_ARGS); 80b16e7ddfSschwarze static int hwarn_eq0(POST_ARGS); 817c2be9f8Sschwarze static int hwarn_eq1(POST_ARGS); 82bb648afaSschwarze static int hwarn_ge1(POST_ARGS); 8367c719adSschwarze 8467c719adSschwarze static int post_an(POST_ARGS); 8567c719adSschwarze static int post_at(POST_ARGS); 8667c719adSschwarze static int post_bf(POST_ARGS); 8767c719adSschwarze static int post_bl(POST_ARGS); 8820fa2881Sschwarze static int post_bl_block(POST_ARGS); 8920fa2881Sschwarze static int post_bl_block_width(POST_ARGS); 9020fa2881Sschwarze static int post_bl_block_tag(POST_ARGS); 9167c719adSschwarze static int post_bl_head(POST_ARGS); 92992063deSschwarze static int post_bx(POST_ARGS); 934039b21cSschwarze static int post_defaults(POST_ARGS); 9420fa2881Sschwarze static int post_dd(POST_ARGS); 956093755cSschwarze static int post_dt(POST_ARGS); 96551cd4a8Sschwarze static int post_en(POST_ARGS); 97551cd4a8Sschwarze static int post_es(POST_ARGS); 9820fa2881Sschwarze static int post_eoln(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); 11520fa2881Sschwarze static int post_std(POST_ARGS); 1168521b0bcSschwarze static int post_vt(POST_ARGS); 117f73abda9Skristaps static int pre_an(PRE_ARGS); 118f73abda9Skristaps static int pre_bd(PRE_ARGS); 119f73abda9Skristaps static int pre_bl(PRE_ARGS); 120f73abda9Skristaps static int pre_dd(PRE_ARGS); 121f73abda9Skristaps static int pre_display(PRE_ARGS); 122f73abda9Skristaps static int pre_dt(PRE_ARGS); 123f73abda9Skristaps static int pre_it(PRE_ARGS); 12420fa2881Sschwarze static int pre_literal(PRE_ARGS); 125551cd4a8Sschwarze static int pre_obsolete(PRE_ARGS); 126f73abda9Skristaps static int pre_os(PRE_ARGS); 12720fa2881Sschwarze static int pre_par(PRE_ARGS); 128f73abda9Skristaps static int pre_sh(PRE_ARGS); 129f73abda9Skristaps static int pre_ss(PRE_ARGS); 13020fa2881Sschwarze static int pre_std(PRE_ARGS); 131f73abda9Skristaps 13267c719adSschwarze static v_post posts_an[] = { post_an, NULL }; 13320fa2881Sschwarze static v_post posts_at[] = { post_at, post_defaults, NULL }; 13420fa2881Sschwarze static v_post posts_bd[] = { post_literal, hwarn_eq0, bwarn_ge1, NULL }; 135ecb10c32Sschwarze static v_post posts_bf[] = { post_bf, NULL }; 13620fa2881Sschwarze static v_post posts_bk[] = { hwarn_eq0, bwarn_ge1, NULL }; 13767c719adSschwarze static v_post posts_bl[] = { bwarn_ge1, post_bl, NULL }; 138992063deSschwarze static v_post posts_bx[] = { post_bx, NULL }; 139bb648afaSschwarze static v_post posts_bool[] = { ebool, NULL }; 140b31af00dSschwarze static v_post posts_eoln[] = { post_eoln, NULL }; 14120fa2881Sschwarze static v_post posts_defaults[] = { post_defaults, NULL }; 1424039b21cSschwarze static v_post posts_d1[] = { bwarn_ge1, post_hyph, NULL }; 143b058e777Sschwarze static v_post posts_dd[] = { post_dd, post_prol, NULL }; 144bb648afaSschwarze static v_post posts_dl[] = { post_literal, bwarn_ge1, NULL }; 14520fa2881Sschwarze static v_post posts_dt[] = { post_dt, post_prol, NULL }; 146551cd4a8Sschwarze static v_post posts_en[] = { post_en, NULL }; 147551cd4a8Sschwarze static v_post posts_es[] = { post_es, NULL }; 14867c719adSschwarze static v_post posts_fo[] = { hwarn_eq1, bwarn_ge1, NULL }; 1494039b21cSschwarze static v_post posts_hyph[] = { post_hyph, NULL }; 1504039b21cSschwarze static v_post posts_hyphtext[] = { ewarn_ge1, post_hyph, NULL }; 15167c719adSschwarze static v_post posts_it[] = { post_it, NULL }; 152bb648afaSschwarze static v_post posts_lb[] = { post_lb, NULL }; 1534039b21cSschwarze static v_post posts_nd[] = { berr_ge1, post_hyph, NULL }; 15467c719adSschwarze static v_post posts_nm[] = { post_nm, NULL }; 155da272f5eSschwarze static v_post posts_notext[] = { ewarn_eq0, NULL }; 156af216717Sschwarze static v_post posts_ns[] = { post_ns, NULL }; 15720fa2881Sschwarze static v_post posts_os[] = { post_os, post_prol, NULL }; 158e0dd4c9cSschwarze static v_post posts_pp[] = { post_par, ewarn_eq0, NULL }; 159bb648afaSschwarze static v_post posts_rs[] = { post_rs, NULL }; 1604039b21cSschwarze static v_post posts_sh[] = { post_ignpar,hwarn_ge1,post_sh,post_hyph,NULL }; 161e0dd4c9cSschwarze static v_post posts_sp[] = { post_par, ewarn_le1, NULL }; 1624039b21cSschwarze static v_post posts_ss[] = { post_ignpar, hwarn_ge1, post_hyph, NULL }; 163bb648afaSschwarze static v_post posts_st[] = { post_st, NULL }; 16420fa2881Sschwarze static v_post posts_std[] = { post_std, NULL }; 165e7a93ef3Sschwarze static v_post posts_text[] = { ewarn_ge1, NULL }; 166bb648afaSschwarze static v_post posts_text1[] = { ewarn_eq1, NULL }; 1678521b0bcSschwarze static v_post posts_vt[] = { post_vt, NULL }; 168f73abda9Skristaps static v_pre pres_an[] = { pre_an, NULL }; 16920fa2881Sschwarze static v_pre pres_bd[] = { pre_display, pre_bd, pre_literal, pre_par, NULL }; 17020fa2881Sschwarze static v_pre pres_bl[] = { pre_bl, pre_par, NULL }; 171f73abda9Skristaps static v_pre pres_d1[] = { pre_display, NULL }; 17220fa2881Sschwarze static v_pre pres_dl[] = { pre_literal, pre_display, NULL }; 17367c719adSschwarze static v_pre pres_dd[] = { pre_dd, NULL }; 1746be99f77Sschwarze static v_pre pres_dt[] = { pre_dt, NULL }; 175f6127a73Sschwarze static v_pre pres_it[] = { pre_it, pre_par, NULL }; 176551cd4a8Sschwarze static v_pre pres_obsolete[] = { pre_obsolete, NULL }; 1776be99f77Sschwarze static v_pre pres_os[] = { pre_os, NULL }; 17820fa2881Sschwarze static v_pre pres_pp[] = { pre_par, NULL }; 179f73abda9Skristaps static v_pre pres_sh[] = { pre_sh, NULL }; 180f73abda9Skristaps static v_pre pres_ss[] = { pre_ss, NULL }; 18120fa2881Sschwarze static v_pre pres_std[] = { pre_std, NULL }; 182f73abda9Skristaps 18319a69263Sschwarze static const struct valids mdoc_valids[MDOC_MAX] = { 184099cfa7eSschwarze { NULL, NULL }, /* Ap */ 18520fa2881Sschwarze { pres_dd, posts_dd }, /* Dd */ 1866093755cSschwarze { pres_dt, posts_dt }, /* Dt */ 18720fa2881Sschwarze { pres_os, posts_os }, /* Os */ 188f73abda9Skristaps { pres_sh, posts_sh }, /* Sh */ 189f73abda9Skristaps { pres_ss, posts_ss }, /* Ss */ 190e0dd4c9cSschwarze { pres_pp, posts_pp }, /* Pp */ 1914039b21cSschwarze { pres_d1, posts_d1 }, /* D1 */ 19220fa2881Sschwarze { pres_dl, posts_dl }, /* Dl */ 19320fa2881Sschwarze { pres_bd, posts_bd }, /* Bd */ 194f73abda9Skristaps { NULL, NULL }, /* Ed */ 195f73abda9Skristaps { pres_bl, posts_bl }, /* Bl */ 196f73abda9Skristaps { NULL, NULL }, /* El */ 197f73abda9Skristaps { pres_it, posts_it }, /* It */ 198e7a93ef3Sschwarze { NULL, NULL }, /* Ad */ 199f73abda9Skristaps { pres_an, posts_an }, /* An */ 20020fa2881Sschwarze { NULL, posts_defaults }, /* Ar */ 201e7a93ef3Sschwarze { NULL, NULL }, /* Cd */ 202f73abda9Skristaps { NULL, NULL }, /* Cm */ 203f73abda9Skristaps { NULL, NULL }, /* Dv */ 2044039b21cSschwarze { NULL, NULL }, /* Er */ 205f73abda9Skristaps { NULL, NULL }, /* Ev */ 20620fa2881Sschwarze { pres_std, posts_std }, /* Ex */ 207f73abda9Skristaps { NULL, NULL }, /* Fa */ 2084039b21cSschwarze { NULL, posts_text }, /* Fd */ 209f73abda9Skristaps { NULL, NULL }, /* Fl */ 210e7a93ef3Sschwarze { NULL, NULL }, /* Fn */ 211e7a93ef3Sschwarze { NULL, NULL }, /* Ft */ 212e7a93ef3Sschwarze { NULL, NULL }, /* Ic */ 213b822ca0dSschwarze { NULL, posts_text1 }, /* In */ 21420fa2881Sschwarze { NULL, posts_defaults }, /* Li */ 2154602e85cSschwarze { NULL, posts_nd }, /* Nd */ 216f73abda9Skristaps { NULL, posts_nm }, /* Nm */ 217bca76d61Sschwarze { NULL, NULL }, /* Op */ 218551cd4a8Sschwarze { pres_obsolete, NULL }, /* Ot */ 21920fa2881Sschwarze { NULL, posts_defaults }, /* Pa */ 22020fa2881Sschwarze { pres_std, posts_std }, /* Rv */ 221f73abda9Skristaps { NULL, posts_st }, /* St */ 222f73abda9Skristaps { NULL, NULL }, /* Va */ 2238521b0bcSschwarze { NULL, posts_vt }, /* Vt */ 224e7a93ef3Sschwarze { NULL, posts_text }, /* Xr */ 225f73abda9Skristaps { NULL, posts_text }, /* %A */ 2264039b21cSschwarze { NULL, posts_hyphtext }, /* %B */ /* FIXME: can be used outside Rs/Re. */ 227b058e777Sschwarze { NULL, posts_text }, /* %D */ 228f73abda9Skristaps { NULL, posts_text }, /* %I */ 229f73abda9Skristaps { NULL, posts_text }, /* %J */ 2304039b21cSschwarze { NULL, posts_hyphtext }, /* %N */ 2314039b21cSschwarze { NULL, posts_hyphtext }, /* %O */ 232f73abda9Skristaps { NULL, posts_text }, /* %P */ 2334039b21cSschwarze { NULL, posts_hyphtext }, /* %R */ 2344039b21cSschwarze { NULL, posts_hyphtext }, /* %T */ /* FIXME: can be used outside Rs/Re. */ 235f73abda9Skristaps { NULL, posts_text }, /* %V */ 236f73abda9Skristaps { NULL, NULL }, /* Ac */ 237f73abda9Skristaps { NULL, NULL }, /* Ao */ 238bca76d61Sschwarze { NULL, NULL }, /* Aq */ 239f73abda9Skristaps { NULL, posts_at }, /* At */ 240f73abda9Skristaps { NULL, NULL }, /* Bc */ 241f73abda9Skristaps { NULL, posts_bf }, /* Bf */ 242f73abda9Skristaps { NULL, NULL }, /* Bo */ 243bca76d61Sschwarze { NULL, NULL }, /* Bq */ 244f73abda9Skristaps { NULL, NULL }, /* Bsx */ 245992063deSschwarze { NULL, posts_bx }, /* Bx */ 246f73abda9Skristaps { NULL, posts_bool }, /* Db */ 247f73abda9Skristaps { NULL, NULL }, /* Dc */ 248f73abda9Skristaps { NULL, NULL }, /* Do */ 249bca76d61Sschwarze { NULL, NULL }, /* Dq */ 250f73abda9Skristaps { NULL, NULL }, /* Ec */ 251f73abda9Skristaps { NULL, NULL }, /* Ef */ 252f73abda9Skristaps { NULL, NULL }, /* Em */ 253f73abda9Skristaps { NULL, NULL }, /* Eo */ 254f73abda9Skristaps { NULL, NULL }, /* Fx */ 255e7a93ef3Sschwarze { NULL, NULL }, /* Ms */ 256f73abda9Skristaps { NULL, posts_notext }, /* No */ 257af216717Sschwarze { NULL, posts_ns }, /* Ns */ 258f73abda9Skristaps { NULL, NULL }, /* Nx */ 259f73abda9Skristaps { NULL, NULL }, /* Ox */ 260f73abda9Skristaps { NULL, NULL }, /* Pc */ 261b822ca0dSschwarze { NULL, posts_text1 }, /* Pf */ 262f73abda9Skristaps { NULL, NULL }, /* Po */ 263bca76d61Sschwarze { NULL, NULL }, /* Pq */ 264f73abda9Skristaps { NULL, NULL }, /* Qc */ 265bca76d61Sschwarze { NULL, NULL }, /* Ql */ 266f73abda9Skristaps { NULL, NULL }, /* Qo */ 267bca76d61Sschwarze { NULL, NULL }, /* Qq */ 268f73abda9Skristaps { NULL, NULL }, /* Re */ 2698c62fbf5Sschwarze { NULL, posts_rs }, /* Rs */ 270f73abda9Skristaps { NULL, NULL }, /* Sc */ 271f73abda9Skristaps { NULL, NULL }, /* So */ 272bca76d61Sschwarze { NULL, NULL }, /* Sq */ 273f73abda9Skristaps { NULL, posts_bool }, /* Sm */ 2744039b21cSschwarze { NULL, posts_hyph }, /* Sx */ 275e7a93ef3Sschwarze { NULL, NULL }, /* Sy */ 276e7a93ef3Sschwarze { NULL, NULL }, /* Tn */ 277f73abda9Skristaps { NULL, NULL }, /* Ux */ 278f73abda9Skristaps { NULL, NULL }, /* Xc */ 279f73abda9Skristaps { NULL, NULL }, /* Xo */ 280f73abda9Skristaps { NULL, posts_fo }, /* Fo */ 281f73abda9Skristaps { NULL, NULL }, /* Fc */ 282f73abda9Skristaps { NULL, NULL }, /* Oo */ 283f73abda9Skristaps { NULL, NULL }, /* Oc */ 28420fa2881Sschwarze { NULL, posts_bk }, /* Bk */ 285f73abda9Skristaps { NULL, NULL }, /* Ek */ 286b31af00dSschwarze { NULL, posts_eoln }, /* Bt */ 287f73abda9Skristaps { NULL, NULL }, /* Hf */ 288551cd4a8Sschwarze { pres_obsolete, NULL }, /* Fr */ 289b31af00dSschwarze { NULL, posts_eoln }, /* Ud */ 290b31af00dSschwarze { NULL, posts_lb }, /* Lb */ 291e0dd4c9cSschwarze { pres_pp, posts_pp }, /* Lp */ 292e7a93ef3Sschwarze { NULL, NULL }, /* Lk */ 29320fa2881Sschwarze { NULL, posts_defaults }, /* Mt */ 294bca76d61Sschwarze { NULL, NULL }, /* Brq */ 295f73abda9Skristaps { NULL, NULL }, /* Bro */ 296f73abda9Skristaps { NULL, NULL }, /* Brc */ 297f73abda9Skristaps { NULL, posts_text }, /* %C */ 298551cd4a8Sschwarze { pres_obsolete, posts_es }, /* Es */ 299551cd4a8Sschwarze { pres_obsolete, posts_en }, /* En */ 300f73abda9Skristaps { NULL, NULL }, /* Dx */ 301f73abda9Skristaps { NULL, posts_text }, /* %Q */ 302e0dd4c9cSschwarze { NULL, posts_pp }, /* br */ 303e0dd4c9cSschwarze { NULL, posts_sp }, /* sp */ 304b822ca0dSschwarze { NULL, posts_text1 }, /* %U */ 3056093755cSschwarze { NULL, NULL }, /* Ta */ 3065281506aSschwarze { NULL, NULL }, /* ll */ 307f73abda9Skristaps }; 308f73abda9Skristaps 30920fa2881Sschwarze #define RSORD_MAX 14 /* Number of `Rs' blocks. */ 31020fa2881Sschwarze 31120fa2881Sschwarze static const enum mdoct rsord[RSORD_MAX] = { 31220fa2881Sschwarze MDOC__A, 31320fa2881Sschwarze MDOC__T, 31420fa2881Sschwarze MDOC__B, 31520fa2881Sschwarze MDOC__I, 31620fa2881Sschwarze MDOC__J, 31720fa2881Sschwarze MDOC__R, 31820fa2881Sschwarze MDOC__N, 31920fa2881Sschwarze MDOC__V, 3200397c682Sschwarze MDOC__U, 32120fa2881Sschwarze MDOC__P, 32220fa2881Sschwarze MDOC__Q, 3234e32ec8fSschwarze MDOC__C, 32420fa2881Sschwarze MDOC__D, 3254e32ec8fSschwarze MDOC__O 32620fa2881Sschwarze }; 32720fa2881Sschwarze 32819a69263Sschwarze static const char * const secnames[SEC__MAX] = { 32919a69263Sschwarze NULL, 33019a69263Sschwarze "NAME", 33119a69263Sschwarze "LIBRARY", 33219a69263Sschwarze "SYNOPSIS", 33319a69263Sschwarze "DESCRIPTION", 33403ab2f23Sdlg "CONTEXT", 33519a69263Sschwarze "IMPLEMENTATION NOTES", 33619a69263Sschwarze "RETURN VALUES", 33719a69263Sschwarze "ENVIRONMENT", 33819a69263Sschwarze "FILES", 33919a69263Sschwarze "EXIT STATUS", 34019a69263Sschwarze "EXAMPLES", 34119a69263Sschwarze "DIAGNOSTICS", 34219a69263Sschwarze "COMPATIBILITY", 34319a69263Sschwarze "ERRORS", 34419a69263Sschwarze "SEE ALSO", 34519a69263Sschwarze "STANDARDS", 34619a69263Sschwarze "HISTORY", 34719a69263Sschwarze "AUTHORS", 34819a69263Sschwarze "CAVEATS", 34919a69263Sschwarze "BUGS", 35019a69263Sschwarze "SECURITY CONSIDERATIONS", 35119a69263Sschwarze NULL 35219a69263Sschwarze }; 353f73abda9Skristaps 35449aff9f8Sschwarze 355f73abda9Skristaps int 3566093755cSschwarze mdoc_valid_pre(struct mdoc *mdoc, struct mdoc_node *n) 357f73abda9Skristaps { 358f73abda9Skristaps v_pre *p; 359f73abda9Skristaps int line, pos; 36031e23753Sschwarze char *tp; 361f73abda9Skristaps 3622791bd1cSschwarze switch (n->type) { 36349aff9f8Sschwarze case MDOC_TEXT: 364f73abda9Skristaps tp = n->string; 365f73abda9Skristaps line = n->line; 366f73abda9Skristaps pos = n->pos; 36720fa2881Sschwarze check_text(mdoc, line, pos, tp); 3682791bd1cSschwarze /* FALLTHROUGH */ 36949aff9f8Sschwarze case MDOC_TBL: 3702791bd1cSschwarze /* FALLTHROUGH */ 37149aff9f8Sschwarze case MDOC_EQN: 3728d973ab1Sschwarze /* FALLTHROUGH */ 37349aff9f8Sschwarze case MDOC_ROOT: 37420fa2881Sschwarze return(1); 3752791bd1cSschwarze default: 3762791bd1cSschwarze break; 377f73abda9Skristaps } 378f73abda9Skristaps 37920fa2881Sschwarze check_args(mdoc, n); 38020fa2881Sschwarze 381f73abda9Skristaps if (NULL == mdoc_valids[n->tok].pre) 382f73abda9Skristaps return(1); 383f73abda9Skristaps for (p = mdoc_valids[n->tok].pre; *p; p++) 384f73abda9Skristaps if ( ! (*p)(mdoc, n)) 385f73abda9Skristaps return(0); 386f73abda9Skristaps return(1); 387f73abda9Skristaps } 388f73abda9Skristaps 389f73abda9Skristaps int 390f73abda9Skristaps mdoc_valid_post(struct mdoc *mdoc) 391f73abda9Skristaps { 392f73abda9Skristaps v_post *p; 393f73abda9Skristaps 394f73abda9Skristaps if (MDOC_VALID & mdoc->last->flags) 395f73abda9Skristaps return(1); 396f73abda9Skristaps mdoc->last->flags |= MDOC_VALID; 397f73abda9Skristaps 3982791bd1cSschwarze switch (mdoc->last->type) { 39949aff9f8Sschwarze case MDOC_TEXT: 4002791bd1cSschwarze /* FALLTHROUGH */ 40149aff9f8Sschwarze case MDOC_EQN: 4028d973ab1Sschwarze /* FALLTHROUGH */ 40349aff9f8Sschwarze case MDOC_TBL: 404f73abda9Skristaps return(1); 40549aff9f8Sschwarze case MDOC_ROOT: 406f73abda9Skristaps return(post_root(mdoc)); 4072791bd1cSschwarze default: 4082791bd1cSschwarze break; 4092791bd1cSschwarze } 410f73abda9Skristaps 411f73abda9Skristaps if (NULL == mdoc_valids[mdoc->last->tok].post) 412f73abda9Skristaps return(1); 413f73abda9Skristaps for (p = mdoc_valids[mdoc->last->tok].post; *p; p++) 414f73abda9Skristaps if ( ! (*p)(mdoc)) 415f73abda9Skristaps return(0); 416f73abda9Skristaps 417f73abda9Skristaps return(1); 418f73abda9Skristaps } 419f73abda9Skristaps 4207c2be9f8Sschwarze static int 4217ead8a4eSschwarze check_count(struct mdoc *mdoc, enum mdoc_type type, 4227c2be9f8Sschwarze enum check_lvl lvl, enum check_ineq ineq, int val) 423f73abda9Skristaps { 4247c2be9f8Sschwarze const char *p; 425bb648afaSschwarze enum mandocerr t; 4267c2be9f8Sschwarze 4277ead8a4eSschwarze if (mdoc->last->type != type) 4287c2be9f8Sschwarze return(1); 4297c2be9f8Sschwarze 4307c2be9f8Sschwarze switch (ineq) { 43149aff9f8Sschwarze case CHECK_LT: 4327c2be9f8Sschwarze p = "less than "; 4337ead8a4eSschwarze if (mdoc->last->nchild < val) 4347c2be9f8Sschwarze return(1); 4357c2be9f8Sschwarze break; 43649aff9f8Sschwarze case CHECK_GT: 437bb648afaSschwarze p = "more than "; 4387ead8a4eSschwarze if (mdoc->last->nchild > val) 4397c2be9f8Sschwarze return(1); 4407c2be9f8Sschwarze break; 44149aff9f8Sschwarze case CHECK_EQ: 4427c2be9f8Sschwarze p = ""; 4437ead8a4eSschwarze if (val == mdoc->last->nchild) 4447c2be9f8Sschwarze return(1); 4457c2be9f8Sschwarze break; 44620fa2881Sschwarze default: 44720fa2881Sschwarze abort(); 44820fa2881Sschwarze /* NOTREACHED */ 4497c2be9f8Sschwarze } 4507c2be9f8Sschwarze 451bb648afaSschwarze t = lvl == CHECK_WARN ? MANDOCERR_ARGCWARN : MANDOCERR_ARGCOUNT; 45249aff9f8Sschwarze mandoc_vmsg(t, mdoc->parse, mdoc->last->line, 45349aff9f8Sschwarze mdoc->last->pos, "want %s%d children (have %d)", 4547ead8a4eSschwarze p, val, mdoc->last->nchild); 45519a69263Sschwarze return(1); 4567c2be9f8Sschwarze } 457f73abda9Skristaps 4587c2be9f8Sschwarze static int 4597c2be9f8Sschwarze berr_ge1(POST_ARGS) 460f73abda9Skristaps { 461f73abda9Skristaps 462bb648afaSschwarze return(check_count(mdoc, MDOC_BODY, CHECK_ERROR, CHECK_GT, 0)); 463f73abda9Skristaps } 464f73abda9Skristaps 4657c2be9f8Sschwarze static int 4667c2be9f8Sschwarze bwarn_ge1(POST_ARGS) 4677c2be9f8Sschwarze { 4687c2be9f8Sschwarze return(check_count(mdoc, MDOC_BODY, CHECK_WARN, CHECK_GT, 0)); 469f73abda9Skristaps } 470f73abda9Skristaps 4717c2be9f8Sschwarze static int 4727c2be9f8Sschwarze ewarn_eq0(POST_ARGS) 4737c2be9f8Sschwarze { 4747c2be9f8Sschwarze return(check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 0)); 4757c2be9f8Sschwarze } 4767c2be9f8Sschwarze 4777c2be9f8Sschwarze static int 478bb648afaSschwarze ewarn_eq1(POST_ARGS) 479bb648afaSschwarze { 480bb648afaSschwarze return(check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 1)); 481bb648afaSschwarze } 482bb648afaSschwarze 483bb648afaSschwarze static int 4847c2be9f8Sschwarze ewarn_ge1(POST_ARGS) 4857c2be9f8Sschwarze { 4867c2be9f8Sschwarze return(check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_GT, 0)); 4877c2be9f8Sschwarze } 4887c2be9f8Sschwarze 4897c2be9f8Sschwarze static int 490bb648afaSschwarze ewarn_le1(POST_ARGS) 4917c2be9f8Sschwarze { 492bb648afaSschwarze return(check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_LT, 2)); 4937c2be9f8Sschwarze } 4947c2be9f8Sschwarze 4957c2be9f8Sschwarze static int 4967c2be9f8Sschwarze hwarn_eq0(POST_ARGS) 4977c2be9f8Sschwarze { 4987c2be9f8Sschwarze return(check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_EQ, 0)); 4997c2be9f8Sschwarze } 5007c2be9f8Sschwarze 5017c2be9f8Sschwarze static int 5027c2be9f8Sschwarze hwarn_eq1(POST_ARGS) 5037c2be9f8Sschwarze { 5047c2be9f8Sschwarze return(check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_EQ, 1)); 5057c2be9f8Sschwarze } 5067c2be9f8Sschwarze 5077c2be9f8Sschwarze static int 508bb648afaSschwarze hwarn_ge1(POST_ARGS) 509bb648afaSschwarze { 510bb648afaSschwarze return(check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_GT, 0)); 511bb648afaSschwarze } 512bb648afaSschwarze 51320fa2881Sschwarze static void 5147ead8a4eSschwarze check_args(struct mdoc *mdoc, struct mdoc_node *n) 515f73abda9Skristaps { 516f73abda9Skristaps int i; 517f73abda9Skristaps 518f73abda9Skristaps if (NULL == n->args) 51920fa2881Sschwarze return; 520f73abda9Skristaps 521f73abda9Skristaps assert(n->args->argc); 522f73abda9Skristaps for (i = 0; i < (int)n->args->argc; i++) 5237ead8a4eSschwarze check_argv(mdoc, n, &n->args->argv[i]); 524f73abda9Skristaps } 525f73abda9Skristaps 52620fa2881Sschwarze static void 5277ead8a4eSschwarze check_argv(struct mdoc *mdoc, struct mdoc_node *n, struct mdoc_argv *v) 528f73abda9Skristaps { 529f73abda9Skristaps int i; 530f73abda9Skristaps 531f73abda9Skristaps for (i = 0; i < (int)v->sz; i++) 5327ead8a4eSschwarze check_text(mdoc, v->line, v->pos, v->value[i]); 533f73abda9Skristaps 53420fa2881Sschwarze /* FIXME: move to post_std(). */ 53520fa2881Sschwarze 53620fa2881Sschwarze if (MDOC_Std == v->arg) 5377ead8a4eSschwarze if ( ! (v->sz || mdoc->meta.name)) 5387ead8a4eSschwarze mdoc_nmsg(mdoc, n, MANDOCERR_NONAME); 539f73abda9Skristaps } 540f73abda9Skristaps 54120fa2881Sschwarze static void 5427ead8a4eSschwarze check_text(struct mdoc *mdoc, int ln, int pos, char *p) 543f73abda9Skristaps { 54404e980cbSschwarze char *cp; 545769ee804Sschwarze 5467ead8a4eSschwarze if (MDOC_LITERAL & mdoc->flags) 5471cdbf331Sschwarze return; 5481cdbf331Sschwarze 5491cdbf331Sschwarze for (cp = p; NULL != (p = strchr(p, '\t')); p++) 5507ead8a4eSschwarze mdoc_pmsg(mdoc, ln, pos + (int)(p - cp), MANDOCERR_BADTAB); 551f73abda9Skristaps } 552f73abda9Skristaps 553f73abda9Skristaps static int 554dd94fa3aSschwarze check_parent(PRE_ARGS, enum mdoct tok, enum mdoc_type t) 555f73abda9Skristaps { 556f73abda9Skristaps 557f73abda9Skristaps assert(n->parent); 558f73abda9Skristaps if ((MDOC_ROOT == t || tok == n->parent->tok) && 559f73abda9Skristaps (t == n->parent->type)) 560f73abda9Skristaps return(1); 561f73abda9Skristaps 56249aff9f8Sschwarze mandoc_vmsg(MANDOCERR_SYNTCHILD, mdoc->parse, 56349aff9f8Sschwarze n->line, n->pos, "want parent %s", 56449aff9f8Sschwarze MDOC_ROOT == t ? "<root>" : mdoc_macronames[tok]); 5656e03d529Sschwarze return(0); 566f73abda9Skristaps } 567f73abda9Skristaps 568f73abda9Skristaps 569f73abda9Skristaps static int 570f73abda9Skristaps pre_display(PRE_ARGS) 571f73abda9Skristaps { 572f73abda9Skristaps struct mdoc_node *node; 573f73abda9Skristaps 574f73abda9Skristaps if (MDOC_BLOCK != n->type) 575f73abda9Skristaps return(1); 576f73abda9Skristaps 577f73abda9Skristaps for (node = mdoc->last->parent; node; node = node->parent) 578f73abda9Skristaps if (MDOC_BLOCK == node->type) 579f73abda9Skristaps if (MDOC_Bd == node->tok) 580f73abda9Skristaps break; 58120fa2881Sschwarze 58205c39368Sschwarze if (node) 583b723eac2Sschwarze mandoc_vmsg(MANDOCERR_BD_NEST, 584b723eac2Sschwarze mdoc->parse, n->line, n->pos, 585b723eac2Sschwarze "%s in Bd", mdoc_macronames[n->tok]); 58605c39368Sschwarze 58705c39368Sschwarze return(1); 588f73abda9Skristaps } 589f73abda9Skristaps 590f73abda9Skristaps static int 591f73abda9Skristaps pre_bl(PRE_ARGS) 592f73abda9Skristaps { 593769ee804Sschwarze struct mdoc_node *np; 594*4a9f685fSschwarze struct mdoc_argv *argv; 595*4a9f685fSschwarze int i; 596*4a9f685fSschwarze enum mdoc_list lt; 597f73abda9Skristaps 5986093755cSschwarze if (MDOC_BLOCK != n->type) { 599769ee804Sschwarze if (ENDBODY_NOT != n->end) { 600769ee804Sschwarze assert(n->pending); 601769ee804Sschwarze np = n->pending->parent; 602769ee804Sschwarze } else 603769ee804Sschwarze np = n->parent; 604769ee804Sschwarze 605769ee804Sschwarze assert(np); 606769ee804Sschwarze assert(MDOC_BLOCK == np->type); 607769ee804Sschwarze assert(MDOC_Bl == np->tok); 608f73abda9Skristaps return(1); 6096e03d529Sschwarze } 610f73abda9Skristaps 6116093755cSschwarze /* 6126093755cSschwarze * First figure out which kind of list to use: bind ourselves to 6136093755cSschwarze * the first mentioned list type and warn about any remaining 6146093755cSschwarze * ones. If we find no list type, we default to LIST_item. 6156093755cSschwarze */ 616f73abda9Skristaps 6176093755cSschwarze for (i = 0; n->args && i < (int)n->args->argc; i++) { 618*4a9f685fSschwarze argv = n->args->argv + i; 6196093755cSschwarze lt = LIST__NONE; 620*4a9f685fSschwarze switch (argv->arg) { 6216093755cSschwarze /* Set list types. */ 62249aff9f8Sschwarze case MDOC_Bullet: 6236093755cSschwarze lt = LIST_bullet; 6246093755cSschwarze break; 62549aff9f8Sschwarze case MDOC_Dash: 6266093755cSschwarze lt = LIST_dash; 6276093755cSschwarze break; 62849aff9f8Sschwarze case MDOC_Enum: 6296093755cSschwarze lt = LIST_enum; 6306093755cSschwarze break; 63149aff9f8Sschwarze case MDOC_Hyphen: 6326093755cSschwarze lt = LIST_hyphen; 6336093755cSschwarze break; 63449aff9f8Sschwarze case MDOC_Item: 6356093755cSschwarze lt = LIST_item; 6366093755cSschwarze break; 63749aff9f8Sschwarze case MDOC_Tag: 6386093755cSschwarze lt = LIST_tag; 6396093755cSschwarze break; 64049aff9f8Sschwarze case MDOC_Diag: 6416093755cSschwarze lt = LIST_diag; 6426093755cSschwarze break; 64349aff9f8Sschwarze case MDOC_Hang: 6446093755cSschwarze lt = LIST_hang; 6456093755cSschwarze break; 64649aff9f8Sschwarze case MDOC_Ohang: 6476093755cSschwarze lt = LIST_ohang; 6486093755cSschwarze break; 64949aff9f8Sschwarze case MDOC_Inset: 6506093755cSschwarze lt = LIST_inset; 6516093755cSschwarze break; 65249aff9f8Sschwarze case MDOC_Column: 6536093755cSschwarze lt = LIST_column; 65464d728e4Sschwarze break; 6556093755cSschwarze /* Set list arguments. */ 65649aff9f8Sschwarze case MDOC_Compact: 657*4a9f685fSschwarze if (n->norm->Bl.comp) 658*4a9f685fSschwarze mandoc_msg(MANDOCERR_ARG_REP, 659*4a9f685fSschwarze mdoc->parse, argv->line, 660*4a9f685fSschwarze argv->pos, "Bl -compact"); 661*4a9f685fSschwarze n->norm->Bl.comp = 1; 66250e63e03Sschwarze break; 66349aff9f8Sschwarze case MDOC_Width: 664*4a9f685fSschwarze if (0 == argv->sz) { 665*4a9f685fSschwarze mandoc_msg(MANDOCERR_ARG_EMPTY, 666*4a9f685fSschwarze mdoc->parse, argv->line, 667*4a9f685fSschwarze argv->pos, "Bl -width"); 668*4a9f685fSschwarze n->norm->Bl.width = "0n"; 66922972b14Sschwarze break; 67022972b14Sschwarze } 671*4a9f685fSschwarze if (NULL != n->norm->Bl.width) 672*4a9f685fSschwarze mandoc_vmsg(MANDOCERR_ARG_REP, 673*4a9f685fSschwarze mdoc->parse, argv->line, 674*4a9f685fSschwarze argv->pos, "Bl -width %s", 675*4a9f685fSschwarze argv->value[0]); 676*4a9f685fSschwarze n->norm->Bl.width = argv->value[0]; 67764d728e4Sschwarze break; 67849aff9f8Sschwarze case MDOC_Offset: 679*4a9f685fSschwarze if (0 == argv->sz) { 680*4a9f685fSschwarze mandoc_msg(MANDOCERR_ARG_EMPTY, 681*4a9f685fSschwarze mdoc->parse, argv->line, 682*4a9f685fSschwarze argv->pos, "Bl -offset"); 68331e23753Sschwarze break; 68431e23753Sschwarze } 685*4a9f685fSschwarze if (NULL != n->norm->Bl.offs) 686*4a9f685fSschwarze mandoc_vmsg(MANDOCERR_ARG_REP, 687*4a9f685fSschwarze mdoc->parse, argv->line, 688*4a9f685fSschwarze argv->pos, "Bl -offset %s", 689*4a9f685fSschwarze argv->value[0]); 690*4a9f685fSschwarze n->norm->Bl.offs = argv->value[0]; 691f73abda9Skristaps break; 692ddce0b0cSschwarze default: 693ddce0b0cSschwarze continue; 694f73abda9Skristaps } 695f73abda9Skristaps 6966093755cSschwarze /* Check: multiple list types. */ 6976093755cSschwarze 6988c62fbf5Sschwarze if (LIST__NONE != lt && n->norm->Bl.type != LIST__NONE) 69920fa2881Sschwarze mdoc_nmsg(mdoc, n, MANDOCERR_LISTREP); 7006093755cSschwarze 7016093755cSschwarze /* Assign list type. */ 7026093755cSschwarze 7038c62fbf5Sschwarze if (LIST__NONE != lt && n->norm->Bl.type == LIST__NONE) { 7048c62fbf5Sschwarze n->norm->Bl.type = lt; 705769ee804Sschwarze /* Set column information, too. */ 706769ee804Sschwarze if (LIST_column == lt) { 7078c62fbf5Sschwarze n->norm->Bl.ncols = 708769ee804Sschwarze n->args->argv[i].sz; 70904e980cbSschwarze n->norm->Bl.cols = (void *) 710769ee804Sschwarze n->args->argv[i].value; 711769ee804Sschwarze } 712769ee804Sschwarze } 7136093755cSschwarze 7146093755cSschwarze /* The list type should come first. */ 7156093755cSschwarze 7168c62fbf5Sschwarze if (n->norm->Bl.type == LIST__NONE) 7178c62fbf5Sschwarze if (n->norm->Bl.width || 7188c62fbf5Sschwarze n->norm->Bl.offs || 7198c62fbf5Sschwarze n->norm->Bl.comp) 72066788495Sschwarze mandoc_msg(MANDOCERR_BL_LATETYPE, 72166788495Sschwarze mdoc->parse, n->line, n->pos, 72266788495Sschwarze mdoc_argnames[n->args->argv[0].arg]); 7236093755cSschwarze continue; 7246093755cSschwarze } 7256093755cSschwarze 7266093755cSschwarze /* Allow lists to default to LIST_item. */ 7276093755cSschwarze 7288c62fbf5Sschwarze if (LIST__NONE == n->norm->Bl.type) { 72966788495Sschwarze mdoc_nmsg(mdoc, n, MANDOCERR_BL_NOTYPE); 7308c62fbf5Sschwarze n->norm->Bl.type = LIST_item; 7316e03d529Sschwarze } 732f73abda9Skristaps 73364d728e4Sschwarze /* 73464d728e4Sschwarze * Validate the width field. Some list types don't need width 73564d728e4Sschwarze * types and should be warned about them. Others should have it 7365eced068Sschwarze * and must also be warned. Yet others have a default and need 7375eced068Sschwarze * no warning. 73864d728e4Sschwarze */ 73964d728e4Sschwarze 7408c62fbf5Sschwarze switch (n->norm->Bl.type) { 74149aff9f8Sschwarze case LIST_tag: 7425eced068Sschwarze if (NULL == n->norm->Bl.width) 74366788495Sschwarze mdoc_nmsg(mdoc, n, MANDOCERR_BL_WIDTH); 744f73abda9Skristaps break; 74549aff9f8Sschwarze case LIST_column: 7466093755cSschwarze /* FALLTHROUGH */ 74749aff9f8Sschwarze case LIST_diag: 7486093755cSschwarze /* FALLTHROUGH */ 74949aff9f8Sschwarze case LIST_ohang: 7506093755cSschwarze /* FALLTHROUGH */ 75149aff9f8Sschwarze case LIST_inset: 7526093755cSschwarze /* FALLTHROUGH */ 75349aff9f8Sschwarze case LIST_item: 7548c62fbf5Sschwarze if (n->norm->Bl.width) 755817ac90bSschwarze mdoc_nmsg(mdoc, n, MANDOCERR_IGNARGV); 7566093755cSschwarze break; 75749aff9f8Sschwarze case LIST_bullet: 7585eced068Sschwarze /* FALLTHROUGH */ 75949aff9f8Sschwarze case LIST_dash: 7605eced068Sschwarze /* FALLTHROUGH */ 76149aff9f8Sschwarze case LIST_hyphen: 7625eced068Sschwarze if (NULL == n->norm->Bl.width) 7635eced068Sschwarze n->norm->Bl.width = "2n"; 7645eced068Sschwarze break; 76549aff9f8Sschwarze case LIST_enum: 7665eced068Sschwarze if (NULL == n->norm->Bl.width) 7675eced068Sschwarze n->norm->Bl.width = "3n"; 7685eced068Sschwarze break; 76964d728e4Sschwarze default: 770f73abda9Skristaps break; 77164d728e4Sschwarze } 77264d728e4Sschwarze 773f73abda9Skristaps return(1); 774f73abda9Skristaps } 775f73abda9Skristaps 776f73abda9Skristaps static int 777f73abda9Skristaps pre_bd(PRE_ARGS) 778f73abda9Skristaps { 779769ee804Sschwarze struct mdoc_node *np; 780*4a9f685fSschwarze struct mdoc_argv *argv; 781*4a9f685fSschwarze int i; 782*4a9f685fSschwarze enum mdoc_disp dt; 783f73abda9Skristaps 78431e23753Sschwarze if (MDOC_BLOCK != n->type) { 785769ee804Sschwarze if (ENDBODY_NOT != n->end) { 786769ee804Sschwarze assert(n->pending); 787769ee804Sschwarze np = n->pending->parent; 788769ee804Sschwarze } else 789769ee804Sschwarze np = n->parent; 790769ee804Sschwarze 791769ee804Sschwarze assert(np); 792769ee804Sschwarze assert(MDOC_BLOCK == np->type); 793769ee804Sschwarze assert(MDOC_Bd == np->tok); 794f73abda9Skristaps return(1); 7956e03d529Sschwarze } 796f73abda9Skristaps 79731e23753Sschwarze for (i = 0; n->args && i < (int)n->args->argc; i++) { 798*4a9f685fSschwarze argv = n->args->argv + i; 79931e23753Sschwarze dt = DISP__NONE; 80031e23753Sschwarze 801*4a9f685fSschwarze switch (argv->arg) { 80249aff9f8Sschwarze case MDOC_Centred: 80331e23753Sschwarze dt = DISP_centred; 80431e23753Sschwarze break; 80549aff9f8Sschwarze case MDOC_Ragged: 80631e23753Sschwarze dt = DISP_ragged; 80731e23753Sschwarze break; 80849aff9f8Sschwarze case MDOC_Unfilled: 80931e23753Sschwarze dt = DISP_unfilled; 81031e23753Sschwarze break; 81149aff9f8Sschwarze case MDOC_Filled: 81231e23753Sschwarze dt = DISP_filled; 81331e23753Sschwarze break; 81449aff9f8Sschwarze case MDOC_Literal: 81531e23753Sschwarze dt = DISP_literal; 816f73abda9Skristaps break; 81749aff9f8Sschwarze case MDOC_File: 81831e23753Sschwarze mdoc_nmsg(mdoc, n, MANDOCERR_BADDISP); 8196e03d529Sschwarze return(0); 82049aff9f8Sschwarze case MDOC_Offset: 821*4a9f685fSschwarze if (0 == argv->sz) { 822*4a9f685fSschwarze mandoc_msg(MANDOCERR_ARG_EMPTY, 823*4a9f685fSschwarze mdoc->parse, argv->line, 824*4a9f685fSschwarze argv->pos, "Bd -offset"); 825f73abda9Skristaps break; 826f73abda9Skristaps } 827*4a9f685fSschwarze if (NULL != n->norm->Bd.offs) 828*4a9f685fSschwarze mandoc_vmsg(MANDOCERR_ARG_REP, 829*4a9f685fSschwarze mdoc->parse, argv->line, 830*4a9f685fSschwarze argv->pos, "Bd -offset %s", 831*4a9f685fSschwarze argv->value[0]); 832*4a9f685fSschwarze n->norm->Bd.offs = argv->value[0]; 83331e23753Sschwarze break; 83449aff9f8Sschwarze case MDOC_Compact: 835*4a9f685fSschwarze if (n->norm->Bd.comp) 836*4a9f685fSschwarze mandoc_msg(MANDOCERR_ARG_REP, 837*4a9f685fSschwarze mdoc->parse, argv->line, 838*4a9f685fSschwarze argv->pos, "Bd -compact"); 839*4a9f685fSschwarze n->norm->Bd.comp = 1; 84031e23753Sschwarze break; 84131e23753Sschwarze default: 84231e23753Sschwarze abort(); 84331e23753Sschwarze /* NOTREACHED */ 84431e23753Sschwarze } 84531e23753Sschwarze 84631e23753Sschwarze /* Check whether a type has already been assigned. */ 84731e23753Sschwarze 8488c62fbf5Sschwarze if (DISP__NONE != dt && n->norm->Bd.type != DISP__NONE) 84920fa2881Sschwarze mdoc_nmsg(mdoc, n, MANDOCERR_DISPREP); 85031e23753Sschwarze 85131e23753Sschwarze /* Make our type assignment. */ 85231e23753Sschwarze 8538c62fbf5Sschwarze if (DISP__NONE != dt && n->norm->Bd.type == DISP__NONE) 8548c62fbf5Sschwarze n->norm->Bd.type = dt; 85531e23753Sschwarze } 85631e23753Sschwarze 8578c62fbf5Sschwarze if (DISP__NONE == n->norm->Bd.type) { 85866788495Sschwarze mdoc_nmsg(mdoc, n, MANDOCERR_BD_NOTYPE); 8598c62fbf5Sschwarze n->norm->Bd.type = DISP_ragged; 86031e23753Sschwarze } 86131e23753Sschwarze 86231e23753Sschwarze return(1); 863f73abda9Skristaps } 864f73abda9Skristaps 865f73abda9Skristaps static int 866f73abda9Skristaps pre_ss(PRE_ARGS) 867f73abda9Skristaps { 868f73abda9Skristaps 869f73abda9Skristaps if (MDOC_BLOCK != n->type) 870f73abda9Skristaps return(1); 871f73abda9Skristaps return(check_parent(mdoc, n, MDOC_Sh, MDOC_BODY)); 872f73abda9Skristaps } 873f73abda9Skristaps 874f73abda9Skristaps static int 875f73abda9Skristaps pre_sh(PRE_ARGS) 876f73abda9Skristaps { 877f73abda9Skristaps 878f73abda9Skristaps if (MDOC_BLOCK != n->type) 879f73abda9Skristaps return(1); 880a4c002ecSschwarze return(check_parent(mdoc, n, MDOC_MAX, MDOC_ROOT)); 881f73abda9Skristaps } 882f73abda9Skristaps 883f73abda9Skristaps static int 884f73abda9Skristaps pre_it(PRE_ARGS) 885f73abda9Skristaps { 886f73abda9Skristaps 887f73abda9Skristaps if (MDOC_BLOCK != n->type) 888f73abda9Skristaps return(1); 88920fa2881Sschwarze 890f73abda9Skristaps return(check_parent(mdoc, n, MDOC_Bl, MDOC_BODY)); 891f73abda9Skristaps } 892f73abda9Skristaps 893f73abda9Skristaps static int 894f73abda9Skristaps pre_an(PRE_ARGS) 895f73abda9Skristaps { 8966475d5b0Sschwarze int i; 897f73abda9Skristaps 898769ee804Sschwarze if (NULL == n->args) 899f73abda9Skristaps return(1); 900769ee804Sschwarze 9016475d5b0Sschwarze for (i = 1; i < (int)n->args->argc; i++) 90220fa2881Sschwarze mdoc_pmsg(mdoc, n->args->argv[i].line, 90320fa2881Sschwarze n->args->argv[i].pos, MANDOCERR_IGNARGV); 9047c2be9f8Sschwarze 905769ee804Sschwarze if (MDOC_Split == n->args->argv[0].arg) 9068c62fbf5Sschwarze n->norm->An.auth = AUTH_split; 907769ee804Sschwarze else if (MDOC_Nosplit == n->args->argv[0].arg) 9088c62fbf5Sschwarze n->norm->An.auth = AUTH_nosplit; 909769ee804Sschwarze else 910769ee804Sschwarze abort(); 911769ee804Sschwarze 912769ee804Sschwarze return(1); 913f73abda9Skristaps } 914f73abda9Skristaps 915f73abda9Skristaps static int 91620fa2881Sschwarze pre_std(PRE_ARGS) 917f73abda9Skristaps { 918f73abda9Skristaps 91920fa2881Sschwarze if (n->args && 1 == n->args->argc) 92020fa2881Sschwarze if (MDOC_Std == n->args->argv[0].arg) 92120fa2881Sschwarze return(1); 922f73abda9Skristaps 92366788495Sschwarze mandoc_msg(MANDOCERR_ARG_STD, mdoc->parse, 92466788495Sschwarze n->line, n->pos, mdoc_macronames[n->tok]); 9256093755cSschwarze return(1); 9266093755cSschwarze } 9276093755cSschwarze 9286093755cSschwarze static int 929551cd4a8Sschwarze pre_obsolete(PRE_ARGS) 930551cd4a8Sschwarze { 931551cd4a8Sschwarze 932551cd4a8Sschwarze if (MDOC_ELEM == n->type || MDOC_BLOCK == n->type) 933551cd4a8Sschwarze mandoc_msg(MANDOCERR_MACRO_OBS, mdoc->parse, 934551cd4a8Sschwarze n->line, n->pos, mdoc_macronames[n->tok]); 935551cd4a8Sschwarze return(1); 936551cd4a8Sschwarze } 937551cd4a8Sschwarze 938551cd4a8Sschwarze static int 939f73abda9Skristaps pre_dt(PRE_ARGS) 940f73abda9Skristaps { 941f73abda9Skristaps 942b058e777Sschwarze if (NULL == mdoc->meta.date || mdoc->meta.os) 94351fcab2fSschwarze mandoc_msg(MANDOCERR_PROLOG_ORDER, mdoc->parse, 94451fcab2fSschwarze n->line, n->pos, "Dt"); 94520fa2881Sschwarze 946f73abda9Skristaps if (mdoc->meta.title) 94751fcab2fSschwarze mandoc_msg(MANDOCERR_PROLOG_REP, mdoc->parse, 94851fcab2fSschwarze n->line, n->pos, "Dt"); 94920fa2881Sschwarze 950f73abda9Skristaps return(1); 951f73abda9Skristaps } 952f73abda9Skristaps 953f73abda9Skristaps static int 954f73abda9Skristaps pre_os(PRE_ARGS) 955f73abda9Skristaps { 956f73abda9Skristaps 957b058e777Sschwarze if (NULL == mdoc->meta.title || NULL == mdoc->meta.date) 95851fcab2fSschwarze mandoc_msg(MANDOCERR_PROLOG_ORDER, mdoc->parse, 95951fcab2fSschwarze n->line, n->pos, "Os"); 96020fa2881Sschwarze 961f73abda9Skristaps if (mdoc->meta.os) 96251fcab2fSschwarze mandoc_msg(MANDOCERR_PROLOG_REP, mdoc->parse, 96351fcab2fSschwarze n->line, n->pos, "Os"); 96420fa2881Sschwarze 965f73abda9Skristaps return(1); 966f73abda9Skristaps } 967f73abda9Skristaps 968f73abda9Skristaps static int 969f73abda9Skristaps pre_dd(PRE_ARGS) 970f73abda9Skristaps { 971f73abda9Skristaps 972f73abda9Skristaps if (mdoc->meta.title || mdoc->meta.os) 97351fcab2fSschwarze mandoc_msg(MANDOCERR_PROLOG_ORDER, mdoc->parse, 97451fcab2fSschwarze n->line, n->pos, "Dd"); 97520fa2881Sschwarze 976f73abda9Skristaps if (mdoc->meta.date) 97751fcab2fSschwarze mandoc_msg(MANDOCERR_PROLOG_REP, mdoc->parse, 97851fcab2fSschwarze n->line, n->pos, "Dd"); 97920fa2881Sschwarze 980f73abda9Skristaps return(1); 981f73abda9Skristaps } 982f73abda9Skristaps 983f73abda9Skristaps static int 984f73abda9Skristaps post_bf(POST_ARGS) 985f73abda9Skristaps { 986ecb10c32Sschwarze struct mdoc_node *np, *nch; 987ddce0b0cSschwarze enum mdocargt arg; 988f73abda9Skristaps 989769ee804Sschwarze /* 990769ee804Sschwarze * Unlike other data pointers, these are "housed" by the HEAD 991769ee804Sschwarze * element, which contains the goods. 992769ee804Sschwarze */ 993769ee804Sschwarze 994769ee804Sschwarze if (MDOC_HEAD != mdoc->last->type) { 995769ee804Sschwarze if (ENDBODY_NOT != mdoc->last->end) { 996769ee804Sschwarze assert(mdoc->last->pending); 997769ee804Sschwarze np = mdoc->last->pending->parent->head; 998769ee804Sschwarze } else if (MDOC_BLOCK != mdoc->last->type) { 999769ee804Sschwarze np = mdoc->last->parent->head; 1000769ee804Sschwarze } else 1001769ee804Sschwarze np = mdoc->last->head; 1002769ee804Sschwarze 1003769ee804Sschwarze assert(np); 1004769ee804Sschwarze assert(MDOC_HEAD == np->type); 1005769ee804Sschwarze assert(MDOC_Bf == np->tok); 1006f73abda9Skristaps return(1); 10076e03d529Sschwarze } 1008f73abda9Skristaps 1009769ee804Sschwarze np = mdoc->last; 1010769ee804Sschwarze assert(MDOC_BLOCK == np->parent->type); 1011769ee804Sschwarze assert(MDOC_Bf == np->parent->tok); 101250d41253Sschwarze 1013ecb10c32Sschwarze /* Check the number of arguments. */ 1014f73abda9Skristaps 1015ecb10c32Sschwarze nch = np->child; 1016ecb10c32Sschwarze if (NULL == np->parent->args) { 1017ecb10c32Sschwarze if (NULL == nch) { 1018ecb10c32Sschwarze mdoc_nmsg(mdoc, np, MANDOCERR_BF_NOFONT); 101920fa2881Sschwarze return(1); 102020fa2881Sschwarze } 1021ecb10c32Sschwarze nch = nch->next; 1022ecb10c32Sschwarze } 1023ecb10c32Sschwarze if (NULL != nch) 1024ecb10c32Sschwarze mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse, 1025ecb10c32Sschwarze nch->line, nch->pos, "Bf ... %s", nch->string); 1026769ee804Sschwarze 1027769ee804Sschwarze /* Extract argument into data. */ 1028769ee804Sschwarze 1029769ee804Sschwarze if (np->parent->args) { 1030769ee804Sschwarze arg = np->parent->args->argv[0].arg; 1031769ee804Sschwarze if (MDOC_Emphasis == arg) 10328c62fbf5Sschwarze np->norm->Bf.font = FONT_Em; 1033769ee804Sschwarze else if (MDOC_Literal == arg) 10348c62fbf5Sschwarze np->norm->Bf.font = FONT_Li; 1035769ee804Sschwarze else if (MDOC_Symbolic == arg) 10368c62fbf5Sschwarze np->norm->Bf.font = FONT_Sy; 1037769ee804Sschwarze else 1038769ee804Sschwarze abort(); 1039769ee804Sschwarze return(1); 1040769ee804Sschwarze } 1041769ee804Sschwarze 1042769ee804Sschwarze /* Extract parameter into data. */ 1043769ee804Sschwarze 1044769ee804Sschwarze if (0 == strcmp(np->child->string, "Em")) 10458c62fbf5Sschwarze np->norm->Bf.font = FONT_Em; 1046769ee804Sschwarze else if (0 == strcmp(np->child->string, "Li")) 10478c62fbf5Sschwarze np->norm->Bf.font = FONT_Li; 1048769ee804Sschwarze else if (0 == strcmp(np->child->string, "Sy")) 10498c62fbf5Sschwarze np->norm->Bf.font = FONT_Sy; 105020fa2881Sschwarze else 1051ecb10c32Sschwarze mandoc_vmsg(MANDOCERR_BF_BADFONT, mdoc->parse, 1052ecb10c32Sschwarze np->child->line, np->child->pos, 1053ecb10c32Sschwarze "Bf %s", np->child->string); 1054769ee804Sschwarze 1055769ee804Sschwarze return(1); 1056f73abda9Skristaps } 1057f73abda9Skristaps 1058f73abda9Skristaps static int 105971719887Sschwarze post_lb(POST_ARGS) 106071719887Sschwarze { 106177e000ffSschwarze struct mdoc_node *n; 106277e000ffSschwarze const char *stdlibname; 106377e000ffSschwarze char *libname; 106471719887Sschwarze 1065bb648afaSschwarze check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 1); 1066bb648afaSschwarze 106777e000ffSschwarze n = mdoc->last->child; 106820fa2881Sschwarze 106977e000ffSschwarze assert(n); 107077e000ffSschwarze assert(MDOC_TEXT == n->type); 107120fa2881Sschwarze 107277e000ffSschwarze if (NULL == (stdlibname = mdoc_a2lib(n->string))) 107377e000ffSschwarze mandoc_asprintf(&libname, 107477e000ffSschwarze "library \\(lq%s\\(rq", n->string); 107577e000ffSschwarze else 107677e000ffSschwarze libname = mandoc_strdup(stdlibname); 107720fa2881Sschwarze 107877e000ffSschwarze free(n->string); 107977e000ffSschwarze n->string = libname; 108020fa2881Sschwarze return(1); 108120fa2881Sschwarze } 108271719887Sschwarze 108371719887Sschwarze static int 1084b31af00dSschwarze post_eoln(POST_ARGS) 1085b31af00dSschwarze { 1086ecb10c32Sschwarze const struct mdoc_node *n; 1087b31af00dSschwarze 1088ecb10c32Sschwarze n = mdoc->last; 1089ecb10c32Sschwarze if (n->child) 1090ecb10c32Sschwarze mandoc_vmsg(MANDOCERR_ARG_SKIP, 1091ecb10c32Sschwarze mdoc->parse, n->line, n->pos, 1092ecb10c32Sschwarze "%s %s", mdoc_macronames[n->tok], 1093ecb10c32Sschwarze n->child->string); 1094b31af00dSschwarze return(1); 1095b31af00dSschwarze } 1096b31af00dSschwarze 1097b31af00dSschwarze static int 10988521b0bcSschwarze post_vt(POST_ARGS) 10998521b0bcSschwarze { 11008521b0bcSschwarze const struct mdoc_node *n; 11018521b0bcSschwarze 11028521b0bcSschwarze /* 11038521b0bcSschwarze * The Vt macro comes in both ELEM and BLOCK form, both of which 11048521b0bcSschwarze * have different syntaxes (yet more context-sensitive 1105e7a93ef3Sschwarze * behaviour). ELEM types must have a child, which is already 1106e7a93ef3Sschwarze * guaranteed by the in_line parsing routine; BLOCK types, 11078521b0bcSschwarze * specifically the BODY, should only have TEXT children. 11088521b0bcSschwarze */ 11098521b0bcSschwarze 11108521b0bcSschwarze if (MDOC_BODY != mdoc->last->type) 11118521b0bcSschwarze return(1); 11128521b0bcSschwarze 11138521b0bcSschwarze for (n = mdoc->last->child; n; n = n->next) 1114bc49dbe1Sschwarze if (MDOC_TEXT != n->type) 1115dd25b57cSschwarze mandoc_msg(MANDOCERR_VT_CHILD, mdoc->parse, 1116dd25b57cSschwarze n->line, n->pos, mdoc_macronames[n->tok]); 11178521b0bcSschwarze 11188521b0bcSschwarze return(1); 11198521b0bcSschwarze } 11208521b0bcSschwarze 11218521b0bcSschwarze static int 1122f73abda9Skristaps post_nm(POST_ARGS) 1123f73abda9Skristaps { 112420fa2881Sschwarze 1125160ac481Sschwarze if (NULL != mdoc->meta.name) 112620fa2881Sschwarze return(1); 112720fa2881Sschwarze 112883af2bccSschwarze mdoc_deroff(&mdoc->meta.name, mdoc->last); 112920fa2881Sschwarze 113083af2bccSschwarze if (NULL == mdoc->meta.name) { 1131160ac481Sschwarze mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NONAME); 1132160ac481Sschwarze mdoc->meta.name = mandoc_strdup("UNKNOWN"); 1133160ac481Sschwarze } 113420fa2881Sschwarze return(1); 113520fa2881Sschwarze } 113620fa2881Sschwarze 113720fa2881Sschwarze static int 113820fa2881Sschwarze post_literal(POST_ARGS) 113920fa2881Sschwarze { 114020fa2881Sschwarze 114120fa2881Sschwarze /* 114220fa2881Sschwarze * The `Dl' (note "el" not "one") and `Bd' macros unset the 114320fa2881Sschwarze * MDOC_LITERAL flag as they leave. Note that `Bd' only sets 114420fa2881Sschwarze * this in literal mode, but it doesn't hurt to just switch it 114520fa2881Sschwarze * off in general since displays can't be nested. 114620fa2881Sschwarze */ 114720fa2881Sschwarze 114820fa2881Sschwarze if (MDOC_BODY == mdoc->last->type) 114920fa2881Sschwarze mdoc->flags &= ~MDOC_LITERAL; 115020fa2881Sschwarze 115120fa2881Sschwarze return(1); 115220fa2881Sschwarze } 115320fa2881Sschwarze 115420fa2881Sschwarze static int 115520fa2881Sschwarze post_defaults(POST_ARGS) 115620fa2881Sschwarze { 115720fa2881Sschwarze struct mdoc_node *nn; 115820fa2881Sschwarze 115920fa2881Sschwarze /* 116020fa2881Sschwarze * The `Ar' defaults to "file ..." if no value is provided as an 116120fa2881Sschwarze * argument; the `Mt' and `Pa' macros use "~"; the `Li' just 116220fa2881Sschwarze * gets an empty string. 116320fa2881Sschwarze */ 1164f73abda9Skristaps 1165f73abda9Skristaps if (mdoc->last->child) 1166f73abda9Skristaps return(1); 116720fa2881Sschwarze 116820fa2881Sschwarze nn = mdoc->last; 116920fa2881Sschwarze mdoc->next = MDOC_NEXT_CHILD; 117020fa2881Sschwarze 117120fa2881Sschwarze switch (nn->tok) { 117249aff9f8Sschwarze case MDOC_Ar: 117320fa2881Sschwarze if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "file")) 117420fa2881Sschwarze return(0); 117520fa2881Sschwarze if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "...")) 117620fa2881Sschwarze return(0); 117720fa2881Sschwarze break; 117849aff9f8Sschwarze case MDOC_At: 117920fa2881Sschwarze if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "AT&T")) 118020fa2881Sschwarze return(0); 118120fa2881Sschwarze if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "UNIX")) 118220fa2881Sschwarze return(0); 118320fa2881Sschwarze break; 118449aff9f8Sschwarze case MDOC_Li: 118520fa2881Sschwarze if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "")) 118620fa2881Sschwarze return(0); 118720fa2881Sschwarze break; 118849aff9f8Sschwarze case MDOC_Pa: 118920fa2881Sschwarze /* FALLTHROUGH */ 119049aff9f8Sschwarze case MDOC_Mt: 119120fa2881Sschwarze if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "~")) 119220fa2881Sschwarze return(0); 119320fa2881Sschwarze break; 119420fa2881Sschwarze default: 119520fa2881Sschwarze abort(); 119620fa2881Sschwarze /* NOTREACHED */ 1197f73abda9Skristaps } 1198f73abda9Skristaps 119920fa2881Sschwarze mdoc->last = nn; 120020fa2881Sschwarze return(1); 120120fa2881Sschwarze } 1202f73abda9Skristaps 1203f73abda9Skristaps static int 1204f73abda9Skristaps post_at(POST_ARGS) 1205f73abda9Skristaps { 12060b2f1307Sschwarze struct mdoc_node *n; 12070b2f1307Sschwarze const char *std_att; 12080b2f1307Sschwarze char *att; 120920fa2881Sschwarze 121020fa2881Sschwarze /* 121120fa2881Sschwarze * If we have a child, look it up in the standard keys. If a 121220fa2881Sschwarze * key exist, use that instead of the child; if it doesn't, 121320fa2881Sschwarze * prefix "AT&T UNIX " to the existing data. 121420fa2881Sschwarze */ 1215f73abda9Skristaps 12160b2f1307Sschwarze if (NULL == (n = mdoc->last->child)) 1217f73abda9Skristaps return(1); 121820fa2881Sschwarze 12190b2f1307Sschwarze assert(MDOC_TEXT == n->type); 12200b2f1307Sschwarze if (NULL == (std_att = mdoc_a2att(n->string))) { 122120fa2881Sschwarze mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADATT); 12220b2f1307Sschwarze mandoc_asprintf(&att, "AT&T UNIX %s", n->string); 12230b2f1307Sschwarze } else 12240b2f1307Sschwarze att = mandoc_strdup(std_att); 1225f73abda9Skristaps 12260b2f1307Sschwarze free(n->string); 12270b2f1307Sschwarze n->string = att; 122820fa2881Sschwarze return(1); 122920fa2881Sschwarze } 1230f73abda9Skristaps 1231f73abda9Skristaps static int 1232f73abda9Skristaps post_an(POST_ARGS) 1233f73abda9Skristaps { 1234769ee804Sschwarze struct mdoc_node *np; 1235f73abda9Skristaps 1236769ee804Sschwarze np = mdoc->last; 1237e7a93ef3Sschwarze if (AUTH__NONE == np->norm->An.auth) { 1238e7a93ef3Sschwarze if (0 == np->child) 1239e7a93ef3Sschwarze check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_GT, 0); 1240e7a93ef3Sschwarze } else if (np->child) 1241bb648afaSschwarze check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 0); 124220fa2881Sschwarze 124320fa2881Sschwarze return(1); 1244f73abda9Skristaps } 1245f73abda9Skristaps 1246f73abda9Skristaps static int 1247551cd4a8Sschwarze post_en(POST_ARGS) 1248551cd4a8Sschwarze { 1249551cd4a8Sschwarze 1250551cd4a8Sschwarze if (MDOC_BLOCK == mdoc->last->type) 1251551cd4a8Sschwarze mdoc->last->norm->Es = mdoc->last_es; 1252551cd4a8Sschwarze return(1); 1253551cd4a8Sschwarze } 1254551cd4a8Sschwarze 1255551cd4a8Sschwarze static int 1256551cd4a8Sschwarze post_es(POST_ARGS) 1257551cd4a8Sschwarze { 1258551cd4a8Sschwarze 1259551cd4a8Sschwarze mdoc->last_es = mdoc->last; 1260551cd4a8Sschwarze return(1); 1261551cd4a8Sschwarze } 1262551cd4a8Sschwarze 1263551cd4a8Sschwarze static int 1264f73abda9Skristaps post_it(POST_ARGS) 1265f73abda9Skristaps { 126619a69263Sschwarze int i, cols; 12676093755cSschwarze enum mdoc_list lt; 12689530682eSschwarze struct mdoc_node *nbl, *nit, *nch; 12696093755cSschwarze enum mandocerr er; 1270f73abda9Skristaps 12719530682eSschwarze nit = mdoc->last; 12729530682eSschwarze if (MDOC_BLOCK != nit->type) 1273f73abda9Skristaps return(1); 1274f73abda9Skristaps 12759530682eSschwarze nbl = nit->parent->parent; 12769530682eSschwarze lt = nbl->norm->Bl.type; 12776093755cSschwarze 12786093755cSschwarze switch (lt) { 127949aff9f8Sschwarze case LIST_tag: 12809530682eSschwarze /* FALLTHROUGH */ 128149aff9f8Sschwarze case LIST_hang: 1282f73abda9Skristaps /* FALLTHROUGH */ 128349aff9f8Sschwarze case LIST_ohang: 1284f73abda9Skristaps /* FALLTHROUGH */ 128549aff9f8Sschwarze case LIST_inset: 1286f73abda9Skristaps /* FALLTHROUGH */ 128749aff9f8Sschwarze case LIST_diag: 12889530682eSschwarze if (NULL == nit->head->child) 12899530682eSschwarze mandoc_msg(MANDOCERR_IT_NOHEAD, 12909530682eSschwarze mdoc->parse, nit->line, nit->pos, 12919530682eSschwarze mdoc_argnames[nbl->args->argv[0].arg]); 1292f73abda9Skristaps break; 129349aff9f8Sschwarze case LIST_bullet: 1294f73abda9Skristaps /* FALLTHROUGH */ 129549aff9f8Sschwarze case LIST_dash: 1296f73abda9Skristaps /* FALLTHROUGH */ 129749aff9f8Sschwarze case LIST_enum: 1298f73abda9Skristaps /* FALLTHROUGH */ 129949aff9f8Sschwarze case LIST_hyphen: 13009530682eSschwarze if (NULL == nit->body->child) 130166788495Sschwarze mandoc_msg(MANDOCERR_IT_NOBODY, 130266788495Sschwarze mdoc->parse, nit->line, nit->pos, 130366788495Sschwarze mdoc_argnames[nbl->args->argv[0].arg]); 1304f73abda9Skristaps /* FALLTHROUGH */ 130549aff9f8Sschwarze case LIST_item: 13069530682eSschwarze if (NULL != nit->head->child) 1307ecb10c32Sschwarze mandoc_vmsg(MANDOCERR_ARG_SKIP, 1308ecb10c32Sschwarze mdoc->parse, nit->line, nit->pos, 1309ecb10c32Sschwarze "It %s", nit->head->child->string); 1310f73abda9Skristaps break; 131149aff9f8Sschwarze case LIST_column: 13129530682eSschwarze cols = (int)nbl->norm->Bl.ncols; 13136093755cSschwarze 13149530682eSschwarze assert(NULL == nit->head->child); 13156093755cSschwarze 13169530682eSschwarze for (i = 0, nch = nit->child; nch; nch = nch->next) 13179530682eSschwarze if (MDOC_BODY == nch->type) 1318f73abda9Skristaps i++; 131953292e81Sschwarze 13206093755cSschwarze if (i < cols) 13216093755cSschwarze er = MANDOCERR_ARGCOUNT; 13226093755cSschwarze else if (i == cols || i == cols + 1) 1323f73abda9Skristaps break; 13246093755cSschwarze else 13256093755cSschwarze er = MANDOCERR_SYNTARGCOUNT; 132653292e81Sschwarze 13279530682eSschwarze mandoc_vmsg(er, mdoc->parse, nit->line, nit->pos, 13286e03d529Sschwarze "columns == %d (have %d)", cols, i); 132919a69263Sschwarze return(MANDOCERR_ARGCOUNT == er); 1330f73abda9Skristaps default: 133166788495Sschwarze abort(); 1332f73abda9Skristaps } 1333f73abda9Skristaps 1334f73abda9Skristaps return(1); 1335f73abda9Skristaps } 1336f73abda9Skristaps 133720fa2881Sschwarze static int 133820fa2881Sschwarze post_bl_block(POST_ARGS) 133920fa2881Sschwarze { 1340bb99f0faSschwarze struct mdoc_node *n, *ni, *nc; 134120fa2881Sschwarze 134220fa2881Sschwarze /* 134320fa2881Sschwarze * These are fairly complicated, so we've broken them into two 134420fa2881Sschwarze * functions. post_bl_block_tag() is called when a -tag is 134520fa2881Sschwarze * specified, but no -width (it must be guessed). The second 134620fa2881Sschwarze * when a -width is specified (macro indicators must be 134720fa2881Sschwarze * rewritten into real lengths). 134820fa2881Sschwarze */ 134920fa2881Sschwarze 135020fa2881Sschwarze n = mdoc->last; 135120fa2881Sschwarze 13528c62fbf5Sschwarze if (LIST_tag == n->norm->Bl.type && 13538c62fbf5Sschwarze NULL == n->norm->Bl.width) { 135420fa2881Sschwarze if ( ! post_bl_block_tag(mdoc)) 135520fa2881Sschwarze return(0); 1356bb99f0faSschwarze assert(n->norm->Bl.width); 13578c62fbf5Sschwarze } else if (NULL != n->norm->Bl.width) { 135820fa2881Sschwarze if ( ! post_bl_block_width(mdoc)) 135920fa2881Sschwarze return(0); 13608c62fbf5Sschwarze assert(n->norm->Bl.width); 1361bb99f0faSschwarze } 1362bb99f0faSschwarze 1363bb99f0faSschwarze for (ni = n->body->child; ni; ni = ni->next) { 1364bb99f0faSschwarze if (NULL == ni->body) 1365bb99f0faSschwarze continue; 1366bb99f0faSschwarze nc = ni->body->last; 1367bb99f0faSschwarze while (NULL != nc) { 1368bb99f0faSschwarze switch (nc->tok) { 136949aff9f8Sschwarze case MDOC_Pp: 1370bb99f0faSschwarze /* FALLTHROUGH */ 137149aff9f8Sschwarze case MDOC_Lp: 1372bb99f0faSschwarze /* FALLTHROUGH */ 137349aff9f8Sschwarze case MDOC_br: 1374bb99f0faSschwarze break; 1375bb99f0faSschwarze default: 1376bb99f0faSschwarze nc = NULL; 1377bb99f0faSschwarze continue; 1378bb99f0faSschwarze } 1379bb99f0faSschwarze if (NULL == ni->next) { 138020369664Sschwarze mandoc_msg(MANDOCERR_PAR_MOVE, 138120369664Sschwarze mdoc->parse, nc->line, nc->pos, 138220369664Sschwarze mdoc_macronames[nc->tok]); 1383bb99f0faSschwarze if ( ! mdoc_node_relink(mdoc, nc)) 1384bb99f0faSschwarze return(0); 1385bb99f0faSschwarze } else if (0 == n->norm->Bl.comp && 1386bb99f0faSschwarze LIST_column != n->norm->Bl.type) { 138720369664Sschwarze mandoc_vmsg(MANDOCERR_PAR_SKIP, 138820369664Sschwarze mdoc->parse, nc->line, nc->pos, 138920369664Sschwarze "%s before It", 139020369664Sschwarze mdoc_macronames[nc->tok]); 1391bb99f0faSschwarze mdoc_node_delete(mdoc, nc); 1392bb99f0faSschwarze } else 1393bb99f0faSschwarze break; 1394bb99f0faSschwarze nc = ni->body->last; 1395bb99f0faSschwarze } 1396bb99f0faSschwarze } 139720fa2881Sschwarze return(1); 139820fa2881Sschwarze } 139920fa2881Sschwarze 140020fa2881Sschwarze static int 140120fa2881Sschwarze post_bl_block_width(POST_ARGS) 140220fa2881Sschwarze { 140320fa2881Sschwarze size_t width; 140420fa2881Sschwarze int i; 140520fa2881Sschwarze enum mdoct tok; 140620fa2881Sschwarze struct mdoc_node *n; 140747813146Sschwarze char buf[24]; 140820fa2881Sschwarze 140920fa2881Sschwarze n = mdoc->last; 141020fa2881Sschwarze 141120fa2881Sschwarze /* 141220fa2881Sschwarze * Calculate the real width of a list from the -width string, 141320fa2881Sschwarze * which may contain a macro (with a known default width), a 141420fa2881Sschwarze * literal string, or a scaling width. 141520fa2881Sschwarze * 141620fa2881Sschwarze * If the value to -width is a macro, then we re-write it to be 141720fa2881Sschwarze * the macro's width as set in share/tmac/mdoc/doc-common. 141820fa2881Sschwarze */ 141920fa2881Sschwarze 14208c62fbf5Sschwarze if (0 == strcmp(n->norm->Bl.width, "Ds")) 142120fa2881Sschwarze width = 6; 14228c62fbf5Sschwarze else if (MDOC_MAX == (tok = mdoc_hash_find(n->norm->Bl.width))) 142320fa2881Sschwarze return(1); 142419a69263Sschwarze else if (0 == (width = macro2len(tok))) { 142520fa2881Sschwarze mdoc_nmsg(mdoc, n, MANDOCERR_BADWIDTH); 142620fa2881Sschwarze return(1); 142720fa2881Sschwarze } 142820fa2881Sschwarze 142920fa2881Sschwarze /* The value already exists: free and reallocate it. */ 143020fa2881Sschwarze 143120fa2881Sschwarze assert(n->args); 143220fa2881Sschwarze 143320fa2881Sschwarze for (i = 0; i < (int)n->args->argc; i++) 143420fa2881Sschwarze if (MDOC_Width == n->args->argv[i].arg) 143520fa2881Sschwarze break; 143620fa2881Sschwarze 143720fa2881Sschwarze assert(i < (int)n->args->argc); 143820fa2881Sschwarze 143947813146Sschwarze (void)snprintf(buf, sizeof(buf), "%un", (unsigned int)width); 144020fa2881Sschwarze free(n->args->argv[i].value[0]); 144120fa2881Sschwarze n->args->argv[i].value[0] = mandoc_strdup(buf); 144220fa2881Sschwarze 144320fa2881Sschwarze /* Set our width! */ 14448c62fbf5Sschwarze n->norm->Bl.width = n->args->argv[i].value[0]; 144520fa2881Sschwarze return(1); 144620fa2881Sschwarze } 144720fa2881Sschwarze 144820fa2881Sschwarze static int 144920fa2881Sschwarze post_bl_block_tag(POST_ARGS) 145020fa2881Sschwarze { 145120fa2881Sschwarze struct mdoc_node *n, *nn; 145220fa2881Sschwarze size_t sz, ssz; 145320fa2881Sschwarze int i; 145447813146Sschwarze char buf[24]; 145520fa2881Sschwarze 145620fa2881Sschwarze /* 145720fa2881Sschwarze * Calculate the -width for a `Bl -tag' list if it hasn't been 145820fa2881Sschwarze * provided. Uses the first head macro. NOTE AGAIN: this is 145920fa2881Sschwarze * ONLY if the -width argument has NOT been provided. See 146020fa2881Sschwarze * post_bl_block_width() for converting the -width string. 146120fa2881Sschwarze */ 146220fa2881Sschwarze 146320fa2881Sschwarze sz = 10; 146420fa2881Sschwarze n = mdoc->last; 146520fa2881Sschwarze 146620fa2881Sschwarze for (nn = n->body->child; nn; nn = nn->next) { 146720fa2881Sschwarze if (MDOC_It != nn->tok) 146820fa2881Sschwarze continue; 146920fa2881Sschwarze 147020fa2881Sschwarze assert(MDOC_BLOCK == nn->type); 147120fa2881Sschwarze nn = nn->head->child; 147220fa2881Sschwarze 147320fa2881Sschwarze if (nn == NULL) 147420fa2881Sschwarze break; 147520fa2881Sschwarze 147620fa2881Sschwarze if (MDOC_TEXT == nn->type) { 147720fa2881Sschwarze sz = strlen(nn->string) + 1; 147820fa2881Sschwarze break; 147920fa2881Sschwarze } 148020fa2881Sschwarze 148119a69263Sschwarze if (0 != (ssz = macro2len(nn->tok))) 148220fa2881Sschwarze sz = ssz; 148320fa2881Sschwarze 148420fa2881Sschwarze break; 148520fa2881Sschwarze } 148620fa2881Sschwarze 148720fa2881Sschwarze /* Defaults to ten ens. */ 148820fa2881Sschwarze 148947813146Sschwarze (void)snprintf(buf, sizeof(buf), "%un", (unsigned int)sz); 149020fa2881Sschwarze 149120fa2881Sschwarze /* 149220fa2881Sschwarze * We have to dynamically add this to the macro's argument list. 149320fa2881Sschwarze * We're guaranteed that a MDOC_Width doesn't already exist. 149420fa2881Sschwarze */ 149520fa2881Sschwarze 149620fa2881Sschwarze assert(n->args); 149720fa2881Sschwarze i = (int)(n->args->argc)++; 149820fa2881Sschwarze 14998286bf36Sschwarze n->args->argv = mandoc_reallocarray(n->args->argv, 15008286bf36Sschwarze n->args->argc, sizeof(struct mdoc_argv)); 150120fa2881Sschwarze 150220fa2881Sschwarze n->args->argv[i].arg = MDOC_Width; 150320fa2881Sschwarze n->args->argv[i].line = n->line; 150420fa2881Sschwarze n->args->argv[i].pos = n->pos; 150520fa2881Sschwarze n->args->argv[i].sz = 1; 150620fa2881Sschwarze n->args->argv[i].value = mandoc_malloc(sizeof(char *)); 150720fa2881Sschwarze n->args->argv[i].value[0] = mandoc_strdup(buf); 150820fa2881Sschwarze 150920fa2881Sschwarze /* Set our width! */ 15108c62fbf5Sschwarze n->norm->Bl.width = n->args->argv[i].value[0]; 151120fa2881Sschwarze return(1); 151220fa2881Sschwarze } 151320fa2881Sschwarze 1514f73abda9Skristaps static int 1515395185ccSschwarze post_bl_head(POST_ARGS) 1516395185ccSschwarze { 151720fa2881Sschwarze struct mdoc_node *np, *nn, *nnp; 151820fa2881Sschwarze int i, j; 1519395185ccSschwarze 15208c62fbf5Sschwarze if (LIST_column != mdoc->last->norm->Bl.type) 152120fa2881Sschwarze /* FIXME: this should be ERROR class... */ 152220fa2881Sschwarze return(hwarn_eq0(mdoc)); 1523395185ccSschwarze 152420fa2881Sschwarze /* 152520fa2881Sschwarze * Convert old-style lists, where the column width specifiers 152620fa2881Sschwarze * trail as macro parameters, to the new-style ("normal-form") 152720fa2881Sschwarze * lists where they're argument values following -column. 152820fa2881Sschwarze */ 152920fa2881Sschwarze 153020fa2881Sschwarze /* First, disallow both types and allow normal-form. */ 153120fa2881Sschwarze 153220fa2881Sschwarze /* 153320fa2881Sschwarze * TODO: technically, we can accept both and just merge the two 153420fa2881Sschwarze * lists, but I'll leave that for another day. 153520fa2881Sschwarze */ 153620fa2881Sschwarze 15378c62fbf5Sschwarze if (mdoc->last->norm->Bl.ncols && mdoc->last->nchild) { 153820fa2881Sschwarze mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_COLUMNS); 15396093755cSschwarze return(0); 154020fa2881Sschwarze } else if (NULL == mdoc->last->child) 154120fa2881Sschwarze return(1); 154220fa2881Sschwarze 154320fa2881Sschwarze np = mdoc->last->parent; 154420fa2881Sschwarze assert(np->args); 154520fa2881Sschwarze 154620fa2881Sschwarze for (j = 0; j < (int)np->args->argc; j++) 154720fa2881Sschwarze if (MDOC_Column == np->args->argv[j].arg) 154820fa2881Sschwarze break; 154920fa2881Sschwarze 155020fa2881Sschwarze assert(j < (int)np->args->argc); 155120fa2881Sschwarze assert(0 == np->args->argv[j].sz); 155220fa2881Sschwarze 155320fa2881Sschwarze /* 1554a5e11edeSschwarze * Accommodate for new-style groff column syntax. Shuffle the 155520fa2881Sschwarze * child nodes, all of which must be TEXT, as arguments for the 155620fa2881Sschwarze * column field. Then, delete the head children. 155720fa2881Sschwarze */ 155820fa2881Sschwarze 155920fa2881Sschwarze np->args->argv[j].sz = (size_t)mdoc->last->nchild; 15608286bf36Sschwarze np->args->argv[j].value = mandoc_reallocarray(NULL, 15618286bf36Sschwarze (size_t)mdoc->last->nchild, sizeof(char *)); 156220fa2881Sschwarze 15638c62fbf5Sschwarze mdoc->last->norm->Bl.ncols = np->args->argv[j].sz; 156404e980cbSschwarze mdoc->last->norm->Bl.cols = (void *)np->args->argv[j].value; 156520fa2881Sschwarze 156620fa2881Sschwarze for (i = 0, nn = mdoc->last->child; nn; i++) { 156720fa2881Sschwarze np->args->argv[j].value[i] = nn->string; 156820fa2881Sschwarze nn->string = NULL; 156920fa2881Sschwarze nnp = nn; 157020fa2881Sschwarze nn = nn->next; 157120fa2881Sschwarze mdoc_node_delete(NULL, nnp); 1572395185ccSschwarze } 157320fa2881Sschwarze 157420fa2881Sschwarze mdoc->last->nchild = 0; 157520fa2881Sschwarze mdoc->last->child = NULL; 157620fa2881Sschwarze 15776093755cSschwarze return(1); 1578b16e7ddfSschwarze } 1579b16e7ddfSschwarze 1580395185ccSschwarze static int 1581f73abda9Skristaps post_bl(POST_ARGS) 1582f73abda9Skristaps { 15832a427d60Sschwarze struct mdoc_node *nparent, *nprev; /* of the Bl block */ 15842a427d60Sschwarze struct mdoc_node *nblock, *nbody; /* of the Bl */ 15852a427d60Sschwarze struct mdoc_node *nchild, *nnext; /* of the Bl body */ 1586f73abda9Skristaps 15872a427d60Sschwarze nbody = mdoc->last; 15882a427d60Sschwarze switch (nbody->type) { 158949aff9f8Sschwarze case MDOC_BLOCK: 159020fa2881Sschwarze return(post_bl_block(mdoc)); 159149aff9f8Sschwarze case MDOC_HEAD: 15922a427d60Sschwarze return(post_bl_head(mdoc)); 159349aff9f8Sschwarze case MDOC_BODY: 1594f6127a73Sschwarze break; 15952a427d60Sschwarze default: 15962a427d60Sschwarze return(1); 1597f6127a73Sschwarze } 1598f6127a73Sschwarze 15992a427d60Sschwarze nchild = nbody->child; 16002a427d60Sschwarze while (NULL != nchild) { 16012a427d60Sschwarze if (MDOC_It == nchild->tok || MDOC_Sm == nchild->tok) { 16022a427d60Sschwarze nchild = nchild->next; 16032a427d60Sschwarze continue; 16042a427d60Sschwarze } 16052a427d60Sschwarze 1606dd25b57cSschwarze mandoc_msg(MANDOCERR_BL_MOVE, mdoc->parse, 1607dd25b57cSschwarze nchild->line, nchild->pos, 1608dd25b57cSschwarze mdoc_macronames[nchild->tok]); 16092a427d60Sschwarze 16102a427d60Sschwarze /* 16112a427d60Sschwarze * Move the node out of the Bl block. 16122a427d60Sschwarze * First, collect all required node pointers. 16132a427d60Sschwarze */ 16142a427d60Sschwarze 16152a427d60Sschwarze nblock = nbody->parent; 16162a427d60Sschwarze nprev = nblock->prev; 16172a427d60Sschwarze nparent = nblock->parent; 16182a427d60Sschwarze nnext = nchild->next; 16192a427d60Sschwarze 16202a427d60Sschwarze /* 16212a427d60Sschwarze * Unlink this child. 16222a427d60Sschwarze */ 16232a427d60Sschwarze 16242a427d60Sschwarze assert(NULL == nchild->prev); 16252a427d60Sschwarze if (0 == --nbody->nchild) { 16262a427d60Sschwarze nbody->child = NULL; 16272a427d60Sschwarze nbody->last = NULL; 16282a427d60Sschwarze assert(NULL == nnext); 16292a427d60Sschwarze } else { 16302a427d60Sschwarze nbody->child = nnext; 16312a427d60Sschwarze nnext->prev = NULL; 16322a427d60Sschwarze } 16332a427d60Sschwarze 16342a427d60Sschwarze /* 16352a427d60Sschwarze * Relink this child. 16362a427d60Sschwarze */ 16372a427d60Sschwarze 16382a427d60Sschwarze nchild->parent = nparent; 16392a427d60Sschwarze nchild->prev = nprev; 16402a427d60Sschwarze nchild->next = nblock; 16412a427d60Sschwarze 16422a427d60Sschwarze nblock->prev = nchild; 16432a427d60Sschwarze nparent->nchild++; 16442a427d60Sschwarze if (NULL == nprev) 16452a427d60Sschwarze nparent->child = nchild; 16462a427d60Sschwarze else 16472a427d60Sschwarze nprev->next = nchild; 16482a427d60Sschwarze 16492a427d60Sschwarze nchild = nnext; 1650f73abda9Skristaps } 1651f73abda9Skristaps 1652f73abda9Skristaps return(1); 1653f73abda9Skristaps } 1654f73abda9Skristaps 1655f73abda9Skristaps static int 1656f73abda9Skristaps ebool(struct mdoc *mdoc) 1657f73abda9Skristaps { 1658f73abda9Skristaps 1659bb648afaSschwarze if (NULL == mdoc->last->child) { 1660f9e7bf99Sschwarze if (MDOC_Sm == mdoc->last->tok) 1661f9e7bf99Sschwarze mdoc->flags ^= MDOC_SMOFF; 1662f73abda9Skristaps return(1); 1663bb648afaSschwarze } 1664f9e7bf99Sschwarze 1665f9e7bf99Sschwarze check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_LT, 2); 1666f73abda9Skristaps 166720fa2881Sschwarze assert(MDOC_TEXT == mdoc->last->child->type); 166820fa2881Sschwarze 1669ec2beb53Sschwarze if (0 == strcmp(mdoc->last->child->string, "on")) { 1670ec2beb53Sschwarze if (MDOC_Sm == mdoc->last->tok) 1671ec2beb53Sschwarze mdoc->flags &= ~MDOC_SMOFF; 167220fa2881Sschwarze return(1); 1673ec2beb53Sschwarze } 1674ec2beb53Sschwarze if (0 == strcmp(mdoc->last->child->string, "off")) { 1675ec2beb53Sschwarze if (MDOC_Sm == mdoc->last->tok) 1676ec2beb53Sschwarze mdoc->flags |= MDOC_SMOFF; 167720fa2881Sschwarze return(1); 1678ec2beb53Sschwarze } 167920fa2881Sschwarze 168020fa2881Sschwarze mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADBOOL); 168120fa2881Sschwarze return(1); 168220fa2881Sschwarze } 1683f73abda9Skristaps 1684f73abda9Skristaps static int 1685f73abda9Skristaps post_root(POST_ARGS) 1686f73abda9Skristaps { 168743edbcc8Sschwarze int ret; 168820fa2881Sschwarze struct mdoc_node *n; 1689f73abda9Skristaps 169043edbcc8Sschwarze ret = 1; 169120fa2881Sschwarze 169220fa2881Sschwarze /* Check that we have a finished prologue. */ 169320fa2881Sschwarze 169420fa2881Sschwarze if ( ! (MDOC_PBODY & mdoc->flags)) { 169543edbcc8Sschwarze ret = 0; 16966e03d529Sschwarze mdoc_nmsg(mdoc, mdoc->first, MANDOCERR_NODOCPROLOG); 1697f73abda9Skristaps } 1698f73abda9Skristaps 169920fa2881Sschwarze n = mdoc->first; 170020fa2881Sschwarze assert(n); 170120fa2881Sschwarze 170220fa2881Sschwarze /* Check that we begin with a proper `Sh'. */ 170320fa2881Sschwarze 170443edbcc8Sschwarze if (NULL == n->child) 170543edbcc8Sschwarze mdoc_nmsg(mdoc, n, MANDOCERR_DOC_EMPTY); 170651fcab2fSschwarze else if (MDOC_Sh != n->child->tok) 170751fcab2fSschwarze mandoc_msg(MANDOCERR_SEC_BEFORE, mdoc->parse, 170851fcab2fSschwarze n->child->line, n->child->pos, 170951fcab2fSschwarze mdoc_macronames[n->child->tok]); 171020fa2881Sschwarze 171143edbcc8Sschwarze return(ret); 171220fa2881Sschwarze } 1713f73abda9Skristaps 1714f73abda9Skristaps static int 1715f73abda9Skristaps post_st(POST_ARGS) 1716f73abda9Skristaps { 1717bb648afaSschwarze struct mdoc_node *ch; 171820fa2881Sschwarze const char *p; 1719f73abda9Skristaps 1720bb648afaSschwarze if (NULL == (ch = mdoc->last->child)) { 1721307e5a07Sschwarze mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse, 1722307e5a07Sschwarze mdoc->last->line, mdoc->last->pos, 1723307e5a07Sschwarze mdoc_macronames[mdoc->last->tok]); 1724bb648afaSschwarze mdoc_node_delete(mdoc, mdoc->last); 1725bb648afaSschwarze return(1); 1726bb648afaSschwarze } 172720fa2881Sschwarze 1728bb648afaSschwarze assert(MDOC_TEXT == ch->type); 172920fa2881Sschwarze 1730bb648afaSschwarze if (NULL == (p = mdoc_a2st(ch->string))) { 173120fa2881Sschwarze mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADSTANDARD); 173220fa2881Sschwarze mdoc_node_delete(mdoc, mdoc->last); 173320fa2881Sschwarze } else { 1734bb648afaSschwarze free(ch->string); 1735bb648afaSschwarze ch->string = mandoc_strdup(p); 1736f73abda9Skristaps } 1737f73abda9Skristaps 173820fa2881Sschwarze return(1); 173920fa2881Sschwarze } 1740f73abda9Skristaps 1741f73abda9Skristaps static int 1742011fe33bSschwarze post_rs(POST_ARGS) 1743011fe33bSschwarze { 174420fa2881Sschwarze struct mdoc_node *nn, *next, *prev; 174520fa2881Sschwarze int i, j; 1746011fe33bSschwarze 1747bb648afaSschwarze switch (mdoc->last->type) { 174849aff9f8Sschwarze case MDOC_HEAD: 1749bb648afaSschwarze check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_EQ, 0); 1750011fe33bSschwarze return(1); 175149aff9f8Sschwarze case MDOC_BODY: 1752bb648afaSschwarze if (mdoc->last->child) 1753bb648afaSschwarze break; 1754bb648afaSschwarze check_count(mdoc, MDOC_BODY, CHECK_WARN, CHECK_GT, 0); 1755bb648afaSschwarze return(1); 1756bb648afaSschwarze default: 1757bb648afaSschwarze return(1); 1758bb648afaSschwarze } 1759011fe33bSschwarze 176020fa2881Sschwarze /* 176120fa2881Sschwarze * Make sure only certain types of nodes are allowed within the 176220fa2881Sschwarze * the `Rs' body. Delete offending nodes and raise a warning. 176320fa2881Sschwarze * Do this before re-ordering for the sake of clarity. 176420fa2881Sschwarze */ 176520fa2881Sschwarze 176620fa2881Sschwarze next = NULL; 176720fa2881Sschwarze for (nn = mdoc->last->child; nn; nn = next) { 176820fa2881Sschwarze for (i = 0; i < RSORD_MAX; i++) 176920fa2881Sschwarze if (nn->tok == rsord[i]) 1770011fe33bSschwarze break; 177120fa2881Sschwarze 177220fa2881Sschwarze if (i < RSORD_MAX) { 17735d273f35Sschwarze if (MDOC__J == rsord[i] || MDOC__B == rsord[i]) 17745d273f35Sschwarze mdoc->last->norm->Rs.quote_T++; 177520fa2881Sschwarze next = nn->next; 177620fa2881Sschwarze continue; 177720fa2881Sschwarze } 177820fa2881Sschwarze 177920fa2881Sschwarze next = nn->next; 1780dd25b57cSschwarze mandoc_msg(MANDOCERR_RS_SKIP, mdoc->parse, 1781dd25b57cSschwarze nn->line, nn->pos, mdoc_macronames[nn->tok]); 178220fa2881Sschwarze mdoc_node_delete(mdoc, nn); 178320fa2881Sschwarze } 178420fa2881Sschwarze 178520fa2881Sschwarze /* 1786c6176538Sschwarze * Nothing to sort if only invalid nodes were found 1787c6176538Sschwarze * inside the `Rs' body. 1788c6176538Sschwarze */ 1789c6176538Sschwarze 1790c6176538Sschwarze if (NULL == mdoc->last->child) 1791c6176538Sschwarze return(1); 1792c6176538Sschwarze 1793c6176538Sschwarze /* 179420fa2881Sschwarze * The full `Rs' block needs special handling to order the 179520fa2881Sschwarze * sub-elements according to `rsord'. Pick through each element 179620fa2881Sschwarze * and correctly order it. This is a insertion sort. 179720fa2881Sschwarze */ 179820fa2881Sschwarze 179920fa2881Sschwarze next = NULL; 180020fa2881Sschwarze for (nn = mdoc->last->child->next; nn; nn = next) { 180120fa2881Sschwarze /* Determine order of `nn'. */ 180220fa2881Sschwarze for (i = 0; i < RSORD_MAX; i++) 180320fa2881Sschwarze if (rsord[i] == nn->tok) 180420fa2881Sschwarze break; 180520fa2881Sschwarze 180620fa2881Sschwarze /* 180720fa2881Sschwarze * Remove `nn' from the chain. This somewhat 180820fa2881Sschwarze * repeats mdoc_node_unlink(), but since we're 180920fa2881Sschwarze * just re-ordering, there's no need for the 181020fa2881Sschwarze * full unlink process. 181120fa2881Sschwarze */ 181220fa2881Sschwarze 181320fa2881Sschwarze if (NULL != (next = nn->next)) 181420fa2881Sschwarze next->prev = nn->prev; 181520fa2881Sschwarze 181620fa2881Sschwarze if (NULL != (prev = nn->prev)) 181720fa2881Sschwarze prev->next = nn->next; 181820fa2881Sschwarze 181920fa2881Sschwarze nn->prev = nn->next = NULL; 182020fa2881Sschwarze 182120fa2881Sschwarze /* 182220fa2881Sschwarze * Scan back until we reach a node that's 182320fa2881Sschwarze * ordered before `nn'. 182420fa2881Sschwarze */ 182520fa2881Sschwarze 182620fa2881Sschwarze for ( ; prev ; prev = prev->prev) { 182720fa2881Sschwarze /* Determine order of `prev'. */ 182820fa2881Sschwarze for (j = 0; j < RSORD_MAX; j++) 182920fa2881Sschwarze if (rsord[j] == prev->tok) 183020fa2881Sschwarze break; 183120fa2881Sschwarze 183220fa2881Sschwarze if (j <= i) 183320fa2881Sschwarze break; 183420fa2881Sschwarze } 183520fa2881Sschwarze 183620fa2881Sschwarze /* 183720fa2881Sschwarze * Set `nn' back into its correct place in front 183820fa2881Sschwarze * of the `prev' node. 183920fa2881Sschwarze */ 184020fa2881Sschwarze 184120fa2881Sschwarze nn->prev = prev; 184220fa2881Sschwarze 184320fa2881Sschwarze if (prev) { 184420fa2881Sschwarze if (prev->next) 184520fa2881Sschwarze prev->next->prev = nn; 184620fa2881Sschwarze nn->next = prev->next; 184720fa2881Sschwarze prev->next = nn; 184820fa2881Sschwarze } else { 184920fa2881Sschwarze mdoc->last->child->prev = nn; 185020fa2881Sschwarze nn->next = mdoc->last->child; 185120fa2881Sschwarze mdoc->last->child = nn; 185220fa2881Sschwarze } 1853011fe33bSschwarze } 1854011fe33bSschwarze 1855011fe33bSschwarze return(1); 1856011fe33bSschwarze } 1857011fe33bSschwarze 18584039b21cSschwarze /* 18594039b21cSschwarze * For some arguments of some macros, 18604039b21cSschwarze * convert all breakable hyphens into ASCII_HYPH. 18614039b21cSschwarze */ 18624039b21cSschwarze static int 18634039b21cSschwarze post_hyph(POST_ARGS) 18644039b21cSschwarze { 18654039b21cSschwarze struct mdoc_node *n, *nch; 18664039b21cSschwarze char *cp; 18674039b21cSschwarze 18684039b21cSschwarze n = mdoc->last; 18694039b21cSschwarze switch (n->type) { 187049aff9f8Sschwarze case MDOC_HEAD: 18714039b21cSschwarze if (MDOC_Sh == n->tok || MDOC_Ss == n->tok) 18724039b21cSschwarze break; 18734039b21cSschwarze return(1); 187449aff9f8Sschwarze case MDOC_BODY: 18754039b21cSschwarze if (MDOC_D1 == n->tok || MDOC_Nd == n->tok) 18764039b21cSschwarze break; 18774039b21cSschwarze return(1); 187849aff9f8Sschwarze case MDOC_ELEM: 18794039b21cSschwarze break; 18804039b21cSschwarze default: 18814039b21cSschwarze return(1); 18824039b21cSschwarze } 18834039b21cSschwarze 18844039b21cSschwarze for (nch = n->child; nch; nch = nch->next) { 18854039b21cSschwarze if (MDOC_TEXT != nch->type) 18864039b21cSschwarze continue; 18874039b21cSschwarze cp = nch->string; 1888b7e2b14eSschwarze if ('\0' == *cp) 18894039b21cSschwarze continue; 18904039b21cSschwarze while ('\0' != *(++cp)) 18914039b21cSschwarze if ('-' == *cp && 18924039b21cSschwarze isalpha((unsigned char)cp[-1]) && 18934039b21cSschwarze isalpha((unsigned char)cp[1])) 18944039b21cSschwarze *cp = ASCII_HYPH; 18954039b21cSschwarze } 18964039b21cSschwarze return(1); 18974039b21cSschwarze } 18984039b21cSschwarze 1899011fe33bSschwarze static int 1900af216717Sschwarze post_ns(POST_ARGS) 1901af216717Sschwarze { 1902af216717Sschwarze 1903af216717Sschwarze if (MDOC_LINE & mdoc->last->flags) 1904b723eac2Sschwarze mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NS_SKIP); 1905af216717Sschwarze return(1); 1906af216717Sschwarze } 1907af216717Sschwarze 1908af216717Sschwarze static int 1909f73abda9Skristaps post_sh(POST_ARGS) 1910f73abda9Skristaps { 1911f73abda9Skristaps 1912f73abda9Skristaps if (MDOC_HEAD == mdoc->last->type) 1913f73abda9Skristaps return(post_sh_head(mdoc)); 1914f73abda9Skristaps if (MDOC_BODY == mdoc->last->type) 1915f73abda9Skristaps return(post_sh_body(mdoc)); 1916f73abda9Skristaps 1917f73abda9Skristaps return(1); 1918f73abda9Skristaps } 1919f73abda9Skristaps 1920f73abda9Skristaps static int 1921f73abda9Skristaps post_sh_body(POST_ARGS) 1922f73abda9Skristaps { 1923f73abda9Skristaps struct mdoc_node *n; 1924f73abda9Skristaps 1925f8c9d6f2Sschwarze if (SEC_NAME != mdoc->lastsec) 1926f73abda9Skristaps return(1); 1927f73abda9Skristaps 1928f73abda9Skristaps /* 1929f73abda9Skristaps * Warn if the NAME section doesn't contain the `Nm' and `Nd' 1930f73abda9Skristaps * macros (can have multiple `Nm' and one `Nd'). Note that the 1931f73abda9Skristaps * children of the BODY declaration can also be "text". 1932f73abda9Skristaps */ 1933f73abda9Skristaps 193420fa2881Sschwarze if (NULL == (n = mdoc->last->child)) { 193551fcab2fSschwarze mandoc_msg(MANDOCERR_NAMESEC_BAD, mdoc->parse, 193651fcab2fSschwarze mdoc->last->line, mdoc->last->pos, "empty"); 193720fa2881Sschwarze return(1); 193820fa2881Sschwarze } 1939f73abda9Skristaps 1940f73abda9Skristaps for ( ; n && n->next; n = n->next) { 1941f73abda9Skristaps if (MDOC_ELEM == n->type && MDOC_Nm == n->tok) 1942f73abda9Skristaps continue; 1943f73abda9Skristaps if (MDOC_TEXT == n->type) 1944f73abda9Skristaps continue; 194551fcab2fSschwarze mandoc_msg(MANDOCERR_NAMESEC_BAD, mdoc->parse, 194651fcab2fSschwarze n->line, n->pos, mdoc_macronames[n->tok]); 1947f73abda9Skristaps } 1948f73abda9Skristaps 194949d529b5Sschwarze assert(n); 19504602e85cSschwarze if (MDOC_BLOCK == n->type && MDOC_Nd == n->tok) 1951f73abda9Skristaps return(1); 1952f73abda9Skristaps 195351fcab2fSschwarze mandoc_msg(MANDOCERR_NAMESEC_BAD, mdoc->parse, 195451fcab2fSschwarze n->line, n->pos, mdoc_macronames[n->tok]); 195520fa2881Sschwarze return(1); 195620fa2881Sschwarze } 1957f73abda9Skristaps 1958f73abda9Skristaps static int 1959f73abda9Skristaps post_sh_head(POST_ARGS) 1960f73abda9Skristaps { 1961a2cff342Sschwarze struct mdoc_node *n; 196251fcab2fSschwarze const char *goodsec; 196346133849Sschwarze char *secname; 1964f73abda9Skristaps enum mdoc_sec sec; 1965f73abda9Skristaps 1966f73abda9Skristaps /* 1967f73abda9Skristaps * Process a new section. Sections are either "named" or 196820fa2881Sschwarze * "custom". Custom sections are user-defined, while named ones 196920fa2881Sschwarze * follow a conventional order and may only appear in certain 197020fa2881Sschwarze * manual sections. 1971f73abda9Skristaps */ 1972f73abda9Skristaps 197383af2bccSschwarze secname = NULL; 197404e980cbSschwarze sec = SEC_CUSTOM; 197546133849Sschwarze mdoc_deroff(&secname, mdoc->last); 197646133849Sschwarze sec = NULL == secname ? SEC_CUSTOM : a2sec(secname); 1977f73abda9Skristaps 197820fa2881Sschwarze /* The NAME should be first. */ 1979f73abda9Skristaps 1980fccfce9dSschwarze if (SEC_NAME != sec && SEC_NONE == mdoc->lastnamed) 198151fcab2fSschwarze mandoc_msg(MANDOCERR_NAMESEC_FIRST, mdoc->parse, 198251fcab2fSschwarze mdoc->last->line, mdoc->last->pos, secname); 198320fa2881Sschwarze 198420fa2881Sschwarze /* The SYNOPSIS gets special attention in other areas. */ 198520fa2881Sschwarze 198622881299Sschwarze if (SEC_SYNOPSIS == sec) { 198775088a49Sschwarze roff_setreg(mdoc->roff, "nS", 1, '='); 198820fa2881Sschwarze mdoc->flags |= MDOC_SYNOPSIS; 198922881299Sschwarze } else { 199075088a49Sschwarze roff_setreg(mdoc->roff, "nS", 0, '='); 199120fa2881Sschwarze mdoc->flags &= ~MDOC_SYNOPSIS; 199222881299Sschwarze } 199320fa2881Sschwarze 199420fa2881Sschwarze /* Mark our last section. */ 199520fa2881Sschwarze 199620fa2881Sschwarze mdoc->lastsec = sec; 19971eccdf28Sschwarze 19981eccdf28Sschwarze /* 19991eccdf28Sschwarze * Set the section attribute for the current HEAD, for its 20001eccdf28Sschwarze * parent BLOCK, and for the HEAD children; the latter can 20011eccdf28Sschwarze * only be TEXT nodes, so no recursion is needed. 20021eccdf28Sschwarze * For other blocks and elements, including .Sh BODY, this is 20031eccdf28Sschwarze * done when allocating the node data structures, but for .Sh 20041eccdf28Sschwarze * BLOCK and HEAD, the section is still unknown at that time. 20051eccdf28Sschwarze */ 20061eccdf28Sschwarze 2007a2cff342Sschwarze mdoc->last->parent->sec = sec; 2008a2cff342Sschwarze mdoc->last->sec = sec; 2009a2cff342Sschwarze for (n = mdoc->last->child; n; n = n->next) 2010a2cff342Sschwarze n->sec = sec; 201120fa2881Sschwarze 201220fa2881Sschwarze /* We don't care about custom sections after this. */ 2013fccfce9dSschwarze 201446133849Sschwarze if (SEC_CUSTOM == sec) { 201546133849Sschwarze free(secname); 2016f73abda9Skristaps return(1); 201746133849Sschwarze } 2018fccfce9dSschwarze 20196be99f77Sschwarze /* 202020fa2881Sschwarze * Check whether our non-custom section is being repeated or is 202120fa2881Sschwarze * out of order. 20226be99f77Sschwarze */ 2023f73abda9Skristaps 202420fa2881Sschwarze if (sec == mdoc->lastnamed) 202551fcab2fSschwarze mandoc_msg(MANDOCERR_SEC_REP, mdoc->parse, 202651fcab2fSschwarze mdoc->last->line, mdoc->last->pos, secname); 202720fa2881Sschwarze 202820fa2881Sschwarze if (sec < mdoc->lastnamed) 202951fcab2fSschwarze mandoc_msg(MANDOCERR_SEC_ORDER, mdoc->parse, 203051fcab2fSschwarze mdoc->last->line, mdoc->last->pos, secname); 203120fa2881Sschwarze 203220fa2881Sschwarze /* Mark the last named section. */ 203320fa2881Sschwarze 203420fa2881Sschwarze mdoc->lastnamed = sec; 203520fa2881Sschwarze 203620fa2881Sschwarze /* Check particular section/manual conventions. */ 203720fa2881Sschwarze 203892c0ca7fSschwarze assert(mdoc->meta.msec); 203920fa2881Sschwarze 204051fcab2fSschwarze goodsec = NULL; 204120fa2881Sschwarze switch (sec) { 204249aff9f8Sschwarze case SEC_ERRORS: 2043be89e780Sschwarze if (*mdoc->meta.msec == '4') 2044be89e780Sschwarze break; 204551fcab2fSschwarze goodsec = "2, 3, 4, 9"; 2046be89e780Sschwarze /* FALLTHROUGH */ 204749aff9f8Sschwarze case SEC_RETURN_VALUES: 204820fa2881Sschwarze /* FALLTHROUGH */ 204949aff9f8Sschwarze case SEC_LIBRARY: 205092c0ca7fSschwarze if (*mdoc->meta.msec == '2') 2051f73abda9Skristaps break; 205292c0ca7fSschwarze if (*mdoc->meta.msec == '3') 205392c0ca7fSschwarze break; 205451fcab2fSschwarze if (NULL == goodsec) 205551fcab2fSschwarze goodsec = "2, 3, 9"; 205603ab2f23Sdlg /* FALLTHROUGH */ 205749aff9f8Sschwarze case SEC_CONTEXT: 205892c0ca7fSschwarze if (*mdoc->meta.msec == '9') 205992c0ca7fSschwarze break; 206051fcab2fSschwarze if (NULL == goodsec) 206151fcab2fSschwarze goodsec = "9"; 206251fcab2fSschwarze mandoc_vmsg(MANDOCERR_SEC_MSEC, mdoc->parse, 206351fcab2fSschwarze mdoc->last->line, mdoc->last->pos, 206451fcab2fSschwarze "%s for %s only", secname, goodsec); 206520fa2881Sschwarze break; 2066f73abda9Skristaps default: 2067f73abda9Skristaps break; 2068f73abda9Skristaps } 2069f73abda9Skristaps 207046133849Sschwarze free(secname); 2071f73abda9Skristaps return(1); 2072f73abda9Skristaps } 2073d39b9a9cSschwarze 207420fa2881Sschwarze static int 2075f6127a73Sschwarze post_ignpar(POST_ARGS) 2076f6127a73Sschwarze { 2077f6127a73Sschwarze struct mdoc_node *np; 2078f6127a73Sschwarze 2079f6127a73Sschwarze if (MDOC_BODY != mdoc->last->type) 2080f6127a73Sschwarze return(1); 2081f6127a73Sschwarze 2082f6127a73Sschwarze if (NULL != (np = mdoc->last->child)) 2083f6127a73Sschwarze if (MDOC_Pp == np->tok || MDOC_Lp == np->tok) { 208420369664Sschwarze mandoc_vmsg(MANDOCERR_PAR_SKIP, 208520369664Sschwarze mdoc->parse, np->line, np->pos, 208620369664Sschwarze "%s after %s", mdoc_macronames[np->tok], 208720369664Sschwarze mdoc_macronames[mdoc->last->tok]); 2088f6127a73Sschwarze mdoc_node_delete(mdoc, np); 2089f6127a73Sschwarze } 2090f6127a73Sschwarze 2091f6127a73Sschwarze if (NULL != (np = mdoc->last->last)) 2092f6127a73Sschwarze if (MDOC_Pp == np->tok || MDOC_Lp == np->tok) { 209320369664Sschwarze mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse, 209420369664Sschwarze np->line, np->pos, "%s at the end of %s", 209520369664Sschwarze mdoc_macronames[np->tok], 209620369664Sschwarze mdoc_macronames[mdoc->last->tok]); 2097f6127a73Sschwarze mdoc_node_delete(mdoc, np); 2098f6127a73Sschwarze } 2099f6127a73Sschwarze 2100f6127a73Sschwarze return(1); 2101f6127a73Sschwarze } 2102f6127a73Sschwarze 2103f6127a73Sschwarze static int 210420fa2881Sschwarze pre_par(PRE_ARGS) 2105d39b9a9cSschwarze { 2106d39b9a9cSschwarze 2107d39b9a9cSschwarze if (NULL == mdoc->last) 2108d39b9a9cSschwarze return(1); 2109f6127a73Sschwarze if (MDOC_ELEM != n->type && MDOC_BLOCK != n->type) 2110f6127a73Sschwarze return(1); 2111d39b9a9cSschwarze 211220fa2881Sschwarze /* 211320fa2881Sschwarze * Don't allow prior `Lp' or `Pp' prior to a paragraph-type 211420fa2881Sschwarze * block: `Lp', `Pp', or non-compact `Bd' or `Bl'. 211520fa2881Sschwarze */ 2116d39b9a9cSschwarze 2117e0dd4c9cSschwarze if (MDOC_Pp != mdoc->last->tok && 2118e0dd4c9cSschwarze MDOC_Lp != mdoc->last->tok && 2119e0dd4c9cSschwarze MDOC_br != mdoc->last->tok) 2120d39b9a9cSschwarze return(1); 21218c62fbf5Sschwarze if (MDOC_Bl == n->tok && n->norm->Bl.comp) 2122d39b9a9cSschwarze return(1); 21238c62fbf5Sschwarze if (MDOC_Bd == n->tok && n->norm->Bd.comp) 2124d39b9a9cSschwarze return(1); 21258c62fbf5Sschwarze if (MDOC_It == n->tok && n->parent->norm->Bl.comp) 2126f6127a73Sschwarze return(1); 2127d39b9a9cSschwarze 212820369664Sschwarze mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse, 212920369664Sschwarze mdoc->last->line, mdoc->last->pos, 213020369664Sschwarze "%s before %s", mdoc_macronames[mdoc->last->tok], 213120369664Sschwarze mdoc_macronames[n->tok]); 2132d39b9a9cSschwarze mdoc_node_delete(mdoc, mdoc->last); 2133d39b9a9cSschwarze return(1); 2134d39b9a9cSschwarze } 213520fa2881Sschwarze 213620fa2881Sschwarze static int 2137e0dd4c9cSschwarze post_par(POST_ARGS) 2138e0dd4c9cSschwarze { 213920369664Sschwarze struct mdoc_node *np; 2140e0dd4c9cSschwarze 2141e0dd4c9cSschwarze if (MDOC_ELEM != mdoc->last->type && 2142e0dd4c9cSschwarze MDOC_BLOCK != mdoc->last->type) 2143e0dd4c9cSschwarze return(1); 2144e0dd4c9cSschwarze 214520369664Sschwarze if (NULL == (np = mdoc->last->prev)) { 214620369664Sschwarze np = mdoc->last->parent; 214720369664Sschwarze if (MDOC_Sh != np->tok && MDOC_Ss != np->tok) 2148e0dd4c9cSschwarze return(1); 2149e0dd4c9cSschwarze } else { 215020369664Sschwarze if (MDOC_Pp != np->tok && MDOC_Lp != np->tok && 2151e0dd4c9cSschwarze (MDOC_br != mdoc->last->tok || 215220369664Sschwarze (MDOC_sp != np->tok && MDOC_br != np->tok))) 2153e0dd4c9cSschwarze return(1); 2154e0dd4c9cSschwarze } 2155e0dd4c9cSschwarze 215620369664Sschwarze mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse, 215720369664Sschwarze mdoc->last->line, mdoc->last->pos, 215820369664Sschwarze "%s after %s", mdoc_macronames[mdoc->last->tok], 215920369664Sschwarze mdoc_macronames[np->tok]); 2160e0dd4c9cSschwarze mdoc_node_delete(mdoc, mdoc->last); 2161e0dd4c9cSschwarze return(1); 2162e0dd4c9cSschwarze } 2163e0dd4c9cSschwarze 2164e0dd4c9cSschwarze static int 216520fa2881Sschwarze pre_literal(PRE_ARGS) 216620fa2881Sschwarze { 216720fa2881Sschwarze 216820fa2881Sschwarze if (MDOC_BODY != n->type) 216920fa2881Sschwarze return(1); 217020fa2881Sschwarze 217120fa2881Sschwarze /* 217220fa2881Sschwarze * The `Dl' (note "el" not "one") and `Bd -literal' and `Bd 217320fa2881Sschwarze * -unfilled' macros set MDOC_LITERAL on entrance to the body. 217420fa2881Sschwarze */ 217520fa2881Sschwarze 217620fa2881Sschwarze switch (n->tok) { 217749aff9f8Sschwarze case MDOC_Dl: 217820fa2881Sschwarze mdoc->flags |= MDOC_LITERAL; 217920fa2881Sschwarze break; 218049aff9f8Sschwarze case MDOC_Bd: 21818c62fbf5Sschwarze if (DISP_literal == n->norm->Bd.type) 218220fa2881Sschwarze mdoc->flags |= MDOC_LITERAL; 21838c62fbf5Sschwarze if (DISP_unfilled == n->norm->Bd.type) 218420fa2881Sschwarze mdoc->flags |= MDOC_LITERAL; 218520fa2881Sschwarze break; 218620fa2881Sschwarze default: 218720fa2881Sschwarze abort(); 218820fa2881Sschwarze /* NOTREACHED */ 218920fa2881Sschwarze } 219020fa2881Sschwarze 219120fa2881Sschwarze return(1); 219220fa2881Sschwarze } 219320fa2881Sschwarze 219420fa2881Sschwarze static int 219520fa2881Sschwarze post_dd(POST_ARGS) 219620fa2881Sschwarze { 219720fa2881Sschwarze struct mdoc_node *n; 219883af2bccSschwarze char *datestr; 219920fa2881Sschwarze 2200b058e777Sschwarze if (mdoc->meta.date) 2201b058e777Sschwarze free(mdoc->meta.date); 220220fa2881Sschwarze 2203b058e777Sschwarze n = mdoc->last; 2204b058e777Sschwarze if (NULL == n->child || '\0' == n->child->string[0]) { 2205231c7061Sschwarze mdoc->meta.date = mdoc->quick ? mandoc_strdup("") : 2206231c7061Sschwarze mandoc_normdate(mdoc->parse, NULL, n->line, n->pos); 220720fa2881Sschwarze return(1); 220820fa2881Sschwarze } 220920fa2881Sschwarze 221083af2bccSschwarze datestr = NULL; 221183af2bccSschwarze mdoc_deroff(&datestr, n); 221283af2bccSschwarze if (mdoc->quick) 221383af2bccSschwarze mdoc->meta.date = datestr; 221483af2bccSschwarze else { 221583af2bccSschwarze mdoc->meta.date = mandoc_normdate(mdoc->parse, 221683af2bccSschwarze datestr, n->line, n->pos); 221783af2bccSschwarze free(datestr); 221804e980cbSschwarze } 221920fa2881Sschwarze return(1); 222020fa2881Sschwarze } 222120fa2881Sschwarze 222220fa2881Sschwarze static int 222320fa2881Sschwarze post_dt(POST_ARGS) 222420fa2881Sschwarze { 222520fa2881Sschwarze struct mdoc_node *nn, *n; 222620fa2881Sschwarze const char *cp; 222720fa2881Sschwarze char *p; 222820fa2881Sschwarze 222920fa2881Sschwarze n = mdoc->last; 223020fa2881Sschwarze 223120fa2881Sschwarze if (mdoc->meta.title) 223220fa2881Sschwarze free(mdoc->meta.title); 223320fa2881Sschwarze if (mdoc->meta.vol) 223420fa2881Sschwarze free(mdoc->meta.vol); 223520fa2881Sschwarze if (mdoc->meta.arch) 223620fa2881Sschwarze free(mdoc->meta.arch); 223720fa2881Sschwarze 223820fa2881Sschwarze mdoc->meta.title = mdoc->meta.vol = mdoc->meta.arch = NULL; 223920fa2881Sschwarze 224051fcab2fSschwarze /* First check that all characters are uppercase. */ 224120fa2881Sschwarze 224220fa2881Sschwarze if (NULL != (nn = n->child)) 224320fa2881Sschwarze for (p = nn->string; *p; p++) { 224404e980cbSschwarze if (toupper((unsigned char)*p) == *p) 224520fa2881Sschwarze continue; 224651fcab2fSschwarze mandoc_msg(MANDOCERR_TITLE_CASE, 224751fcab2fSschwarze mdoc->parse, nn->line, 224851fcab2fSschwarze nn->pos + (p - nn->string), 224951fcab2fSschwarze nn->string); 225020fa2881Sschwarze break; 225120fa2881Sschwarze } 225220fa2881Sschwarze 225320fa2881Sschwarze /* Handles: `.Dt' 225449aff9f8Sschwarze * title = unknown, volume = local, msec = 0, arch = NULL 225520fa2881Sschwarze */ 225620fa2881Sschwarze 225720fa2881Sschwarze if (NULL == (nn = n->child)) { 225820fa2881Sschwarze /* XXX: make these macro values. */ 225920fa2881Sschwarze /* FIXME: warn about missing values. */ 226020fa2881Sschwarze mdoc->meta.title = mandoc_strdup("UNKNOWN"); 226120fa2881Sschwarze mdoc->meta.vol = mandoc_strdup("LOCAL"); 226220fa2881Sschwarze mdoc->meta.msec = mandoc_strdup("1"); 226320fa2881Sschwarze return(1); 226420fa2881Sschwarze } 226520fa2881Sschwarze 226620fa2881Sschwarze /* Handles: `.Dt TITLE' 226749aff9f8Sschwarze * title = TITLE, volume = local, msec = 0, arch = NULL 226820fa2881Sschwarze */ 226920fa2881Sschwarze 227049aff9f8Sschwarze mdoc->meta.title = mandoc_strdup( 227149aff9f8Sschwarze '\0' == nn->string[0] ? "UNKNOWN" : nn->string); 227220fa2881Sschwarze 227320fa2881Sschwarze if (NULL == (nn = nn->next)) { 227420fa2881Sschwarze /* FIXME: warn about missing msec. */ 227520fa2881Sschwarze /* XXX: make this a macro value. */ 227620fa2881Sschwarze mdoc->meta.vol = mandoc_strdup("LOCAL"); 227720fa2881Sschwarze mdoc->meta.msec = mandoc_strdup("1"); 227820fa2881Sschwarze return(1); 227920fa2881Sschwarze } 228020fa2881Sschwarze 228120fa2881Sschwarze /* Handles: `.Dt TITLE SEC' 228249aff9f8Sschwarze * title = TITLE, 228349aff9f8Sschwarze * volume = SEC is msec ? format(msec) : SEC, 228420fa2881Sschwarze * msec = SEC is msec ? atoi(msec) : 0, 228520fa2881Sschwarze * arch = NULL 228620fa2881Sschwarze */ 228720fa2881Sschwarze 228888ec69e3Sschwarze cp = mandoc_a2msec(nn->string); 228920fa2881Sschwarze if (cp) { 229020fa2881Sschwarze mdoc->meta.vol = mandoc_strdup(cp); 229120fa2881Sschwarze mdoc->meta.msec = mandoc_strdup(nn->string); 229220fa2881Sschwarze } else { 229351fcab2fSschwarze mandoc_msg(MANDOCERR_MSEC_BAD, mdoc->parse, 229451fcab2fSschwarze nn->line, nn->pos, nn->string); 229520fa2881Sschwarze mdoc->meta.vol = mandoc_strdup(nn->string); 229620fa2881Sschwarze mdoc->meta.msec = mandoc_strdup(nn->string); 229720fa2881Sschwarze } 229820fa2881Sschwarze 229920fa2881Sschwarze if (NULL == (nn = nn->next)) 230020fa2881Sschwarze return(1); 230120fa2881Sschwarze 230220fa2881Sschwarze /* Handles: `.Dt TITLE SEC VOL' 230349aff9f8Sschwarze * title = TITLE, 230449aff9f8Sschwarze * volume = VOL is vol ? format(VOL) : 230520fa2881Sschwarze * VOL is arch ? format(arch) : 230620fa2881Sschwarze * VOL 230720fa2881Sschwarze */ 230820fa2881Sschwarze 230920fa2881Sschwarze cp = mdoc_a2vol(nn->string); 231020fa2881Sschwarze if (cp) { 231120fa2881Sschwarze free(mdoc->meta.vol); 231220fa2881Sschwarze mdoc->meta.vol = mandoc_strdup(cp); 231320fa2881Sschwarze } else { 231420fa2881Sschwarze cp = mdoc_a2arch(nn->string); 231520fa2881Sschwarze if (NULL == cp) { 231651fcab2fSschwarze mandoc_msg(MANDOCERR_ARCH_BAD, mdoc->parse, 231751fcab2fSschwarze nn->line, nn->pos, nn->string); 231820fa2881Sschwarze free(mdoc->meta.vol); 231920fa2881Sschwarze mdoc->meta.vol = mandoc_strdup(nn->string); 232020fa2881Sschwarze } else 232120fa2881Sschwarze mdoc->meta.arch = mandoc_strdup(cp); 232220fa2881Sschwarze } 232320fa2881Sschwarze 232420fa2881Sschwarze /* Ignore any subsequent parameters... */ 232520fa2881Sschwarze /* FIXME: warn about subsequent parameters. */ 232620fa2881Sschwarze 232720fa2881Sschwarze return(1); 232820fa2881Sschwarze } 232920fa2881Sschwarze 233020fa2881Sschwarze static int 233120fa2881Sschwarze post_prol(POST_ARGS) 233220fa2881Sschwarze { 233320fa2881Sschwarze /* 233420fa2881Sschwarze * Remove prologue macros from the document after they're 233520fa2881Sschwarze * processed. The final document uses mdoc_meta for these 233620fa2881Sschwarze * values and discards the originals. 233720fa2881Sschwarze */ 233820fa2881Sschwarze 233920fa2881Sschwarze mdoc_node_delete(mdoc, mdoc->last); 234020fa2881Sschwarze if (mdoc->meta.title && mdoc->meta.date && mdoc->meta.os) 234120fa2881Sschwarze mdoc->flags |= MDOC_PBODY; 234220fa2881Sschwarze 234320fa2881Sschwarze return(1); 234420fa2881Sschwarze } 234520fa2881Sschwarze 234620fa2881Sschwarze static int 2347992063deSschwarze post_bx(POST_ARGS) 2348992063deSschwarze { 2349992063deSschwarze struct mdoc_node *n; 2350992063deSschwarze 2351992063deSschwarze /* 2352992063deSschwarze * Make `Bx's second argument always start with an uppercase 2353992063deSschwarze * letter. Groff checks if it's an "accepted" term, but we just 2354992063deSschwarze * uppercase blindly. 2355992063deSschwarze */ 2356992063deSschwarze 2357992063deSschwarze n = mdoc->last->child; 2358992063deSschwarze if (n && NULL != (n = n->next)) 235949aff9f8Sschwarze *n->string = (char)toupper((unsigned char)*n->string); 2360992063deSschwarze 2361992063deSschwarze return(1); 2362992063deSschwarze } 2363992063deSschwarze 2364992063deSschwarze static int 236520fa2881Sschwarze post_os(POST_ARGS) 236620fa2881Sschwarze { 236720fa2881Sschwarze #ifndef OSNAME 236820fa2881Sschwarze struct utsname utsname; 23694c468128Sschwarze static char *defbuf; 237020fa2881Sschwarze #endif 23714c468128Sschwarze struct mdoc_node *n; 237220fa2881Sschwarze 237320fa2881Sschwarze n = mdoc->last; 237420fa2881Sschwarze 237520fa2881Sschwarze /* 2376353fa9ecSschwarze * Set the operating system by way of the `Os' macro. 2377353fa9ecSschwarze * The order of precedence is: 2378353fa9ecSschwarze * 1. the argument of the `Os' macro, unless empty 2379353fa9ecSschwarze * 2. the -Ios=foo command line argument, if provided 2380353fa9ecSschwarze * 3. -DOSNAME="\"foo\"", if provided during compilation 2381353fa9ecSschwarze * 4. "sysname release" from uname(3) 238220fa2881Sschwarze */ 238320fa2881Sschwarze 238420fa2881Sschwarze free(mdoc->meta.os); 238583af2bccSschwarze mdoc->meta.os = NULL; 238683af2bccSschwarze mdoc_deroff(&mdoc->meta.os, n); 238783af2bccSschwarze if (mdoc->meta.os) 23884c468128Sschwarze return(1); 23894c468128Sschwarze 2390353fa9ecSschwarze if (mdoc->defos) { 2391353fa9ecSschwarze mdoc->meta.os = mandoc_strdup(mdoc->defos); 2392353fa9ecSschwarze return(1); 2393353fa9ecSschwarze } 23944c468128Sschwarze 239520fa2881Sschwarze #ifdef OSNAME 23964c468128Sschwarze mdoc->meta.os = mandoc_strdup(OSNAME); 239720fa2881Sschwarze #else /*!OSNAME */ 23984c468128Sschwarze if (NULL == defbuf) { 2399a35fc07aSschwarze if (-1 == uname(&utsname)) { 240020fa2881Sschwarze mdoc_nmsg(mdoc, n, MANDOCERR_UNAME); 24014c468128Sschwarze defbuf = mandoc_strdup("UNKNOWN"); 2402a450f7c4Sschwarze } else 2403a450f7c4Sschwarze mandoc_asprintf(&defbuf, "%s %s", 2404a450f7c4Sschwarze utsname.sysname, utsname.release); 240520fa2881Sschwarze } 24064c468128Sschwarze mdoc->meta.os = mandoc_strdup(defbuf); 240720fa2881Sschwarze #endif /*!OSNAME*/ 240820fa2881Sschwarze return(1); 240920fa2881Sschwarze } 241020fa2881Sschwarze 241120fa2881Sschwarze static int 241220fa2881Sschwarze post_std(POST_ARGS) 241320fa2881Sschwarze { 241420fa2881Sschwarze struct mdoc_node *nn, *n; 241520fa2881Sschwarze 241620fa2881Sschwarze n = mdoc->last; 241720fa2881Sschwarze 241820fa2881Sschwarze /* 241920fa2881Sschwarze * Macros accepting `-std' as an argument have the name of the 242020fa2881Sschwarze * current document (`Nm') filled in as the argument if it's not 242120fa2881Sschwarze * provided. 242220fa2881Sschwarze */ 242320fa2881Sschwarze 242420fa2881Sschwarze if (n->child) 242520fa2881Sschwarze return(1); 242620fa2881Sschwarze 242720fa2881Sschwarze if (NULL == mdoc->meta.name) 242820fa2881Sschwarze return(1); 242920fa2881Sschwarze 243020fa2881Sschwarze nn = n; 243120fa2881Sschwarze mdoc->next = MDOC_NEXT_CHILD; 243220fa2881Sschwarze 243320fa2881Sschwarze if ( ! mdoc_word_alloc(mdoc, n->line, n->pos, mdoc->meta.name)) 243420fa2881Sschwarze return(0); 243520fa2881Sschwarze 243620fa2881Sschwarze mdoc->last = nn; 243720fa2881Sschwarze return(1); 243820fa2881Sschwarze } 243920fa2881Sschwarze 244019a69263Sschwarze static enum mdoc_sec 244119a69263Sschwarze a2sec(const char *p) 244219a69263Sschwarze { 244319a69263Sschwarze int i; 244419a69263Sschwarze 244519a69263Sschwarze for (i = 0; i < (int)SEC__MAX; i++) 244619a69263Sschwarze if (secnames[i] && 0 == strcmp(p, secnames[i])) 244719a69263Sschwarze return((enum mdoc_sec)i); 244819a69263Sschwarze 244919a69263Sschwarze return(SEC_CUSTOM); 245019a69263Sschwarze } 245119a69263Sschwarze 245219a69263Sschwarze static size_t 245319a69263Sschwarze macro2len(enum mdoct macro) 245419a69263Sschwarze { 245519a69263Sschwarze 245619a69263Sschwarze switch (macro) { 245749aff9f8Sschwarze case MDOC_Ad: 245819a69263Sschwarze return(12); 245949aff9f8Sschwarze case MDOC_Ao: 246019a69263Sschwarze return(12); 246149aff9f8Sschwarze case MDOC_An: 246219a69263Sschwarze return(12); 246349aff9f8Sschwarze case MDOC_Aq: 246419a69263Sschwarze return(12); 246549aff9f8Sschwarze case MDOC_Ar: 246619a69263Sschwarze return(12); 246749aff9f8Sschwarze case MDOC_Bo: 246819a69263Sschwarze return(12); 246949aff9f8Sschwarze case MDOC_Bq: 247019a69263Sschwarze return(12); 247149aff9f8Sschwarze case MDOC_Cd: 247219a69263Sschwarze return(12); 247349aff9f8Sschwarze case MDOC_Cm: 247419a69263Sschwarze return(10); 247549aff9f8Sschwarze case MDOC_Do: 247619a69263Sschwarze return(10); 247749aff9f8Sschwarze case MDOC_Dq: 247819a69263Sschwarze return(12); 247949aff9f8Sschwarze case MDOC_Dv: 248019a69263Sschwarze return(12); 248149aff9f8Sschwarze case MDOC_Eo: 248219a69263Sschwarze return(12); 248349aff9f8Sschwarze case MDOC_Em: 248419a69263Sschwarze return(10); 248549aff9f8Sschwarze case MDOC_Er: 248619a69263Sschwarze return(17); 248749aff9f8Sschwarze case MDOC_Ev: 248819a69263Sschwarze return(15); 248949aff9f8Sschwarze case MDOC_Fa: 249019a69263Sschwarze return(12); 249149aff9f8Sschwarze case MDOC_Fl: 249219a69263Sschwarze return(10); 249349aff9f8Sschwarze case MDOC_Fo: 249419a69263Sschwarze return(16); 249549aff9f8Sschwarze case MDOC_Fn: 249619a69263Sschwarze return(16); 249749aff9f8Sschwarze case MDOC_Ic: 249819a69263Sschwarze return(10); 249949aff9f8Sschwarze case MDOC_Li: 250019a69263Sschwarze return(16); 250149aff9f8Sschwarze case MDOC_Ms: 250219a69263Sschwarze return(6); 250349aff9f8Sschwarze case MDOC_Nm: 250419a69263Sschwarze return(10); 250549aff9f8Sschwarze case MDOC_No: 250619a69263Sschwarze return(12); 250749aff9f8Sschwarze case MDOC_Oo: 250819a69263Sschwarze return(10); 250949aff9f8Sschwarze case MDOC_Op: 251019a69263Sschwarze return(14); 251149aff9f8Sschwarze case MDOC_Pa: 251219a69263Sschwarze return(32); 251349aff9f8Sschwarze case MDOC_Pf: 251419a69263Sschwarze return(12); 251549aff9f8Sschwarze case MDOC_Po: 251619a69263Sschwarze return(12); 251749aff9f8Sschwarze case MDOC_Pq: 251819a69263Sschwarze return(12); 251949aff9f8Sschwarze case MDOC_Ql: 252019a69263Sschwarze return(16); 252149aff9f8Sschwarze case MDOC_Qo: 252219a69263Sschwarze return(12); 252349aff9f8Sschwarze case MDOC_So: 252419a69263Sschwarze return(12); 252549aff9f8Sschwarze case MDOC_Sq: 252619a69263Sschwarze return(12); 252749aff9f8Sschwarze case MDOC_Sy: 252819a69263Sschwarze return(6); 252949aff9f8Sschwarze case MDOC_Sx: 253019a69263Sschwarze return(16); 253149aff9f8Sschwarze case MDOC_Tn: 253219a69263Sschwarze return(10); 253349aff9f8Sschwarze case MDOC_Va: 253419a69263Sschwarze return(12); 253549aff9f8Sschwarze case MDOC_Vt: 253619a69263Sschwarze return(12); 253749aff9f8Sschwarze case MDOC_Xr: 253819a69263Sschwarze return(10); 253919a69263Sschwarze default: 254019a69263Sschwarze break; 254119a69263Sschwarze }; 254219a69263Sschwarze return(0); 254319a69263Sschwarze } 2544