1*c1c95addSBrooks Davis /* $Id: mdoc_validate.c,v 1.391 2022/06/08 16:31:46 schwarze Exp $ */ 261d06d6bSBaptiste Daroussin /* 3*c1c95addSBrooks Davis * Copyright (c) 2010-2021 Ingo Schwarze <schwarze@openbsd.org> 461d06d6bSBaptiste Daroussin * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv> 561d06d6bSBaptiste Daroussin * Copyright (c) 2010 Joerg Sonnenberger <joerg@netbsd.org> 661d06d6bSBaptiste Daroussin * 761d06d6bSBaptiste Daroussin * Permission to use, copy, modify, and distribute this software for any 861d06d6bSBaptiste Daroussin * purpose with or without fee is hereby granted, provided that the above 961d06d6bSBaptiste Daroussin * copyright notice and this permission notice appear in all copies. 1061d06d6bSBaptiste Daroussin * 1161d06d6bSBaptiste Daroussin * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES 1261d06d6bSBaptiste Daroussin * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1361d06d6bSBaptiste Daroussin * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR 1461d06d6bSBaptiste Daroussin * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1561d06d6bSBaptiste Daroussin * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1661d06d6bSBaptiste Daroussin * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1761d06d6bSBaptiste Daroussin * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 186d38604fSBaptiste Daroussin * 196d38604fSBaptiste Daroussin * Validation module for mdoc(7) syntax trees used by mandoc(1). 2061d06d6bSBaptiste Daroussin */ 2161d06d6bSBaptiste Daroussin #include "config.h" 2261d06d6bSBaptiste Daroussin 2361d06d6bSBaptiste Daroussin #include <sys/types.h> 2461d06d6bSBaptiste Daroussin #ifndef OSNAME 2561d06d6bSBaptiste Daroussin #include <sys/utsname.h> 2661d06d6bSBaptiste Daroussin #endif 2761d06d6bSBaptiste Daroussin 2861d06d6bSBaptiste Daroussin #include <assert.h> 2961d06d6bSBaptiste Daroussin #include <ctype.h> 3061d06d6bSBaptiste Daroussin #include <limits.h> 3161d06d6bSBaptiste Daroussin #include <stdio.h> 3261d06d6bSBaptiste Daroussin #include <stdlib.h> 3361d06d6bSBaptiste Daroussin #include <string.h> 3461d06d6bSBaptiste Daroussin #include <time.h> 3561d06d6bSBaptiste Daroussin 3661d06d6bSBaptiste Daroussin #include "mandoc_aux.h" 3761d06d6bSBaptiste Daroussin #include "mandoc.h" 3861d06d6bSBaptiste Daroussin #include "mandoc_xr.h" 3961d06d6bSBaptiste Daroussin #include "roff.h" 4061d06d6bSBaptiste Daroussin #include "mdoc.h" 4161d06d6bSBaptiste Daroussin #include "libmandoc.h" 4261d06d6bSBaptiste Daroussin #include "roff_int.h" 4361d06d6bSBaptiste Daroussin #include "libmdoc.h" 446d38604fSBaptiste Daroussin #include "tag.h" 4561d06d6bSBaptiste Daroussin 4661d06d6bSBaptiste Daroussin /* FIXME: .Bl -diag can't have non-text children in HEAD. */ 4761d06d6bSBaptiste Daroussin 4861d06d6bSBaptiste Daroussin #define POST_ARGS struct roff_man *mdoc 4961d06d6bSBaptiste Daroussin 5061d06d6bSBaptiste Daroussin enum check_ineq { 5161d06d6bSBaptiste Daroussin CHECK_LT, 5261d06d6bSBaptiste Daroussin CHECK_GT, 5361d06d6bSBaptiste Daroussin CHECK_EQ 5461d06d6bSBaptiste Daroussin }; 5561d06d6bSBaptiste Daroussin 5661d06d6bSBaptiste Daroussin typedef void (*v_post)(POST_ARGS); 5761d06d6bSBaptiste Daroussin 5861d06d6bSBaptiste Daroussin static int build_list(struct roff_man *, int); 5961d06d6bSBaptiste Daroussin static void check_argv(struct roff_man *, 6061d06d6bSBaptiste Daroussin struct roff_node *, struct mdoc_argv *); 6161d06d6bSBaptiste Daroussin static void check_args(struct roff_man *, struct roff_node *); 6261d06d6bSBaptiste Daroussin static void check_text(struct roff_man *, int, int, char *); 6361d06d6bSBaptiste Daroussin static void check_text_em(struct roff_man *, int, int, char *); 6461d06d6bSBaptiste Daroussin static void check_toptext(struct roff_man *, int, int, const char *); 6561d06d6bSBaptiste Daroussin static int child_an(const struct roff_node *); 6661d06d6bSBaptiste Daroussin static size_t macro2len(enum roff_tok); 6761d06d6bSBaptiste Daroussin static void rewrite_macro2len(struct roff_man *, char **); 6861d06d6bSBaptiste Daroussin static int similar(const char *, const char *); 6961d06d6bSBaptiste Daroussin 7045a5aec3SBaptiste Daroussin static void post_abort(POST_ARGS) __attribute__((__noreturn__)); 7161d06d6bSBaptiste Daroussin static void post_an(POST_ARGS); 7261d06d6bSBaptiste Daroussin static void post_an_norm(POST_ARGS); 7361d06d6bSBaptiste Daroussin static void post_at(POST_ARGS); 7461d06d6bSBaptiste Daroussin static void post_bd(POST_ARGS); 7561d06d6bSBaptiste Daroussin static void post_bf(POST_ARGS); 7661d06d6bSBaptiste Daroussin static void post_bk(POST_ARGS); 7761d06d6bSBaptiste Daroussin static void post_bl(POST_ARGS); 7861d06d6bSBaptiste Daroussin static void post_bl_block(POST_ARGS); 7961d06d6bSBaptiste Daroussin static void post_bl_head(POST_ARGS); 8061d06d6bSBaptiste Daroussin static void post_bl_norm(POST_ARGS); 8161d06d6bSBaptiste Daroussin static void post_bx(POST_ARGS); 8261d06d6bSBaptiste Daroussin static void post_defaults(POST_ARGS); 8361d06d6bSBaptiste Daroussin static void post_display(POST_ARGS); 8461d06d6bSBaptiste Daroussin static void post_dd(POST_ARGS); 8561d06d6bSBaptiste Daroussin static void post_delim(POST_ARGS); 8661d06d6bSBaptiste Daroussin static void post_delim_nb(POST_ARGS); 8761d06d6bSBaptiste Daroussin static void post_dt(POST_ARGS); 886d38604fSBaptiste Daroussin static void post_em(POST_ARGS); 8961d06d6bSBaptiste Daroussin static void post_en(POST_ARGS); 906d38604fSBaptiste Daroussin static void post_er(POST_ARGS); 9161d06d6bSBaptiste Daroussin static void post_es(POST_ARGS); 9261d06d6bSBaptiste Daroussin static void post_eoln(POST_ARGS); 9361d06d6bSBaptiste Daroussin static void post_ex(POST_ARGS); 9461d06d6bSBaptiste Daroussin static void post_fa(POST_ARGS); 956d38604fSBaptiste Daroussin static void post_fl(POST_ARGS); 9661d06d6bSBaptiste Daroussin static void post_fn(POST_ARGS); 9761d06d6bSBaptiste Daroussin static void post_fname(POST_ARGS); 9861d06d6bSBaptiste Daroussin static void post_fo(POST_ARGS); 9961d06d6bSBaptiste Daroussin static void post_hyph(POST_ARGS); 10061d06d6bSBaptiste Daroussin static void post_it(POST_ARGS); 10161d06d6bSBaptiste Daroussin static void post_lb(POST_ARGS); 10261d06d6bSBaptiste Daroussin static void post_nd(POST_ARGS); 10361d06d6bSBaptiste Daroussin static void post_nm(POST_ARGS); 10461d06d6bSBaptiste Daroussin static void post_ns(POST_ARGS); 10561d06d6bSBaptiste Daroussin static void post_obsolete(POST_ARGS); 10661d06d6bSBaptiste Daroussin static void post_os(POST_ARGS); 10761d06d6bSBaptiste Daroussin static void post_par(POST_ARGS); 10861d06d6bSBaptiste Daroussin static void post_prevpar(POST_ARGS); 10961d06d6bSBaptiste Daroussin static void post_root(POST_ARGS); 11061d06d6bSBaptiste Daroussin static void post_rs(POST_ARGS); 11161d06d6bSBaptiste Daroussin static void post_rv(POST_ARGS); 1126d38604fSBaptiste Daroussin static void post_section(POST_ARGS); 11361d06d6bSBaptiste Daroussin static void post_sh(POST_ARGS); 11461d06d6bSBaptiste Daroussin static void post_sh_head(POST_ARGS); 11561d06d6bSBaptiste Daroussin static void post_sh_name(POST_ARGS); 11661d06d6bSBaptiste Daroussin static void post_sh_see_also(POST_ARGS); 11761d06d6bSBaptiste Daroussin static void post_sh_authors(POST_ARGS); 11861d06d6bSBaptiste Daroussin static void post_sm(POST_ARGS); 11961d06d6bSBaptiste Daroussin static void post_st(POST_ARGS); 12061d06d6bSBaptiste Daroussin static void post_std(POST_ARGS); 12161d06d6bSBaptiste Daroussin static void post_sx(POST_ARGS); 1226d38604fSBaptiste Daroussin static void post_tag(POST_ARGS); 1236d38604fSBaptiste Daroussin static void post_tg(POST_ARGS); 12461d06d6bSBaptiste Daroussin static void post_useless(POST_ARGS); 12561d06d6bSBaptiste Daroussin static void post_xr(POST_ARGS); 12661d06d6bSBaptiste Daroussin static void post_xx(POST_ARGS); 12761d06d6bSBaptiste Daroussin 1287295610fSBaptiste Daroussin static const v_post mdoc_valids[MDOC_MAX - MDOC_Dd] = { 12961d06d6bSBaptiste Daroussin post_dd, /* Dd */ 13061d06d6bSBaptiste Daroussin post_dt, /* Dt */ 13161d06d6bSBaptiste Daroussin post_os, /* Os */ 13261d06d6bSBaptiste Daroussin post_sh, /* Sh */ 1336d38604fSBaptiste Daroussin post_section, /* Ss */ 13461d06d6bSBaptiste Daroussin post_par, /* Pp */ 13561d06d6bSBaptiste Daroussin post_display, /* D1 */ 13661d06d6bSBaptiste Daroussin post_display, /* Dl */ 13761d06d6bSBaptiste Daroussin post_display, /* Bd */ 13861d06d6bSBaptiste Daroussin NULL, /* Ed */ 13961d06d6bSBaptiste Daroussin post_bl, /* Bl */ 14061d06d6bSBaptiste Daroussin NULL, /* El */ 14161d06d6bSBaptiste Daroussin post_it, /* It */ 14261d06d6bSBaptiste Daroussin post_delim_nb, /* Ad */ 14361d06d6bSBaptiste Daroussin post_an, /* An */ 14461d06d6bSBaptiste Daroussin NULL, /* Ap */ 14561d06d6bSBaptiste Daroussin post_defaults, /* Ar */ 14661d06d6bSBaptiste Daroussin NULL, /* Cd */ 1476d38604fSBaptiste Daroussin post_tag, /* Cm */ 1486d38604fSBaptiste Daroussin post_tag, /* Dv */ 1496d38604fSBaptiste Daroussin post_er, /* Er */ 1506d38604fSBaptiste Daroussin post_tag, /* Ev */ 15161d06d6bSBaptiste Daroussin post_ex, /* Ex */ 15261d06d6bSBaptiste Daroussin post_fa, /* Fa */ 15361d06d6bSBaptiste Daroussin NULL, /* Fd */ 1546d38604fSBaptiste Daroussin post_fl, /* Fl */ 15561d06d6bSBaptiste Daroussin post_fn, /* Fn */ 15661d06d6bSBaptiste Daroussin post_delim_nb, /* Ft */ 1576d38604fSBaptiste Daroussin post_tag, /* Ic */ 15861d06d6bSBaptiste Daroussin post_delim_nb, /* In */ 1596d38604fSBaptiste Daroussin post_tag, /* Li */ 16061d06d6bSBaptiste Daroussin post_nd, /* Nd */ 16161d06d6bSBaptiste Daroussin post_nm, /* Nm */ 16261d06d6bSBaptiste Daroussin post_delim_nb, /* Op */ 1637295610fSBaptiste Daroussin post_abort, /* Ot */ 16461d06d6bSBaptiste Daroussin post_defaults, /* Pa */ 16561d06d6bSBaptiste Daroussin post_rv, /* Rv */ 16661d06d6bSBaptiste Daroussin post_st, /* St */ 1676d38604fSBaptiste Daroussin post_tag, /* Va */ 16861d06d6bSBaptiste Daroussin post_delim_nb, /* Vt */ 16961d06d6bSBaptiste Daroussin post_xr, /* Xr */ 17061d06d6bSBaptiste Daroussin NULL, /* %A */ 17161d06d6bSBaptiste Daroussin post_hyph, /* %B */ /* FIXME: can be used outside Rs/Re. */ 17261d06d6bSBaptiste Daroussin NULL, /* %D */ 17361d06d6bSBaptiste Daroussin NULL, /* %I */ 17461d06d6bSBaptiste Daroussin NULL, /* %J */ 17561d06d6bSBaptiste Daroussin post_hyph, /* %N */ 17661d06d6bSBaptiste Daroussin post_hyph, /* %O */ 17761d06d6bSBaptiste Daroussin NULL, /* %P */ 17861d06d6bSBaptiste Daroussin post_hyph, /* %R */ 17961d06d6bSBaptiste Daroussin post_hyph, /* %T */ /* FIXME: can be used outside Rs/Re. */ 18061d06d6bSBaptiste Daroussin NULL, /* %V */ 18161d06d6bSBaptiste Daroussin NULL, /* Ac */ 18261d06d6bSBaptiste Daroussin NULL, /* Ao */ 18361d06d6bSBaptiste Daroussin post_delim_nb, /* Aq */ 18461d06d6bSBaptiste Daroussin post_at, /* At */ 18561d06d6bSBaptiste Daroussin NULL, /* Bc */ 18661d06d6bSBaptiste Daroussin post_bf, /* Bf */ 18761d06d6bSBaptiste Daroussin NULL, /* Bo */ 18861d06d6bSBaptiste Daroussin NULL, /* Bq */ 18961d06d6bSBaptiste Daroussin post_xx, /* Bsx */ 19061d06d6bSBaptiste Daroussin post_bx, /* Bx */ 19161d06d6bSBaptiste Daroussin post_obsolete, /* Db */ 19261d06d6bSBaptiste Daroussin NULL, /* Dc */ 19361d06d6bSBaptiste Daroussin NULL, /* Do */ 19461d06d6bSBaptiste Daroussin NULL, /* Dq */ 19561d06d6bSBaptiste Daroussin NULL, /* Ec */ 19661d06d6bSBaptiste Daroussin NULL, /* Ef */ 1976d38604fSBaptiste Daroussin post_em, /* Em */ 19861d06d6bSBaptiste Daroussin NULL, /* Eo */ 19961d06d6bSBaptiste Daroussin post_xx, /* Fx */ 2006d38604fSBaptiste Daroussin post_tag, /* Ms */ 2016d38604fSBaptiste Daroussin post_tag, /* No */ 20261d06d6bSBaptiste Daroussin post_ns, /* Ns */ 20361d06d6bSBaptiste Daroussin post_xx, /* Nx */ 20461d06d6bSBaptiste Daroussin post_xx, /* Ox */ 20561d06d6bSBaptiste Daroussin NULL, /* Pc */ 20661d06d6bSBaptiste Daroussin NULL, /* Pf */ 20761d06d6bSBaptiste Daroussin NULL, /* Po */ 20861d06d6bSBaptiste Daroussin post_delim_nb, /* Pq */ 20961d06d6bSBaptiste Daroussin NULL, /* Qc */ 21061d06d6bSBaptiste Daroussin post_delim_nb, /* Ql */ 21161d06d6bSBaptiste Daroussin NULL, /* Qo */ 21261d06d6bSBaptiste Daroussin post_delim_nb, /* Qq */ 21361d06d6bSBaptiste Daroussin NULL, /* Re */ 21461d06d6bSBaptiste Daroussin post_rs, /* Rs */ 21561d06d6bSBaptiste Daroussin NULL, /* Sc */ 21661d06d6bSBaptiste Daroussin NULL, /* So */ 21761d06d6bSBaptiste Daroussin post_delim_nb, /* Sq */ 21861d06d6bSBaptiste Daroussin post_sm, /* Sm */ 21961d06d6bSBaptiste Daroussin post_sx, /* Sx */ 2206d38604fSBaptiste Daroussin post_em, /* Sy */ 22161d06d6bSBaptiste Daroussin post_useless, /* Tn */ 22261d06d6bSBaptiste Daroussin post_xx, /* Ux */ 22361d06d6bSBaptiste Daroussin NULL, /* Xc */ 22461d06d6bSBaptiste Daroussin NULL, /* Xo */ 22561d06d6bSBaptiste Daroussin post_fo, /* Fo */ 22661d06d6bSBaptiste Daroussin NULL, /* Fc */ 22761d06d6bSBaptiste Daroussin NULL, /* Oo */ 22861d06d6bSBaptiste Daroussin NULL, /* Oc */ 22961d06d6bSBaptiste Daroussin post_bk, /* Bk */ 23061d06d6bSBaptiste Daroussin NULL, /* Ek */ 23161d06d6bSBaptiste Daroussin post_eoln, /* Bt */ 23261d06d6bSBaptiste Daroussin post_obsolete, /* Hf */ 23361d06d6bSBaptiste Daroussin post_obsolete, /* Fr */ 23461d06d6bSBaptiste Daroussin post_eoln, /* Ud */ 23561d06d6bSBaptiste Daroussin post_lb, /* Lb */ 2367295610fSBaptiste Daroussin post_abort, /* Lp */ 23761d06d6bSBaptiste Daroussin post_delim_nb, /* Lk */ 23861d06d6bSBaptiste Daroussin post_defaults, /* Mt */ 23961d06d6bSBaptiste Daroussin post_delim_nb, /* Brq */ 24061d06d6bSBaptiste Daroussin NULL, /* Bro */ 24161d06d6bSBaptiste Daroussin NULL, /* Brc */ 24261d06d6bSBaptiste Daroussin NULL, /* %C */ 24361d06d6bSBaptiste Daroussin post_es, /* Es */ 24461d06d6bSBaptiste Daroussin post_en, /* En */ 24561d06d6bSBaptiste Daroussin post_xx, /* Dx */ 24661d06d6bSBaptiste Daroussin NULL, /* %Q */ 24761d06d6bSBaptiste Daroussin NULL, /* %U */ 24861d06d6bSBaptiste Daroussin NULL, /* Ta */ 2496d38604fSBaptiste Daroussin post_tg, /* Tg */ 25061d06d6bSBaptiste Daroussin }; 25161d06d6bSBaptiste Daroussin 25261d06d6bSBaptiste Daroussin #define RSORD_MAX 14 /* Number of `Rs' blocks. */ 25361d06d6bSBaptiste Daroussin 25461d06d6bSBaptiste Daroussin static const enum roff_tok rsord[RSORD_MAX] = { 25561d06d6bSBaptiste Daroussin MDOC__A, 25661d06d6bSBaptiste Daroussin MDOC__T, 25761d06d6bSBaptiste Daroussin MDOC__B, 25861d06d6bSBaptiste Daroussin MDOC__I, 25961d06d6bSBaptiste Daroussin MDOC__J, 26061d06d6bSBaptiste Daroussin MDOC__R, 26161d06d6bSBaptiste Daroussin MDOC__N, 26261d06d6bSBaptiste Daroussin MDOC__V, 26361d06d6bSBaptiste Daroussin MDOC__U, 26461d06d6bSBaptiste Daroussin MDOC__P, 26561d06d6bSBaptiste Daroussin MDOC__Q, 26661d06d6bSBaptiste Daroussin MDOC__C, 26761d06d6bSBaptiste Daroussin MDOC__D, 26861d06d6bSBaptiste Daroussin MDOC__O 26961d06d6bSBaptiste Daroussin }; 27061d06d6bSBaptiste Daroussin 27161d06d6bSBaptiste Daroussin static const char * const secnames[SEC__MAX] = { 27261d06d6bSBaptiste Daroussin NULL, 27361d06d6bSBaptiste Daroussin "NAME", 27461d06d6bSBaptiste Daroussin "LIBRARY", 27561d06d6bSBaptiste Daroussin "SYNOPSIS", 27661d06d6bSBaptiste Daroussin "DESCRIPTION", 27761d06d6bSBaptiste Daroussin "CONTEXT", 27861d06d6bSBaptiste Daroussin "IMPLEMENTATION NOTES", 27961d06d6bSBaptiste Daroussin "RETURN VALUES", 28061d06d6bSBaptiste Daroussin "ENVIRONMENT", 28161d06d6bSBaptiste Daroussin "FILES", 28261d06d6bSBaptiste Daroussin "EXIT STATUS", 28361d06d6bSBaptiste Daroussin "EXAMPLES", 28461d06d6bSBaptiste Daroussin "DIAGNOSTICS", 28561d06d6bSBaptiste Daroussin "COMPATIBILITY", 28661d06d6bSBaptiste Daroussin "ERRORS", 28761d06d6bSBaptiste Daroussin "SEE ALSO", 28861d06d6bSBaptiste Daroussin "STANDARDS", 28961d06d6bSBaptiste Daroussin "HISTORY", 29061d06d6bSBaptiste Daroussin "AUTHORS", 29161d06d6bSBaptiste Daroussin "CAVEATS", 29261d06d6bSBaptiste Daroussin "BUGS", 29361d06d6bSBaptiste Daroussin "SECURITY CONSIDERATIONS", 29461d06d6bSBaptiste Daroussin NULL 29561d06d6bSBaptiste Daroussin }; 29661d06d6bSBaptiste Daroussin 2976d38604fSBaptiste Daroussin static int fn_prio = TAG_STRONG; 2986d38604fSBaptiste Daroussin 29961d06d6bSBaptiste Daroussin 3007295610fSBaptiste Daroussin /* Validate the subtree rooted at mdoc->last. */ 30161d06d6bSBaptiste Daroussin void 3027295610fSBaptiste Daroussin mdoc_validate(struct roff_man *mdoc) 30361d06d6bSBaptiste Daroussin { 30461d06d6bSBaptiste Daroussin struct roff_node *n, *np; 30561d06d6bSBaptiste Daroussin const v_post *p; 30661d06d6bSBaptiste Daroussin 3077295610fSBaptiste Daroussin /* 3087295610fSBaptiste Daroussin * Translate obsolete macros to modern macros first 3097295610fSBaptiste Daroussin * such that later code does not need to look 3107295610fSBaptiste Daroussin * for the obsolete versions. 3117295610fSBaptiste Daroussin */ 3127295610fSBaptiste Daroussin 31361d06d6bSBaptiste Daroussin n = mdoc->last; 3147295610fSBaptiste Daroussin switch (n->tok) { 3157295610fSBaptiste Daroussin case MDOC_Lp: 3167295610fSBaptiste Daroussin n->tok = MDOC_Pp; 3177295610fSBaptiste Daroussin break; 3187295610fSBaptiste Daroussin case MDOC_Ot: 3197295610fSBaptiste Daroussin post_obsolete(mdoc); 3207295610fSBaptiste Daroussin n->tok = MDOC_Ft; 3217295610fSBaptiste Daroussin break; 3227295610fSBaptiste Daroussin default: 3237295610fSBaptiste Daroussin break; 3247295610fSBaptiste Daroussin } 3257295610fSBaptiste Daroussin 3267295610fSBaptiste Daroussin /* 3277295610fSBaptiste Daroussin * Iterate over all children, recursing into each one 3287295610fSBaptiste Daroussin * in turn, depth-first. 3297295610fSBaptiste Daroussin */ 3307295610fSBaptiste Daroussin 33161d06d6bSBaptiste Daroussin mdoc->last = mdoc->last->child; 33261d06d6bSBaptiste Daroussin while (mdoc->last != NULL) { 3337295610fSBaptiste Daroussin mdoc_validate(mdoc); 33461d06d6bSBaptiste Daroussin if (mdoc->last == n) 33561d06d6bSBaptiste Daroussin mdoc->last = mdoc->last->child; 33661d06d6bSBaptiste Daroussin else 33761d06d6bSBaptiste Daroussin mdoc->last = mdoc->last->next; 33861d06d6bSBaptiste Daroussin } 33961d06d6bSBaptiste Daroussin 3407295610fSBaptiste Daroussin /* Finally validate the macro itself. */ 3417295610fSBaptiste Daroussin 34261d06d6bSBaptiste Daroussin mdoc->last = n; 34361d06d6bSBaptiste Daroussin mdoc->next = ROFF_NEXT_SIBLING; 34461d06d6bSBaptiste Daroussin switch (n->type) { 34561d06d6bSBaptiste Daroussin case ROFFT_TEXT: 34661d06d6bSBaptiste Daroussin np = n->parent; 34761d06d6bSBaptiste Daroussin if (n->sec != SEC_SYNOPSIS || 34861d06d6bSBaptiste Daroussin (np->tok != MDOC_Cd && np->tok != MDOC_Fd)) 34961d06d6bSBaptiste Daroussin check_text(mdoc, n->line, n->pos, n->string); 3507295610fSBaptiste Daroussin if ((n->flags & NODE_NOFILL) == 0 && 35161d06d6bSBaptiste Daroussin (np->tok != MDOC_It || np->type != ROFFT_HEAD || 35261d06d6bSBaptiste Daroussin np->parent->parent->norm->Bl.type != LIST_diag)) 35361d06d6bSBaptiste Daroussin check_text_em(mdoc, n->line, n->pos, n->string); 35461d06d6bSBaptiste Daroussin if (np->tok == MDOC_It || (np->type == ROFFT_BODY && 35561d06d6bSBaptiste Daroussin (np->tok == MDOC_Sh || np->tok == MDOC_Ss))) 35661d06d6bSBaptiste Daroussin check_toptext(mdoc, n->line, n->pos, n->string); 35761d06d6bSBaptiste Daroussin break; 35861d06d6bSBaptiste Daroussin case ROFFT_COMMENT: 35961d06d6bSBaptiste Daroussin case ROFFT_EQN: 36061d06d6bSBaptiste Daroussin case ROFFT_TBL: 36161d06d6bSBaptiste Daroussin break; 36261d06d6bSBaptiste Daroussin case ROFFT_ROOT: 36361d06d6bSBaptiste Daroussin post_root(mdoc); 36461d06d6bSBaptiste Daroussin break; 36561d06d6bSBaptiste Daroussin default: 36661d06d6bSBaptiste Daroussin check_args(mdoc, mdoc->last); 36761d06d6bSBaptiste Daroussin 36861d06d6bSBaptiste Daroussin /* 36961d06d6bSBaptiste Daroussin * Closing delimiters are not special at the 37061d06d6bSBaptiste Daroussin * beginning of a block, opening delimiters 37161d06d6bSBaptiste Daroussin * are not special at the end. 37261d06d6bSBaptiste Daroussin */ 37361d06d6bSBaptiste Daroussin 37461d06d6bSBaptiste Daroussin if (n->child != NULL) 37561d06d6bSBaptiste Daroussin n->child->flags &= ~NODE_DELIMC; 37661d06d6bSBaptiste Daroussin if (n->last != NULL) 37761d06d6bSBaptiste Daroussin n->last->flags &= ~NODE_DELIMO; 37861d06d6bSBaptiste Daroussin 37961d06d6bSBaptiste Daroussin /* Call the macro's postprocessor. */ 38061d06d6bSBaptiste Daroussin 38161d06d6bSBaptiste Daroussin if (n->tok < ROFF_MAX) { 38261d06d6bSBaptiste Daroussin roff_validate(mdoc); 38361d06d6bSBaptiste Daroussin break; 38461d06d6bSBaptiste Daroussin } 38561d06d6bSBaptiste Daroussin 38661d06d6bSBaptiste Daroussin assert(n->tok >= MDOC_Dd && n->tok < MDOC_MAX); 3877295610fSBaptiste Daroussin p = mdoc_valids + (n->tok - MDOC_Dd); 38861d06d6bSBaptiste Daroussin if (*p) 38961d06d6bSBaptiste Daroussin (*p)(mdoc); 39061d06d6bSBaptiste Daroussin if (mdoc->last == n) 39161d06d6bSBaptiste Daroussin mdoc_state(mdoc, n); 39261d06d6bSBaptiste Daroussin break; 39361d06d6bSBaptiste Daroussin } 39461d06d6bSBaptiste Daroussin } 39561d06d6bSBaptiste Daroussin 39661d06d6bSBaptiste Daroussin static void 39761d06d6bSBaptiste Daroussin check_args(struct roff_man *mdoc, struct roff_node *n) 39861d06d6bSBaptiste Daroussin { 39961d06d6bSBaptiste Daroussin int i; 40061d06d6bSBaptiste Daroussin 40161d06d6bSBaptiste Daroussin if (NULL == n->args) 40261d06d6bSBaptiste Daroussin return; 40361d06d6bSBaptiste Daroussin 40461d06d6bSBaptiste Daroussin assert(n->args->argc); 40561d06d6bSBaptiste Daroussin for (i = 0; i < (int)n->args->argc; i++) 40661d06d6bSBaptiste Daroussin check_argv(mdoc, n, &n->args->argv[i]); 40761d06d6bSBaptiste Daroussin } 40861d06d6bSBaptiste Daroussin 40961d06d6bSBaptiste Daroussin static void 41061d06d6bSBaptiste Daroussin check_argv(struct roff_man *mdoc, struct roff_node *n, struct mdoc_argv *v) 41161d06d6bSBaptiste Daroussin { 41261d06d6bSBaptiste Daroussin int i; 41361d06d6bSBaptiste Daroussin 41461d06d6bSBaptiste Daroussin for (i = 0; i < (int)v->sz; i++) 41561d06d6bSBaptiste Daroussin check_text(mdoc, v->line, v->pos, v->value[i]); 41661d06d6bSBaptiste Daroussin } 41761d06d6bSBaptiste Daroussin 41861d06d6bSBaptiste Daroussin static void 41961d06d6bSBaptiste Daroussin check_text(struct roff_man *mdoc, int ln, int pos, char *p) 42061d06d6bSBaptiste Daroussin { 42161d06d6bSBaptiste Daroussin char *cp; 42261d06d6bSBaptiste Daroussin 4237295610fSBaptiste Daroussin if (mdoc->last->flags & NODE_NOFILL) 42461d06d6bSBaptiste Daroussin return; 42561d06d6bSBaptiste Daroussin 42661d06d6bSBaptiste Daroussin for (cp = p; NULL != (p = strchr(p, '\t')); p++) 4277295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_FI_TAB, ln, pos + (int)(p - cp), NULL); 42861d06d6bSBaptiste Daroussin } 42961d06d6bSBaptiste Daroussin 43061d06d6bSBaptiste Daroussin static void 43161d06d6bSBaptiste Daroussin check_text_em(struct roff_man *mdoc, int ln, int pos, char *p) 43261d06d6bSBaptiste Daroussin { 43361d06d6bSBaptiste Daroussin const struct roff_node *np, *nn; 43461d06d6bSBaptiste Daroussin char *cp; 43561d06d6bSBaptiste Daroussin 43661d06d6bSBaptiste Daroussin np = mdoc->last->prev; 43761d06d6bSBaptiste Daroussin nn = mdoc->last->next; 43861d06d6bSBaptiste Daroussin 43961d06d6bSBaptiste Daroussin /* Look for em-dashes wrongly encoded as "--". */ 44061d06d6bSBaptiste Daroussin 44161d06d6bSBaptiste Daroussin for (cp = p; *cp != '\0'; cp++) { 44261d06d6bSBaptiste Daroussin if (cp[0] != '-' || cp[1] != '-') 44361d06d6bSBaptiste Daroussin continue; 44461d06d6bSBaptiste Daroussin cp++; 44561d06d6bSBaptiste Daroussin 44661d06d6bSBaptiste Daroussin /* Skip input sequences of more than two '-'. */ 44761d06d6bSBaptiste Daroussin 44861d06d6bSBaptiste Daroussin if (cp[1] == '-') { 44961d06d6bSBaptiste Daroussin while (cp[1] == '-') 45061d06d6bSBaptiste Daroussin cp++; 45161d06d6bSBaptiste Daroussin continue; 45261d06d6bSBaptiste Daroussin } 45361d06d6bSBaptiste Daroussin 45461d06d6bSBaptiste Daroussin /* Skip "--" directly attached to something else. */ 45561d06d6bSBaptiste Daroussin 45661d06d6bSBaptiste Daroussin if ((cp - p > 1 && cp[-2] != ' ') || 45761d06d6bSBaptiste Daroussin (cp[1] != '\0' && cp[1] != ' ')) 45861d06d6bSBaptiste Daroussin continue; 45961d06d6bSBaptiste Daroussin 46061d06d6bSBaptiste Daroussin /* Require a letter right before or right afterwards. */ 46161d06d6bSBaptiste Daroussin 46261d06d6bSBaptiste Daroussin if ((cp - p > 2 ? 46361d06d6bSBaptiste Daroussin isalpha((unsigned char)cp[-3]) : 46461d06d6bSBaptiste Daroussin np != NULL && 46561d06d6bSBaptiste Daroussin np->type == ROFFT_TEXT && 46661d06d6bSBaptiste Daroussin *np->string != '\0' && 46761d06d6bSBaptiste Daroussin isalpha((unsigned char)np->string[ 46861d06d6bSBaptiste Daroussin strlen(np->string) - 1])) || 46961d06d6bSBaptiste Daroussin (cp[1] != '\0' && cp[2] != '\0' ? 47061d06d6bSBaptiste Daroussin isalpha((unsigned char)cp[2]) : 47161d06d6bSBaptiste Daroussin nn != NULL && 47261d06d6bSBaptiste Daroussin nn->type == ROFFT_TEXT && 47361d06d6bSBaptiste Daroussin isalpha((unsigned char)*nn->string))) { 4747295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_DASHDASH, 47561d06d6bSBaptiste Daroussin ln, pos + (int)(cp - p) - 1, NULL); 47661d06d6bSBaptiste Daroussin break; 47761d06d6bSBaptiste Daroussin } 47861d06d6bSBaptiste Daroussin } 47961d06d6bSBaptiste Daroussin } 48061d06d6bSBaptiste Daroussin 48161d06d6bSBaptiste Daroussin static void 48261d06d6bSBaptiste Daroussin check_toptext(struct roff_man *mdoc, int ln, int pos, const char *p) 48361d06d6bSBaptiste Daroussin { 48461d06d6bSBaptiste Daroussin const char *cp, *cpr; 48561d06d6bSBaptiste Daroussin 48661d06d6bSBaptiste Daroussin if (*p == '\0') 48761d06d6bSBaptiste Daroussin return; 48861d06d6bSBaptiste Daroussin 48961d06d6bSBaptiste Daroussin if ((cp = strstr(p, "OpenBSD")) != NULL) 4907295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_BX, ln, pos + (int)(cp - p), "Ox"); 49161d06d6bSBaptiste Daroussin if ((cp = strstr(p, "NetBSD")) != NULL) 4927295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_BX, ln, pos + (int)(cp - p), "Nx"); 49361d06d6bSBaptiste Daroussin if ((cp = strstr(p, "FreeBSD")) != NULL) 4947295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_BX, ln, pos + (int)(cp - p), "Fx"); 49561d06d6bSBaptiste Daroussin if ((cp = strstr(p, "DragonFly")) != NULL) 4967295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_BX, ln, pos + (int)(cp - p), "Dx"); 49761d06d6bSBaptiste Daroussin 49861d06d6bSBaptiste Daroussin cp = p; 49961d06d6bSBaptiste Daroussin while ((cp = strstr(cp + 1, "()")) != NULL) { 50061d06d6bSBaptiste Daroussin for (cpr = cp - 1; cpr >= p; cpr--) 50161d06d6bSBaptiste Daroussin if (*cpr != '_' && !isalnum((unsigned char)*cpr)) 50261d06d6bSBaptiste Daroussin break; 50361d06d6bSBaptiste Daroussin if ((cpr < p || *cpr == ' ') && cpr + 1 < cp) { 50461d06d6bSBaptiste Daroussin cpr++; 5057295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_FUNC, ln, pos + (int)(cpr - p), 50661d06d6bSBaptiste Daroussin "%.*s()", (int)(cp - cpr), cpr); 50761d06d6bSBaptiste Daroussin } 50861d06d6bSBaptiste Daroussin } 50961d06d6bSBaptiste Daroussin } 51061d06d6bSBaptiste Daroussin 51161d06d6bSBaptiste Daroussin static void 5127295610fSBaptiste Daroussin post_abort(POST_ARGS) 5137295610fSBaptiste Daroussin { 5147295610fSBaptiste Daroussin abort(); 5157295610fSBaptiste Daroussin } 5167295610fSBaptiste Daroussin 5177295610fSBaptiste Daroussin static void 51861d06d6bSBaptiste Daroussin post_delim(POST_ARGS) 51961d06d6bSBaptiste Daroussin { 52061d06d6bSBaptiste Daroussin const struct roff_node *nch; 52161d06d6bSBaptiste Daroussin const char *lc; 52261d06d6bSBaptiste Daroussin enum mdelim delim; 52361d06d6bSBaptiste Daroussin enum roff_tok tok; 52461d06d6bSBaptiste Daroussin 52561d06d6bSBaptiste Daroussin tok = mdoc->last->tok; 52661d06d6bSBaptiste Daroussin nch = mdoc->last->last; 52761d06d6bSBaptiste Daroussin if (nch == NULL || nch->type != ROFFT_TEXT) 52861d06d6bSBaptiste Daroussin return; 52961d06d6bSBaptiste Daroussin lc = strchr(nch->string, '\0') - 1; 53061d06d6bSBaptiste Daroussin if (lc < nch->string) 53161d06d6bSBaptiste Daroussin return; 53261d06d6bSBaptiste Daroussin delim = mdoc_isdelim(lc); 53361d06d6bSBaptiste Daroussin if (delim == DELIM_NONE || delim == DELIM_OPEN) 53461d06d6bSBaptiste Daroussin return; 53561d06d6bSBaptiste Daroussin if (*lc == ')' && (tok == MDOC_Nd || tok == MDOC_Sh || 53661d06d6bSBaptiste Daroussin tok == MDOC_Ss || tok == MDOC_Fo)) 53761d06d6bSBaptiste Daroussin return; 53861d06d6bSBaptiste Daroussin 5397295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_DELIM, nch->line, 5407295610fSBaptiste Daroussin nch->pos + (int)(lc - nch->string), "%s%s %s", roff_name[tok], 54161d06d6bSBaptiste Daroussin nch == mdoc->last->child ? "" : " ...", nch->string); 54261d06d6bSBaptiste Daroussin } 54361d06d6bSBaptiste Daroussin 54461d06d6bSBaptiste Daroussin static void 54561d06d6bSBaptiste Daroussin post_delim_nb(POST_ARGS) 54661d06d6bSBaptiste Daroussin { 54761d06d6bSBaptiste Daroussin const struct roff_node *nch; 54861d06d6bSBaptiste Daroussin const char *lc, *cp; 54961d06d6bSBaptiste Daroussin int nw; 55061d06d6bSBaptiste Daroussin enum mdelim delim; 55161d06d6bSBaptiste Daroussin enum roff_tok tok; 55261d06d6bSBaptiste Daroussin 55361d06d6bSBaptiste Daroussin /* 55461d06d6bSBaptiste Daroussin * Find candidates: at least two bytes, 55561d06d6bSBaptiste Daroussin * the last one a closing or middle delimiter. 55661d06d6bSBaptiste Daroussin */ 55761d06d6bSBaptiste Daroussin 55861d06d6bSBaptiste Daroussin tok = mdoc->last->tok; 55961d06d6bSBaptiste Daroussin nch = mdoc->last->last; 56061d06d6bSBaptiste Daroussin if (nch == NULL || nch->type != ROFFT_TEXT) 56161d06d6bSBaptiste Daroussin return; 56261d06d6bSBaptiste Daroussin lc = strchr(nch->string, '\0') - 1; 56361d06d6bSBaptiste Daroussin if (lc <= nch->string) 56461d06d6bSBaptiste Daroussin return; 56561d06d6bSBaptiste Daroussin delim = mdoc_isdelim(lc); 56661d06d6bSBaptiste Daroussin if (delim == DELIM_NONE || delim == DELIM_OPEN) 56761d06d6bSBaptiste Daroussin return; 56861d06d6bSBaptiste Daroussin 56961d06d6bSBaptiste Daroussin /* 57061d06d6bSBaptiste Daroussin * Reduce false positives by allowing various cases. 57161d06d6bSBaptiste Daroussin */ 57261d06d6bSBaptiste Daroussin 57361d06d6bSBaptiste Daroussin /* Escaped delimiters. */ 57461d06d6bSBaptiste Daroussin if (lc > nch->string + 1 && lc[-2] == '\\' && 57561d06d6bSBaptiste Daroussin (lc[-1] == '&' || lc[-1] == 'e')) 57661d06d6bSBaptiste Daroussin return; 57761d06d6bSBaptiste Daroussin 57861d06d6bSBaptiste Daroussin /* Specific byte sequences. */ 57961d06d6bSBaptiste Daroussin switch (*lc) { 58061d06d6bSBaptiste Daroussin case ')': 58161d06d6bSBaptiste Daroussin for (cp = lc; cp >= nch->string; cp--) 58261d06d6bSBaptiste Daroussin if (*cp == '(') 58361d06d6bSBaptiste Daroussin return; 58461d06d6bSBaptiste Daroussin break; 58561d06d6bSBaptiste Daroussin case '.': 58661d06d6bSBaptiste Daroussin if (lc > nch->string + 1 && lc[-2] == '.' && lc[-1] == '.') 58761d06d6bSBaptiste Daroussin return; 58861d06d6bSBaptiste Daroussin if (lc[-1] == '.') 58961d06d6bSBaptiste Daroussin return; 59061d06d6bSBaptiste Daroussin break; 59161d06d6bSBaptiste Daroussin case ';': 59261d06d6bSBaptiste Daroussin if (tok == MDOC_Vt) 59361d06d6bSBaptiste Daroussin return; 59461d06d6bSBaptiste Daroussin break; 59561d06d6bSBaptiste Daroussin case '?': 59661d06d6bSBaptiste Daroussin if (lc[-1] == '?') 59761d06d6bSBaptiste Daroussin return; 59861d06d6bSBaptiste Daroussin break; 59961d06d6bSBaptiste Daroussin case ']': 60061d06d6bSBaptiste Daroussin for (cp = lc; cp >= nch->string; cp--) 60161d06d6bSBaptiste Daroussin if (*cp == '[') 60261d06d6bSBaptiste Daroussin return; 60361d06d6bSBaptiste Daroussin break; 60461d06d6bSBaptiste Daroussin case '|': 60561d06d6bSBaptiste Daroussin if (lc == nch->string + 1 && lc[-1] == '|') 60661d06d6bSBaptiste Daroussin return; 60761d06d6bSBaptiste Daroussin default: 60861d06d6bSBaptiste Daroussin break; 60961d06d6bSBaptiste Daroussin } 61061d06d6bSBaptiste Daroussin 61161d06d6bSBaptiste Daroussin /* Exactly two non-alphanumeric bytes. */ 61261d06d6bSBaptiste Daroussin if (lc == nch->string + 1 && !isalnum((unsigned char)lc[-1])) 61361d06d6bSBaptiste Daroussin return; 61461d06d6bSBaptiste Daroussin 61561d06d6bSBaptiste Daroussin /* At least three alphabetic words with a sentence ending. */ 61661d06d6bSBaptiste Daroussin if (strchr("!.:?", *lc) != NULL && (tok == MDOC_Em || 61761d06d6bSBaptiste Daroussin tok == MDOC_Li || tok == MDOC_Pq || tok == MDOC_Sy)) { 61861d06d6bSBaptiste Daroussin nw = 0; 61961d06d6bSBaptiste Daroussin for (cp = lc - 1; cp >= nch->string; cp--) { 62061d06d6bSBaptiste Daroussin if (*cp == ' ') { 62161d06d6bSBaptiste Daroussin nw++; 62261d06d6bSBaptiste Daroussin if (cp > nch->string && cp[-1] == ',') 62361d06d6bSBaptiste Daroussin cp--; 62461d06d6bSBaptiste Daroussin } else if (isalpha((unsigned int)*cp)) { 62561d06d6bSBaptiste Daroussin if (nw > 1) 62661d06d6bSBaptiste Daroussin return; 62761d06d6bSBaptiste Daroussin } else 62861d06d6bSBaptiste Daroussin break; 62961d06d6bSBaptiste Daroussin } 63061d06d6bSBaptiste Daroussin } 63161d06d6bSBaptiste Daroussin 6327295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_DELIM_NB, nch->line, 6337295610fSBaptiste Daroussin nch->pos + (int)(lc - nch->string), "%s%s %s", roff_name[tok], 63461d06d6bSBaptiste Daroussin nch == mdoc->last->child ? "" : " ...", nch->string); 63561d06d6bSBaptiste Daroussin } 63661d06d6bSBaptiste Daroussin 63761d06d6bSBaptiste Daroussin static void 63861d06d6bSBaptiste Daroussin post_bl_norm(POST_ARGS) 63961d06d6bSBaptiste Daroussin { 64061d06d6bSBaptiste Daroussin struct roff_node *n; 64161d06d6bSBaptiste Daroussin struct mdoc_argv *argv, *wa; 64261d06d6bSBaptiste Daroussin int i; 64361d06d6bSBaptiste Daroussin enum mdocargt mdoclt; 64461d06d6bSBaptiste Daroussin enum mdoc_list lt; 64561d06d6bSBaptiste Daroussin 64661d06d6bSBaptiste Daroussin n = mdoc->last->parent; 64761d06d6bSBaptiste Daroussin n->norm->Bl.type = LIST__NONE; 64861d06d6bSBaptiste Daroussin 64961d06d6bSBaptiste Daroussin /* 65061d06d6bSBaptiste Daroussin * First figure out which kind of list to use: bind ourselves to 65161d06d6bSBaptiste Daroussin * the first mentioned list type and warn about any remaining 65261d06d6bSBaptiste Daroussin * ones. If we find no list type, we default to LIST_item. 65361d06d6bSBaptiste Daroussin */ 65461d06d6bSBaptiste Daroussin 65561d06d6bSBaptiste Daroussin wa = (n->args == NULL) ? NULL : n->args->argv; 65661d06d6bSBaptiste Daroussin mdoclt = MDOC_ARG_MAX; 65761d06d6bSBaptiste Daroussin for (i = 0; n->args && i < (int)n->args->argc; i++) { 65861d06d6bSBaptiste Daroussin argv = n->args->argv + i; 65961d06d6bSBaptiste Daroussin lt = LIST__NONE; 66061d06d6bSBaptiste Daroussin switch (argv->arg) { 66161d06d6bSBaptiste Daroussin /* Set list types. */ 66261d06d6bSBaptiste Daroussin case MDOC_Bullet: 66361d06d6bSBaptiste Daroussin lt = LIST_bullet; 66461d06d6bSBaptiste Daroussin break; 66561d06d6bSBaptiste Daroussin case MDOC_Dash: 66661d06d6bSBaptiste Daroussin lt = LIST_dash; 66761d06d6bSBaptiste Daroussin break; 66861d06d6bSBaptiste Daroussin case MDOC_Enum: 66961d06d6bSBaptiste Daroussin lt = LIST_enum; 67061d06d6bSBaptiste Daroussin break; 67161d06d6bSBaptiste Daroussin case MDOC_Hyphen: 67261d06d6bSBaptiste Daroussin lt = LIST_hyphen; 67361d06d6bSBaptiste Daroussin break; 67461d06d6bSBaptiste Daroussin case MDOC_Item: 67561d06d6bSBaptiste Daroussin lt = LIST_item; 67661d06d6bSBaptiste Daroussin break; 67761d06d6bSBaptiste Daroussin case MDOC_Tag: 67861d06d6bSBaptiste Daroussin lt = LIST_tag; 67961d06d6bSBaptiste Daroussin break; 68061d06d6bSBaptiste Daroussin case MDOC_Diag: 68161d06d6bSBaptiste Daroussin lt = LIST_diag; 68261d06d6bSBaptiste Daroussin break; 68361d06d6bSBaptiste Daroussin case MDOC_Hang: 68461d06d6bSBaptiste Daroussin lt = LIST_hang; 68561d06d6bSBaptiste Daroussin break; 68661d06d6bSBaptiste Daroussin case MDOC_Ohang: 68761d06d6bSBaptiste Daroussin lt = LIST_ohang; 68861d06d6bSBaptiste Daroussin break; 68961d06d6bSBaptiste Daroussin case MDOC_Inset: 69061d06d6bSBaptiste Daroussin lt = LIST_inset; 69161d06d6bSBaptiste Daroussin break; 69261d06d6bSBaptiste Daroussin case MDOC_Column: 69361d06d6bSBaptiste Daroussin lt = LIST_column; 69461d06d6bSBaptiste Daroussin break; 69561d06d6bSBaptiste Daroussin /* Set list arguments. */ 69661d06d6bSBaptiste Daroussin case MDOC_Compact: 69761d06d6bSBaptiste Daroussin if (n->norm->Bl.comp) 69861d06d6bSBaptiste Daroussin mandoc_msg(MANDOCERR_ARG_REP, 6997295610fSBaptiste Daroussin argv->line, argv->pos, "Bl -compact"); 70061d06d6bSBaptiste Daroussin n->norm->Bl.comp = 1; 70161d06d6bSBaptiste Daroussin break; 70261d06d6bSBaptiste Daroussin case MDOC_Width: 70361d06d6bSBaptiste Daroussin wa = argv; 70461d06d6bSBaptiste Daroussin if (0 == argv->sz) { 70561d06d6bSBaptiste Daroussin mandoc_msg(MANDOCERR_ARG_EMPTY, 7067295610fSBaptiste Daroussin argv->line, argv->pos, "Bl -width"); 70761d06d6bSBaptiste Daroussin n->norm->Bl.width = "0n"; 70861d06d6bSBaptiste Daroussin break; 70961d06d6bSBaptiste Daroussin } 71061d06d6bSBaptiste Daroussin if (NULL != n->norm->Bl.width) 7117295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_ARG_REP, 7127295610fSBaptiste Daroussin argv->line, argv->pos, 7137295610fSBaptiste Daroussin "Bl -width %s", argv->value[0]); 71461d06d6bSBaptiste Daroussin rewrite_macro2len(mdoc, argv->value); 71561d06d6bSBaptiste Daroussin n->norm->Bl.width = argv->value[0]; 71661d06d6bSBaptiste Daroussin break; 71761d06d6bSBaptiste Daroussin case MDOC_Offset: 71861d06d6bSBaptiste Daroussin if (0 == argv->sz) { 71961d06d6bSBaptiste Daroussin mandoc_msg(MANDOCERR_ARG_EMPTY, 7207295610fSBaptiste Daroussin argv->line, argv->pos, "Bl -offset"); 72161d06d6bSBaptiste Daroussin break; 72261d06d6bSBaptiste Daroussin } 72361d06d6bSBaptiste Daroussin if (NULL != n->norm->Bl.offs) 7247295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_ARG_REP, 7257295610fSBaptiste Daroussin argv->line, argv->pos, 7267295610fSBaptiste Daroussin "Bl -offset %s", argv->value[0]); 72761d06d6bSBaptiste Daroussin rewrite_macro2len(mdoc, argv->value); 72861d06d6bSBaptiste Daroussin n->norm->Bl.offs = argv->value[0]; 72961d06d6bSBaptiste Daroussin break; 73061d06d6bSBaptiste Daroussin default: 73161d06d6bSBaptiste Daroussin continue; 73261d06d6bSBaptiste Daroussin } 73361d06d6bSBaptiste Daroussin if (LIST__NONE == lt) 73461d06d6bSBaptiste Daroussin continue; 73561d06d6bSBaptiste Daroussin mdoclt = argv->arg; 73661d06d6bSBaptiste Daroussin 73761d06d6bSBaptiste Daroussin /* Check: multiple list types. */ 73861d06d6bSBaptiste Daroussin 73961d06d6bSBaptiste Daroussin if (LIST__NONE != n->norm->Bl.type) { 7407295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_BL_REP, n->line, n->pos, 74161d06d6bSBaptiste Daroussin "Bl -%s", mdoc_argnames[argv->arg]); 74261d06d6bSBaptiste Daroussin continue; 74361d06d6bSBaptiste Daroussin } 74461d06d6bSBaptiste Daroussin 74561d06d6bSBaptiste Daroussin /* The list type should come first. */ 74661d06d6bSBaptiste Daroussin 74761d06d6bSBaptiste Daroussin if (n->norm->Bl.width || 74861d06d6bSBaptiste Daroussin n->norm->Bl.offs || 74961d06d6bSBaptiste Daroussin n->norm->Bl.comp) 7507295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_BL_LATETYPE, 7517295610fSBaptiste Daroussin n->line, n->pos, "Bl -%s", 75261d06d6bSBaptiste Daroussin mdoc_argnames[n->args->argv[0].arg]); 75361d06d6bSBaptiste Daroussin 75461d06d6bSBaptiste Daroussin n->norm->Bl.type = lt; 75561d06d6bSBaptiste Daroussin if (LIST_column == lt) { 75661d06d6bSBaptiste Daroussin n->norm->Bl.ncols = argv->sz; 75761d06d6bSBaptiste Daroussin n->norm->Bl.cols = (void *)argv->value; 75861d06d6bSBaptiste Daroussin } 75961d06d6bSBaptiste Daroussin } 76061d06d6bSBaptiste Daroussin 76161d06d6bSBaptiste Daroussin /* Allow lists to default to LIST_item. */ 76261d06d6bSBaptiste Daroussin 76361d06d6bSBaptiste Daroussin if (LIST__NONE == n->norm->Bl.type) { 7647295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_BL_NOTYPE, n->line, n->pos, "Bl"); 76561d06d6bSBaptiste Daroussin n->norm->Bl.type = LIST_item; 76661d06d6bSBaptiste Daroussin mdoclt = MDOC_Item; 76761d06d6bSBaptiste Daroussin } 76861d06d6bSBaptiste Daroussin 76961d06d6bSBaptiste Daroussin /* 77061d06d6bSBaptiste Daroussin * Validate the width field. Some list types don't need width 77161d06d6bSBaptiste Daroussin * types and should be warned about them. Others should have it 77261d06d6bSBaptiste Daroussin * and must also be warned. Yet others have a default and need 77361d06d6bSBaptiste Daroussin * no warning. 77461d06d6bSBaptiste Daroussin */ 77561d06d6bSBaptiste Daroussin 77661d06d6bSBaptiste Daroussin switch (n->norm->Bl.type) { 77761d06d6bSBaptiste Daroussin case LIST_tag: 77861d06d6bSBaptiste Daroussin if (n->norm->Bl.width == NULL) 7797295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_BL_NOWIDTH, 78061d06d6bSBaptiste Daroussin n->line, n->pos, "Bl -tag"); 78161d06d6bSBaptiste Daroussin break; 78261d06d6bSBaptiste Daroussin case LIST_column: 78361d06d6bSBaptiste Daroussin case LIST_diag: 78461d06d6bSBaptiste Daroussin case LIST_ohang: 78561d06d6bSBaptiste Daroussin case LIST_inset: 78661d06d6bSBaptiste Daroussin case LIST_item: 78761d06d6bSBaptiste Daroussin if (n->norm->Bl.width != NULL) 7887295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_BL_SKIPW, wa->line, wa->pos, 7897295610fSBaptiste Daroussin "Bl -%s", mdoc_argnames[mdoclt]); 79061d06d6bSBaptiste Daroussin n->norm->Bl.width = NULL; 79161d06d6bSBaptiste Daroussin break; 79261d06d6bSBaptiste Daroussin case LIST_bullet: 79361d06d6bSBaptiste Daroussin case LIST_dash: 79461d06d6bSBaptiste Daroussin case LIST_hyphen: 79561d06d6bSBaptiste Daroussin if (n->norm->Bl.width == NULL) 79661d06d6bSBaptiste Daroussin n->norm->Bl.width = "2n"; 79761d06d6bSBaptiste Daroussin break; 79861d06d6bSBaptiste Daroussin case LIST_enum: 79961d06d6bSBaptiste Daroussin if (n->norm->Bl.width == NULL) 80061d06d6bSBaptiste Daroussin n->norm->Bl.width = "3n"; 80161d06d6bSBaptiste Daroussin break; 80261d06d6bSBaptiste Daroussin default: 80361d06d6bSBaptiste Daroussin break; 80461d06d6bSBaptiste Daroussin } 80561d06d6bSBaptiste Daroussin } 80661d06d6bSBaptiste Daroussin 80761d06d6bSBaptiste Daroussin static void 80861d06d6bSBaptiste Daroussin post_bd(POST_ARGS) 80961d06d6bSBaptiste Daroussin { 81061d06d6bSBaptiste Daroussin struct roff_node *n; 81161d06d6bSBaptiste Daroussin struct mdoc_argv *argv; 81261d06d6bSBaptiste Daroussin int i; 81361d06d6bSBaptiste Daroussin enum mdoc_disp dt; 81461d06d6bSBaptiste Daroussin 81561d06d6bSBaptiste Daroussin n = mdoc->last; 81661d06d6bSBaptiste Daroussin for (i = 0; n->args && i < (int)n->args->argc; i++) { 81761d06d6bSBaptiste Daroussin argv = n->args->argv + i; 81861d06d6bSBaptiste Daroussin dt = DISP__NONE; 81961d06d6bSBaptiste Daroussin 82061d06d6bSBaptiste Daroussin switch (argv->arg) { 82161d06d6bSBaptiste Daroussin case MDOC_Centred: 82261d06d6bSBaptiste Daroussin dt = DISP_centered; 82361d06d6bSBaptiste Daroussin break; 82461d06d6bSBaptiste Daroussin case MDOC_Ragged: 82561d06d6bSBaptiste Daroussin dt = DISP_ragged; 82661d06d6bSBaptiste Daroussin break; 82761d06d6bSBaptiste Daroussin case MDOC_Unfilled: 82861d06d6bSBaptiste Daroussin dt = DISP_unfilled; 82961d06d6bSBaptiste Daroussin break; 83061d06d6bSBaptiste Daroussin case MDOC_Filled: 83161d06d6bSBaptiste Daroussin dt = DISP_filled; 83261d06d6bSBaptiste Daroussin break; 83361d06d6bSBaptiste Daroussin case MDOC_Literal: 83461d06d6bSBaptiste Daroussin dt = DISP_literal; 83561d06d6bSBaptiste Daroussin break; 83661d06d6bSBaptiste Daroussin case MDOC_File: 8377295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_BD_FILE, n->line, n->pos, NULL); 83861d06d6bSBaptiste Daroussin break; 83961d06d6bSBaptiste Daroussin case MDOC_Offset: 84061d06d6bSBaptiste Daroussin if (0 == argv->sz) { 84161d06d6bSBaptiste Daroussin mandoc_msg(MANDOCERR_ARG_EMPTY, 8427295610fSBaptiste Daroussin argv->line, argv->pos, "Bd -offset"); 84361d06d6bSBaptiste Daroussin break; 84461d06d6bSBaptiste Daroussin } 84561d06d6bSBaptiste Daroussin if (NULL != n->norm->Bd.offs) 8467295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_ARG_REP, 8477295610fSBaptiste Daroussin argv->line, argv->pos, 8487295610fSBaptiste Daroussin "Bd -offset %s", argv->value[0]); 84961d06d6bSBaptiste Daroussin rewrite_macro2len(mdoc, argv->value); 85061d06d6bSBaptiste Daroussin n->norm->Bd.offs = argv->value[0]; 85161d06d6bSBaptiste Daroussin break; 85261d06d6bSBaptiste Daroussin case MDOC_Compact: 85361d06d6bSBaptiste Daroussin if (n->norm->Bd.comp) 85461d06d6bSBaptiste Daroussin mandoc_msg(MANDOCERR_ARG_REP, 8557295610fSBaptiste Daroussin argv->line, argv->pos, "Bd -compact"); 85661d06d6bSBaptiste Daroussin n->norm->Bd.comp = 1; 85761d06d6bSBaptiste Daroussin break; 85861d06d6bSBaptiste Daroussin default: 85961d06d6bSBaptiste Daroussin abort(); 86061d06d6bSBaptiste Daroussin } 86161d06d6bSBaptiste Daroussin if (DISP__NONE == dt) 86261d06d6bSBaptiste Daroussin continue; 86361d06d6bSBaptiste Daroussin 86461d06d6bSBaptiste Daroussin if (DISP__NONE == n->norm->Bd.type) 86561d06d6bSBaptiste Daroussin n->norm->Bd.type = dt; 86661d06d6bSBaptiste Daroussin else 8677295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_BD_REP, n->line, n->pos, 86861d06d6bSBaptiste Daroussin "Bd -%s", mdoc_argnames[argv->arg]); 86961d06d6bSBaptiste Daroussin } 87061d06d6bSBaptiste Daroussin 87161d06d6bSBaptiste Daroussin if (DISP__NONE == n->norm->Bd.type) { 8727295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_BD_NOTYPE, n->line, n->pos, "Bd"); 87361d06d6bSBaptiste Daroussin n->norm->Bd.type = DISP_ragged; 87461d06d6bSBaptiste Daroussin } 87561d06d6bSBaptiste Daroussin } 87661d06d6bSBaptiste Daroussin 87761d06d6bSBaptiste Daroussin /* 87861d06d6bSBaptiste Daroussin * Stand-alone line macros. 87961d06d6bSBaptiste Daroussin */ 88061d06d6bSBaptiste Daroussin 88161d06d6bSBaptiste Daroussin static void 88261d06d6bSBaptiste Daroussin post_an_norm(POST_ARGS) 88361d06d6bSBaptiste Daroussin { 88461d06d6bSBaptiste Daroussin struct roff_node *n; 88561d06d6bSBaptiste Daroussin struct mdoc_argv *argv; 88661d06d6bSBaptiste Daroussin size_t i; 88761d06d6bSBaptiste Daroussin 88861d06d6bSBaptiste Daroussin n = mdoc->last; 88961d06d6bSBaptiste Daroussin if (n->args == NULL) 89061d06d6bSBaptiste Daroussin return; 89161d06d6bSBaptiste Daroussin 89261d06d6bSBaptiste Daroussin for (i = 1; i < n->args->argc; i++) { 89361d06d6bSBaptiste Daroussin argv = n->args->argv + i; 8947295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_AN_REP, argv->line, argv->pos, 89561d06d6bSBaptiste Daroussin "An -%s", mdoc_argnames[argv->arg]); 89661d06d6bSBaptiste Daroussin } 89761d06d6bSBaptiste Daroussin 89861d06d6bSBaptiste Daroussin argv = n->args->argv; 89961d06d6bSBaptiste Daroussin if (argv->arg == MDOC_Split) 90061d06d6bSBaptiste Daroussin n->norm->An.auth = AUTH_split; 90161d06d6bSBaptiste Daroussin else if (argv->arg == MDOC_Nosplit) 90261d06d6bSBaptiste Daroussin n->norm->An.auth = AUTH_nosplit; 90361d06d6bSBaptiste Daroussin else 90461d06d6bSBaptiste Daroussin abort(); 90561d06d6bSBaptiste Daroussin } 90661d06d6bSBaptiste Daroussin 90761d06d6bSBaptiste Daroussin static void 90861d06d6bSBaptiste Daroussin post_eoln(POST_ARGS) 90961d06d6bSBaptiste Daroussin { 91061d06d6bSBaptiste Daroussin struct roff_node *n; 91161d06d6bSBaptiste Daroussin 91261d06d6bSBaptiste Daroussin post_useless(mdoc); 91361d06d6bSBaptiste Daroussin n = mdoc->last; 91461d06d6bSBaptiste Daroussin if (n->child != NULL) 9157295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_ARG_SKIP, n->line, 91661d06d6bSBaptiste Daroussin n->pos, "%s %s", roff_name[n->tok], n->child->string); 91761d06d6bSBaptiste Daroussin 91861d06d6bSBaptiste Daroussin while (n->child != NULL) 91961d06d6bSBaptiste Daroussin roff_node_delete(mdoc, n->child); 92061d06d6bSBaptiste Daroussin 92161d06d6bSBaptiste Daroussin roff_word_alloc(mdoc, n->line, n->pos, n->tok == MDOC_Bt ? 92261d06d6bSBaptiste Daroussin "is currently in beta test." : "currently under development."); 92361d06d6bSBaptiste Daroussin mdoc->last->flags |= NODE_EOS | NODE_NOSRC; 92461d06d6bSBaptiste Daroussin mdoc->last = n; 92561d06d6bSBaptiste Daroussin } 92661d06d6bSBaptiste Daroussin 92761d06d6bSBaptiste Daroussin static int 92861d06d6bSBaptiste Daroussin build_list(struct roff_man *mdoc, int tok) 92961d06d6bSBaptiste Daroussin { 93061d06d6bSBaptiste Daroussin struct roff_node *n; 93161d06d6bSBaptiste Daroussin int ic; 93261d06d6bSBaptiste Daroussin 93361d06d6bSBaptiste Daroussin n = mdoc->last->next; 93461d06d6bSBaptiste Daroussin for (ic = 1;; ic++) { 93561d06d6bSBaptiste Daroussin roff_elem_alloc(mdoc, n->line, n->pos, tok); 93661d06d6bSBaptiste Daroussin mdoc->last->flags |= NODE_NOSRC; 9377295610fSBaptiste Daroussin roff_node_relink(mdoc, n); 93861d06d6bSBaptiste Daroussin n = mdoc->last = mdoc->last->parent; 93961d06d6bSBaptiste Daroussin mdoc->next = ROFF_NEXT_SIBLING; 94061d06d6bSBaptiste Daroussin if (n->next == NULL) 94161d06d6bSBaptiste Daroussin return ic; 94261d06d6bSBaptiste Daroussin if (ic > 1 || n->next->next != NULL) { 94361d06d6bSBaptiste Daroussin roff_word_alloc(mdoc, n->line, n->pos, ","); 94461d06d6bSBaptiste Daroussin mdoc->last->flags |= NODE_DELIMC | NODE_NOSRC; 94561d06d6bSBaptiste Daroussin } 94661d06d6bSBaptiste Daroussin n = mdoc->last->next; 94761d06d6bSBaptiste Daroussin if (n->next == NULL) { 94861d06d6bSBaptiste Daroussin roff_word_alloc(mdoc, n->line, n->pos, "and"); 94961d06d6bSBaptiste Daroussin mdoc->last->flags |= NODE_NOSRC; 95061d06d6bSBaptiste Daroussin } 95161d06d6bSBaptiste Daroussin } 95261d06d6bSBaptiste Daroussin } 95361d06d6bSBaptiste Daroussin 95461d06d6bSBaptiste Daroussin static void 95561d06d6bSBaptiste Daroussin post_ex(POST_ARGS) 95661d06d6bSBaptiste Daroussin { 95761d06d6bSBaptiste Daroussin struct roff_node *n; 95861d06d6bSBaptiste Daroussin int ic; 95961d06d6bSBaptiste Daroussin 96061d06d6bSBaptiste Daroussin post_std(mdoc); 96161d06d6bSBaptiste Daroussin 96261d06d6bSBaptiste Daroussin n = mdoc->last; 96361d06d6bSBaptiste Daroussin mdoc->next = ROFF_NEXT_CHILD; 96461d06d6bSBaptiste Daroussin roff_word_alloc(mdoc, n->line, n->pos, "The"); 96561d06d6bSBaptiste Daroussin mdoc->last->flags |= NODE_NOSRC; 96661d06d6bSBaptiste Daroussin 96761d06d6bSBaptiste Daroussin if (mdoc->last->next != NULL) 96861d06d6bSBaptiste Daroussin ic = build_list(mdoc, MDOC_Nm); 96961d06d6bSBaptiste Daroussin else if (mdoc->meta.name != NULL) { 97061d06d6bSBaptiste Daroussin roff_elem_alloc(mdoc, n->line, n->pos, MDOC_Nm); 97161d06d6bSBaptiste Daroussin mdoc->last->flags |= NODE_NOSRC; 97261d06d6bSBaptiste Daroussin roff_word_alloc(mdoc, n->line, n->pos, mdoc->meta.name); 97361d06d6bSBaptiste Daroussin mdoc->last->flags |= NODE_NOSRC; 97461d06d6bSBaptiste Daroussin mdoc->last = mdoc->last->parent; 97561d06d6bSBaptiste Daroussin mdoc->next = ROFF_NEXT_SIBLING; 97661d06d6bSBaptiste Daroussin ic = 1; 97761d06d6bSBaptiste Daroussin } else { 9787295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_EX_NONAME, n->line, n->pos, "Ex"); 97961d06d6bSBaptiste Daroussin ic = 0; 98061d06d6bSBaptiste Daroussin } 98161d06d6bSBaptiste Daroussin 98261d06d6bSBaptiste Daroussin roff_word_alloc(mdoc, n->line, n->pos, 98361d06d6bSBaptiste Daroussin ic > 1 ? "utilities exit\\~0" : "utility exits\\~0"); 98461d06d6bSBaptiste Daroussin mdoc->last->flags |= NODE_NOSRC; 98561d06d6bSBaptiste Daroussin roff_word_alloc(mdoc, n->line, n->pos, 98661d06d6bSBaptiste Daroussin "on success, and\\~>0 if an error occurs."); 98761d06d6bSBaptiste Daroussin mdoc->last->flags |= NODE_EOS | NODE_NOSRC; 98861d06d6bSBaptiste Daroussin mdoc->last = n; 98961d06d6bSBaptiste Daroussin } 99061d06d6bSBaptiste Daroussin 99161d06d6bSBaptiste Daroussin static void 99261d06d6bSBaptiste Daroussin post_lb(POST_ARGS) 99361d06d6bSBaptiste Daroussin { 99461d06d6bSBaptiste Daroussin struct roff_node *n; 99561d06d6bSBaptiste Daroussin const char *p; 99661d06d6bSBaptiste Daroussin 99761d06d6bSBaptiste Daroussin post_delim_nb(mdoc); 99861d06d6bSBaptiste Daroussin 99961d06d6bSBaptiste Daroussin n = mdoc->last; 100061d06d6bSBaptiste Daroussin assert(n->child->type == ROFFT_TEXT); 100161d06d6bSBaptiste Daroussin mdoc->next = ROFF_NEXT_CHILD; 100261d06d6bSBaptiste Daroussin 100361d06d6bSBaptiste Daroussin if ((p = mdoc_a2lib(n->child->string)) != NULL) { 100461d06d6bSBaptiste Daroussin n->child->flags |= NODE_NOPRT; 100561d06d6bSBaptiste Daroussin roff_word_alloc(mdoc, n->line, n->pos, p); 100661d06d6bSBaptiste Daroussin mdoc->last->flags = NODE_NOSRC; 100761d06d6bSBaptiste Daroussin mdoc->last = n; 100861d06d6bSBaptiste Daroussin return; 100961d06d6bSBaptiste Daroussin } 101061d06d6bSBaptiste Daroussin 10117295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_LB_BAD, n->child->line, 101261d06d6bSBaptiste Daroussin n->child->pos, "Lb %s", n->child->string); 101361d06d6bSBaptiste Daroussin 101461d06d6bSBaptiste Daroussin roff_word_alloc(mdoc, n->line, n->pos, "library"); 101561d06d6bSBaptiste Daroussin mdoc->last->flags = NODE_NOSRC; 101661d06d6bSBaptiste Daroussin roff_word_alloc(mdoc, n->line, n->pos, "\\(lq"); 101761d06d6bSBaptiste Daroussin mdoc->last->flags = NODE_DELIMO | NODE_NOSRC; 101861d06d6bSBaptiste Daroussin mdoc->last = mdoc->last->next; 101961d06d6bSBaptiste Daroussin roff_word_alloc(mdoc, n->line, n->pos, "\\(rq"); 102061d06d6bSBaptiste Daroussin mdoc->last->flags = NODE_DELIMC | NODE_NOSRC; 102161d06d6bSBaptiste Daroussin mdoc->last = n; 102261d06d6bSBaptiste Daroussin } 102361d06d6bSBaptiste Daroussin 102461d06d6bSBaptiste Daroussin static void 102561d06d6bSBaptiste Daroussin post_rv(POST_ARGS) 102661d06d6bSBaptiste Daroussin { 102761d06d6bSBaptiste Daroussin struct roff_node *n; 102861d06d6bSBaptiste Daroussin int ic; 102961d06d6bSBaptiste Daroussin 103061d06d6bSBaptiste Daroussin post_std(mdoc); 103161d06d6bSBaptiste Daroussin 103261d06d6bSBaptiste Daroussin n = mdoc->last; 103361d06d6bSBaptiste Daroussin mdoc->next = ROFF_NEXT_CHILD; 103461d06d6bSBaptiste Daroussin if (n->child != NULL) { 103561d06d6bSBaptiste Daroussin roff_word_alloc(mdoc, n->line, n->pos, "The"); 103661d06d6bSBaptiste Daroussin mdoc->last->flags |= NODE_NOSRC; 103761d06d6bSBaptiste Daroussin ic = build_list(mdoc, MDOC_Fn); 103861d06d6bSBaptiste Daroussin roff_word_alloc(mdoc, n->line, n->pos, 103961d06d6bSBaptiste Daroussin ic > 1 ? "functions return" : "function returns"); 104061d06d6bSBaptiste Daroussin mdoc->last->flags |= NODE_NOSRC; 104161d06d6bSBaptiste Daroussin roff_word_alloc(mdoc, n->line, n->pos, 104261d06d6bSBaptiste Daroussin "the value\\~0 if successful;"); 104361d06d6bSBaptiste Daroussin } else 104461d06d6bSBaptiste Daroussin roff_word_alloc(mdoc, n->line, n->pos, "Upon successful " 104561d06d6bSBaptiste Daroussin "completion, the value\\~0 is returned;"); 104661d06d6bSBaptiste Daroussin mdoc->last->flags |= NODE_NOSRC; 104761d06d6bSBaptiste Daroussin 104861d06d6bSBaptiste Daroussin roff_word_alloc(mdoc, n->line, n->pos, "otherwise " 104961d06d6bSBaptiste Daroussin "the value\\~\\-1 is returned and the global variable"); 105061d06d6bSBaptiste Daroussin mdoc->last->flags |= NODE_NOSRC; 105161d06d6bSBaptiste Daroussin roff_elem_alloc(mdoc, n->line, n->pos, MDOC_Va); 105261d06d6bSBaptiste Daroussin mdoc->last->flags |= NODE_NOSRC; 105361d06d6bSBaptiste Daroussin roff_word_alloc(mdoc, n->line, n->pos, "errno"); 105461d06d6bSBaptiste Daroussin mdoc->last->flags |= NODE_NOSRC; 105561d06d6bSBaptiste Daroussin mdoc->last = mdoc->last->parent; 105661d06d6bSBaptiste Daroussin mdoc->next = ROFF_NEXT_SIBLING; 105761d06d6bSBaptiste Daroussin roff_word_alloc(mdoc, n->line, n->pos, 105861d06d6bSBaptiste Daroussin "is set to indicate the error."); 105961d06d6bSBaptiste Daroussin mdoc->last->flags |= NODE_EOS | NODE_NOSRC; 106061d06d6bSBaptiste Daroussin mdoc->last = n; 106161d06d6bSBaptiste Daroussin } 106261d06d6bSBaptiste Daroussin 106361d06d6bSBaptiste Daroussin static void 106461d06d6bSBaptiste Daroussin post_std(POST_ARGS) 106561d06d6bSBaptiste Daroussin { 106661d06d6bSBaptiste Daroussin struct roff_node *n; 106761d06d6bSBaptiste Daroussin 106861d06d6bSBaptiste Daroussin post_delim(mdoc); 106961d06d6bSBaptiste Daroussin 107061d06d6bSBaptiste Daroussin n = mdoc->last; 107161d06d6bSBaptiste Daroussin if (n->args && n->args->argc == 1) 107261d06d6bSBaptiste Daroussin if (n->args->argv[0].arg == MDOC_Std) 107361d06d6bSBaptiste Daroussin return; 107461d06d6bSBaptiste Daroussin 10757295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_ARG_STD, n->line, n->pos, 10767295610fSBaptiste Daroussin "%s", roff_name[n->tok]); 107761d06d6bSBaptiste Daroussin } 107861d06d6bSBaptiste Daroussin 107961d06d6bSBaptiste Daroussin static void 108061d06d6bSBaptiste Daroussin post_st(POST_ARGS) 108161d06d6bSBaptiste Daroussin { 108261d06d6bSBaptiste Daroussin struct roff_node *n, *nch; 108361d06d6bSBaptiste Daroussin const char *p; 108461d06d6bSBaptiste Daroussin 108561d06d6bSBaptiste Daroussin n = mdoc->last; 108661d06d6bSBaptiste Daroussin nch = n->child; 108761d06d6bSBaptiste Daroussin assert(nch->type == ROFFT_TEXT); 108861d06d6bSBaptiste Daroussin 108961d06d6bSBaptiste Daroussin if ((p = mdoc_a2st(nch->string)) == NULL) { 10907295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_ST_BAD, 109161d06d6bSBaptiste Daroussin nch->line, nch->pos, "St %s", nch->string); 109261d06d6bSBaptiste Daroussin roff_node_delete(mdoc, n); 109361d06d6bSBaptiste Daroussin return; 109461d06d6bSBaptiste Daroussin } 109561d06d6bSBaptiste Daroussin 109661d06d6bSBaptiste Daroussin nch->flags |= NODE_NOPRT; 109761d06d6bSBaptiste Daroussin mdoc->next = ROFF_NEXT_CHILD; 109861d06d6bSBaptiste Daroussin roff_word_alloc(mdoc, nch->line, nch->pos, p); 109961d06d6bSBaptiste Daroussin mdoc->last->flags |= NODE_NOSRC; 110061d06d6bSBaptiste Daroussin mdoc->last= n; 110161d06d6bSBaptiste Daroussin } 110261d06d6bSBaptiste Daroussin 110361d06d6bSBaptiste Daroussin static void 11046d38604fSBaptiste Daroussin post_tg(POST_ARGS) 11056d38604fSBaptiste Daroussin { 11066d38604fSBaptiste Daroussin struct roff_node *n; /* The .Tg node. */ 11076d38604fSBaptiste Daroussin struct roff_node *nch; /* The first child of the .Tg node. */ 11086d38604fSBaptiste Daroussin struct roff_node *nn; /* The next node after the .Tg node. */ 11096d38604fSBaptiste Daroussin struct roff_node *np; /* The parent of the next node. */ 11106d38604fSBaptiste Daroussin struct roff_node *nt; /* The TEXT node containing the tag. */ 11116d38604fSBaptiste Daroussin size_t len; /* The number of bytes in the tag. */ 11126d38604fSBaptiste Daroussin 11136d38604fSBaptiste Daroussin /* Find the next node. */ 11146d38604fSBaptiste Daroussin n = mdoc->last; 11156d38604fSBaptiste Daroussin for (nn = n; nn != NULL; nn = nn->parent) { 1116*c1c95addSBrooks Davis if (nn->type != ROFFT_HEAD && nn->type != ROFFT_BODY && 1117*c1c95addSBrooks Davis nn->type != ROFFT_TAIL && nn->next != NULL) { 11186d38604fSBaptiste Daroussin nn = nn->next; 11196d38604fSBaptiste Daroussin break; 11206d38604fSBaptiste Daroussin } 11216d38604fSBaptiste Daroussin } 11226d38604fSBaptiste Daroussin 11236d38604fSBaptiste Daroussin /* Find the tag. */ 11246d38604fSBaptiste Daroussin nt = nch = n->child; 11256d38604fSBaptiste Daroussin if (nch == NULL && nn != NULL && nn->child != NULL && 11266d38604fSBaptiste Daroussin nn->child->type == ROFFT_TEXT) 11276d38604fSBaptiste Daroussin nt = nn->child; 11286d38604fSBaptiste Daroussin 11296d38604fSBaptiste Daroussin /* Validate the tag. */ 11306d38604fSBaptiste Daroussin if (nt == NULL || *nt->string == '\0') 11316d38604fSBaptiste Daroussin mandoc_msg(MANDOCERR_MACRO_EMPTY, n->line, n->pos, "Tg"); 11326d38604fSBaptiste Daroussin if (nt == NULL) { 11336d38604fSBaptiste Daroussin roff_node_delete(mdoc, n); 11346d38604fSBaptiste Daroussin return; 11356d38604fSBaptiste Daroussin } 11366d38604fSBaptiste Daroussin len = strcspn(nt->string, " \t\\"); 11376d38604fSBaptiste Daroussin if (nt->string[len] != '\0') 11386d38604fSBaptiste Daroussin mandoc_msg(MANDOCERR_TG_SPC, nt->line, 11396d38604fSBaptiste Daroussin nt->pos + len, "Tg %s", nt->string); 11406d38604fSBaptiste Daroussin 11416d38604fSBaptiste Daroussin /* Keep only the first argument. */ 11426d38604fSBaptiste Daroussin if (nch != NULL && nch->next != NULL) { 11436d38604fSBaptiste Daroussin mandoc_msg(MANDOCERR_ARG_EXCESS, nch->next->line, 11446d38604fSBaptiste Daroussin nch->next->pos, "Tg ... %s", nch->next->string); 11456d38604fSBaptiste Daroussin while (nch->next != NULL) 11466d38604fSBaptiste Daroussin roff_node_delete(mdoc, nch->next); 11476d38604fSBaptiste Daroussin } 11486d38604fSBaptiste Daroussin 11496d38604fSBaptiste Daroussin /* Drop the macro if the first argument is invalid. */ 11506d38604fSBaptiste Daroussin if (len == 0 || nt->string[len] != '\0') { 11516d38604fSBaptiste Daroussin roff_node_delete(mdoc, n); 11526d38604fSBaptiste Daroussin return; 11536d38604fSBaptiste Daroussin } 11546d38604fSBaptiste Daroussin 11556d38604fSBaptiste Daroussin /* By default, tag the .Tg node itself. */ 11566d38604fSBaptiste Daroussin if (nn == NULL || nn->flags & NODE_ID) 11576d38604fSBaptiste Daroussin nn = n; 11586d38604fSBaptiste Daroussin 11596d38604fSBaptiste Daroussin /* Explicit tagging of specific macros. */ 11606d38604fSBaptiste Daroussin switch (nn->tok) { 11616d38604fSBaptiste Daroussin case MDOC_Sh: 11626d38604fSBaptiste Daroussin case MDOC_Ss: 11636d38604fSBaptiste Daroussin case MDOC_Fo: 11646d38604fSBaptiste Daroussin nn = nn->head->child == NULL ? n : nn->head; 11656d38604fSBaptiste Daroussin break; 11666d38604fSBaptiste Daroussin case MDOC_It: 11676d38604fSBaptiste Daroussin np = nn->parent; 11686d38604fSBaptiste Daroussin while (np->tok != MDOC_Bl) 11696d38604fSBaptiste Daroussin np = np->parent; 11706d38604fSBaptiste Daroussin switch (np->norm->Bl.type) { 11716d38604fSBaptiste Daroussin case LIST_column: 11726d38604fSBaptiste Daroussin break; 11736d38604fSBaptiste Daroussin case LIST_diag: 11746d38604fSBaptiste Daroussin case LIST_hang: 11756d38604fSBaptiste Daroussin case LIST_inset: 11766d38604fSBaptiste Daroussin case LIST_ohang: 11776d38604fSBaptiste Daroussin case LIST_tag: 11786d38604fSBaptiste Daroussin nn = nn->head; 11796d38604fSBaptiste Daroussin break; 11806d38604fSBaptiste Daroussin case LIST_bullet: 11816d38604fSBaptiste Daroussin case LIST_dash: 11826d38604fSBaptiste Daroussin case LIST_enum: 11836d38604fSBaptiste Daroussin case LIST_hyphen: 11846d38604fSBaptiste Daroussin case LIST_item: 11856d38604fSBaptiste Daroussin nn = nn->body->child == NULL ? n : nn->body; 11866d38604fSBaptiste Daroussin break; 11876d38604fSBaptiste Daroussin default: 11886d38604fSBaptiste Daroussin abort(); 11896d38604fSBaptiste Daroussin } 11906d38604fSBaptiste Daroussin break; 11916d38604fSBaptiste Daroussin case MDOC_Bd: 11926d38604fSBaptiste Daroussin case MDOC_Bl: 11936d38604fSBaptiste Daroussin case MDOC_D1: 11946d38604fSBaptiste Daroussin case MDOC_Dl: 11956d38604fSBaptiste Daroussin nn = nn->body->child == NULL ? n : nn->body; 11966d38604fSBaptiste Daroussin break; 11976d38604fSBaptiste Daroussin case MDOC_Pp: 11986d38604fSBaptiste Daroussin break; 11996d38604fSBaptiste Daroussin case MDOC_Cm: 12006d38604fSBaptiste Daroussin case MDOC_Dv: 12016d38604fSBaptiste Daroussin case MDOC_Em: 12026d38604fSBaptiste Daroussin case MDOC_Er: 12036d38604fSBaptiste Daroussin case MDOC_Ev: 12046d38604fSBaptiste Daroussin case MDOC_Fl: 12056d38604fSBaptiste Daroussin case MDOC_Fn: 12066d38604fSBaptiste Daroussin case MDOC_Ic: 12076d38604fSBaptiste Daroussin case MDOC_Li: 12086d38604fSBaptiste Daroussin case MDOC_Ms: 12096d38604fSBaptiste Daroussin case MDOC_No: 12106d38604fSBaptiste Daroussin case MDOC_Sy: 12116d38604fSBaptiste Daroussin if (nn->child == NULL) 12126d38604fSBaptiste Daroussin nn = n; 12136d38604fSBaptiste Daroussin break; 12146d38604fSBaptiste Daroussin default: 12156d38604fSBaptiste Daroussin nn = n; 12166d38604fSBaptiste Daroussin break; 12176d38604fSBaptiste Daroussin } 12186d38604fSBaptiste Daroussin tag_put(nt->string, TAG_MANUAL, nn); 12196d38604fSBaptiste Daroussin if (nn != n) 12206d38604fSBaptiste Daroussin n->flags |= NODE_NOPRT; 12216d38604fSBaptiste Daroussin } 12226d38604fSBaptiste Daroussin 12236d38604fSBaptiste Daroussin static void 122461d06d6bSBaptiste Daroussin post_obsolete(POST_ARGS) 122561d06d6bSBaptiste Daroussin { 122661d06d6bSBaptiste Daroussin struct roff_node *n; 122761d06d6bSBaptiste Daroussin 122861d06d6bSBaptiste Daroussin n = mdoc->last; 122961d06d6bSBaptiste Daroussin if (n->type == ROFFT_ELEM || n->type == ROFFT_BLOCK) 12307295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_MACRO_OBS, n->line, n->pos, 12317295610fSBaptiste Daroussin "%s", roff_name[n->tok]); 123261d06d6bSBaptiste Daroussin } 123361d06d6bSBaptiste Daroussin 123461d06d6bSBaptiste Daroussin static void 123561d06d6bSBaptiste Daroussin post_useless(POST_ARGS) 123661d06d6bSBaptiste Daroussin { 123761d06d6bSBaptiste Daroussin struct roff_node *n; 123861d06d6bSBaptiste Daroussin 123961d06d6bSBaptiste Daroussin n = mdoc->last; 12407295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_MACRO_USELESS, n->line, n->pos, 12417295610fSBaptiste Daroussin "%s", roff_name[n->tok]); 124261d06d6bSBaptiste Daroussin } 124361d06d6bSBaptiste Daroussin 124461d06d6bSBaptiste Daroussin /* 124561d06d6bSBaptiste Daroussin * Block macros. 124661d06d6bSBaptiste Daroussin */ 124761d06d6bSBaptiste Daroussin 124861d06d6bSBaptiste Daroussin static void 124961d06d6bSBaptiste Daroussin post_bf(POST_ARGS) 125061d06d6bSBaptiste Daroussin { 125161d06d6bSBaptiste Daroussin struct roff_node *np, *nch; 125261d06d6bSBaptiste Daroussin 125361d06d6bSBaptiste Daroussin /* 125461d06d6bSBaptiste Daroussin * Unlike other data pointers, these are "housed" by the HEAD 125561d06d6bSBaptiste Daroussin * element, which contains the goods. 125661d06d6bSBaptiste Daroussin */ 125761d06d6bSBaptiste Daroussin 125861d06d6bSBaptiste Daroussin np = mdoc->last; 125961d06d6bSBaptiste Daroussin if (np->type != ROFFT_HEAD) 126061d06d6bSBaptiste Daroussin return; 126161d06d6bSBaptiste Daroussin 126261d06d6bSBaptiste Daroussin assert(np->parent->type == ROFFT_BLOCK); 126361d06d6bSBaptiste Daroussin assert(np->parent->tok == MDOC_Bf); 126461d06d6bSBaptiste Daroussin 126561d06d6bSBaptiste Daroussin /* Check the number of arguments. */ 126661d06d6bSBaptiste Daroussin 126761d06d6bSBaptiste Daroussin nch = np->child; 126861d06d6bSBaptiste Daroussin if (np->parent->args == NULL) { 126961d06d6bSBaptiste Daroussin if (nch == NULL) { 12707295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_BF_NOFONT, 127161d06d6bSBaptiste Daroussin np->line, np->pos, "Bf"); 127261d06d6bSBaptiste Daroussin return; 127361d06d6bSBaptiste Daroussin } 127461d06d6bSBaptiste Daroussin nch = nch->next; 127561d06d6bSBaptiste Daroussin } 127661d06d6bSBaptiste Daroussin if (nch != NULL) 12777295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_ARG_EXCESS, 127861d06d6bSBaptiste Daroussin nch->line, nch->pos, "Bf ... %s", nch->string); 127961d06d6bSBaptiste Daroussin 128061d06d6bSBaptiste Daroussin /* Extract argument into data. */ 128161d06d6bSBaptiste Daroussin 128261d06d6bSBaptiste Daroussin if (np->parent->args != NULL) { 128361d06d6bSBaptiste Daroussin switch (np->parent->args->argv[0].arg) { 128461d06d6bSBaptiste Daroussin case MDOC_Emphasis: 128561d06d6bSBaptiste Daroussin np->norm->Bf.font = FONT_Em; 128661d06d6bSBaptiste Daroussin break; 128761d06d6bSBaptiste Daroussin case MDOC_Literal: 128861d06d6bSBaptiste Daroussin np->norm->Bf.font = FONT_Li; 128961d06d6bSBaptiste Daroussin break; 129061d06d6bSBaptiste Daroussin case MDOC_Symbolic: 129161d06d6bSBaptiste Daroussin np->norm->Bf.font = FONT_Sy; 129261d06d6bSBaptiste Daroussin break; 129361d06d6bSBaptiste Daroussin default: 129461d06d6bSBaptiste Daroussin abort(); 129561d06d6bSBaptiste Daroussin } 129661d06d6bSBaptiste Daroussin return; 129761d06d6bSBaptiste Daroussin } 129861d06d6bSBaptiste Daroussin 129961d06d6bSBaptiste Daroussin /* Extract parameter into data. */ 130061d06d6bSBaptiste Daroussin 130161d06d6bSBaptiste Daroussin if ( ! strcmp(np->child->string, "Em")) 130261d06d6bSBaptiste Daroussin np->norm->Bf.font = FONT_Em; 130361d06d6bSBaptiste Daroussin else if ( ! strcmp(np->child->string, "Li")) 130461d06d6bSBaptiste Daroussin np->norm->Bf.font = FONT_Li; 130561d06d6bSBaptiste Daroussin else if ( ! strcmp(np->child->string, "Sy")) 130661d06d6bSBaptiste Daroussin np->norm->Bf.font = FONT_Sy; 130761d06d6bSBaptiste Daroussin else 13087295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_BF_BADFONT, np->child->line, 13097295610fSBaptiste Daroussin np->child->pos, "Bf %s", np->child->string); 131061d06d6bSBaptiste Daroussin } 131161d06d6bSBaptiste Daroussin 131261d06d6bSBaptiste Daroussin static void 131361d06d6bSBaptiste Daroussin post_fname(POST_ARGS) 131461d06d6bSBaptiste Daroussin { 13156d38604fSBaptiste Daroussin struct roff_node *n, *nch; 131661d06d6bSBaptiste Daroussin const char *cp; 131761d06d6bSBaptiste Daroussin size_t pos; 131861d06d6bSBaptiste Daroussin 13196d38604fSBaptiste Daroussin n = mdoc->last; 13206d38604fSBaptiste Daroussin nch = n->child; 13216d38604fSBaptiste Daroussin cp = nch->string; 13226d38604fSBaptiste Daroussin if (*cp == '(') { 13236d38604fSBaptiste Daroussin if (cp[strlen(cp + 1)] == ')') 13246d38604fSBaptiste Daroussin return; 13256d38604fSBaptiste Daroussin pos = 0; 13266d38604fSBaptiste Daroussin } else { 13276d38604fSBaptiste Daroussin pos = strcspn(cp, "()"); 13286d38604fSBaptiste Daroussin if (cp[pos] == '\0') { 13296d38604fSBaptiste Daroussin if (n->sec == SEC_DESCRIPTION || 13306d38604fSBaptiste Daroussin n->sec == SEC_CUSTOM) 13316d38604fSBaptiste Daroussin tag_put(NULL, fn_prio++, n); 13326d38604fSBaptiste Daroussin return; 13336d38604fSBaptiste Daroussin } 13346d38604fSBaptiste Daroussin } 13356d38604fSBaptiste Daroussin mandoc_msg(MANDOCERR_FN_PAREN, nch->line, nch->pos + pos, "%s", cp); 133661d06d6bSBaptiste Daroussin } 133761d06d6bSBaptiste Daroussin 133861d06d6bSBaptiste Daroussin static void 133961d06d6bSBaptiste Daroussin post_fn(POST_ARGS) 134061d06d6bSBaptiste Daroussin { 134161d06d6bSBaptiste Daroussin post_fname(mdoc); 134261d06d6bSBaptiste Daroussin post_fa(mdoc); 134361d06d6bSBaptiste Daroussin } 134461d06d6bSBaptiste Daroussin 134561d06d6bSBaptiste Daroussin static void 134661d06d6bSBaptiste Daroussin post_fo(POST_ARGS) 134761d06d6bSBaptiste Daroussin { 134861d06d6bSBaptiste Daroussin const struct roff_node *n; 134961d06d6bSBaptiste Daroussin 135061d06d6bSBaptiste Daroussin n = mdoc->last; 135161d06d6bSBaptiste Daroussin 135261d06d6bSBaptiste Daroussin if (n->type != ROFFT_HEAD) 135361d06d6bSBaptiste Daroussin return; 135461d06d6bSBaptiste Daroussin 135561d06d6bSBaptiste Daroussin if (n->child == NULL) { 13567295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_FO_NOHEAD, n->line, n->pos, "Fo"); 135761d06d6bSBaptiste Daroussin return; 135861d06d6bSBaptiste Daroussin } 135961d06d6bSBaptiste Daroussin if (n->child != n->last) { 13607295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_ARG_EXCESS, 136161d06d6bSBaptiste Daroussin n->child->next->line, n->child->next->pos, 136261d06d6bSBaptiste Daroussin "Fo ... %s", n->child->next->string); 136361d06d6bSBaptiste Daroussin while (n->child != n->last) 136461d06d6bSBaptiste Daroussin roff_node_delete(mdoc, n->last); 136561d06d6bSBaptiste Daroussin } else 136661d06d6bSBaptiste Daroussin post_delim(mdoc); 136761d06d6bSBaptiste Daroussin 136861d06d6bSBaptiste Daroussin post_fname(mdoc); 136961d06d6bSBaptiste Daroussin } 137061d06d6bSBaptiste Daroussin 137161d06d6bSBaptiste Daroussin static void 137261d06d6bSBaptiste Daroussin post_fa(POST_ARGS) 137361d06d6bSBaptiste Daroussin { 137461d06d6bSBaptiste Daroussin const struct roff_node *n; 137561d06d6bSBaptiste Daroussin const char *cp; 137661d06d6bSBaptiste Daroussin 137761d06d6bSBaptiste Daroussin for (n = mdoc->last->child; n != NULL; n = n->next) { 137861d06d6bSBaptiste Daroussin for (cp = n->string; *cp != '\0'; cp++) { 137961d06d6bSBaptiste Daroussin /* Ignore callbacks and alterations. */ 138061d06d6bSBaptiste Daroussin if (*cp == '(' || *cp == '{') 138161d06d6bSBaptiste Daroussin break; 138261d06d6bSBaptiste Daroussin if (*cp != ',') 138361d06d6bSBaptiste Daroussin continue; 13847295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_FA_COMMA, n->line, 13857295610fSBaptiste Daroussin n->pos + (int)(cp - n->string), "%s", n->string); 138661d06d6bSBaptiste Daroussin break; 138761d06d6bSBaptiste Daroussin } 138861d06d6bSBaptiste Daroussin } 138961d06d6bSBaptiste Daroussin post_delim_nb(mdoc); 139061d06d6bSBaptiste Daroussin } 139161d06d6bSBaptiste Daroussin 139261d06d6bSBaptiste Daroussin static void 139361d06d6bSBaptiste Daroussin post_nm(POST_ARGS) 139461d06d6bSBaptiste Daroussin { 139561d06d6bSBaptiste Daroussin struct roff_node *n; 139661d06d6bSBaptiste Daroussin 139761d06d6bSBaptiste Daroussin n = mdoc->last; 139861d06d6bSBaptiste Daroussin 139961d06d6bSBaptiste Daroussin if (n->sec == SEC_NAME && n->child != NULL && 140061d06d6bSBaptiste Daroussin n->child->type == ROFFT_TEXT && mdoc->meta.msec != NULL) 140161d06d6bSBaptiste Daroussin mandoc_xr_add(mdoc->meta.msec, n->child->string, -1, -1); 140261d06d6bSBaptiste Daroussin 14037295610fSBaptiste Daroussin if (n->last != NULL && n->last->tok == MDOC_Pp) 14047295610fSBaptiste Daroussin roff_node_relink(mdoc, n->last); 140561d06d6bSBaptiste Daroussin 140661d06d6bSBaptiste Daroussin if (mdoc->meta.name == NULL) 140761d06d6bSBaptiste Daroussin deroff(&mdoc->meta.name, n); 140861d06d6bSBaptiste Daroussin 140961d06d6bSBaptiste Daroussin if (mdoc->meta.name == NULL || 141061d06d6bSBaptiste Daroussin (mdoc->lastsec == SEC_NAME && n->child == NULL)) 14117295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_NM_NONAME, n->line, n->pos, "Nm"); 141261d06d6bSBaptiste Daroussin 141361d06d6bSBaptiste Daroussin switch (n->type) { 141461d06d6bSBaptiste Daroussin case ROFFT_ELEM: 141561d06d6bSBaptiste Daroussin post_delim_nb(mdoc); 141661d06d6bSBaptiste Daroussin break; 141761d06d6bSBaptiste Daroussin case ROFFT_HEAD: 141861d06d6bSBaptiste Daroussin post_delim(mdoc); 141961d06d6bSBaptiste Daroussin break; 142061d06d6bSBaptiste Daroussin default: 142161d06d6bSBaptiste Daroussin return; 142261d06d6bSBaptiste Daroussin } 142361d06d6bSBaptiste Daroussin 142461d06d6bSBaptiste Daroussin if ((n->child != NULL && n->child->type == ROFFT_TEXT) || 142561d06d6bSBaptiste Daroussin mdoc->meta.name == NULL) 142661d06d6bSBaptiste Daroussin return; 142761d06d6bSBaptiste Daroussin 142861d06d6bSBaptiste Daroussin mdoc->next = ROFF_NEXT_CHILD; 142961d06d6bSBaptiste Daroussin roff_word_alloc(mdoc, n->line, n->pos, mdoc->meta.name); 143061d06d6bSBaptiste Daroussin mdoc->last->flags |= NODE_NOSRC; 143161d06d6bSBaptiste Daroussin mdoc->last = n; 143261d06d6bSBaptiste Daroussin } 143361d06d6bSBaptiste Daroussin 143461d06d6bSBaptiste Daroussin static void 143561d06d6bSBaptiste Daroussin post_nd(POST_ARGS) 143661d06d6bSBaptiste Daroussin { 143761d06d6bSBaptiste Daroussin struct roff_node *n; 143861d06d6bSBaptiste Daroussin 143961d06d6bSBaptiste Daroussin n = mdoc->last; 144061d06d6bSBaptiste Daroussin 144161d06d6bSBaptiste Daroussin if (n->type != ROFFT_BODY) 144261d06d6bSBaptiste Daroussin return; 144361d06d6bSBaptiste Daroussin 144461d06d6bSBaptiste Daroussin if (n->sec != SEC_NAME) 14457295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_ND_LATE, n->line, n->pos, "Nd"); 144661d06d6bSBaptiste Daroussin 144761d06d6bSBaptiste Daroussin if (n->child == NULL) 14487295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_ND_EMPTY, n->line, n->pos, "Nd"); 144961d06d6bSBaptiste Daroussin else 145061d06d6bSBaptiste Daroussin post_delim(mdoc); 145161d06d6bSBaptiste Daroussin 145261d06d6bSBaptiste Daroussin post_hyph(mdoc); 145361d06d6bSBaptiste Daroussin } 145461d06d6bSBaptiste Daroussin 145561d06d6bSBaptiste Daroussin static void 145661d06d6bSBaptiste Daroussin post_display(POST_ARGS) 145761d06d6bSBaptiste Daroussin { 145861d06d6bSBaptiste Daroussin struct roff_node *n, *np; 145961d06d6bSBaptiste Daroussin 146061d06d6bSBaptiste Daroussin n = mdoc->last; 146161d06d6bSBaptiste Daroussin switch (n->type) { 146261d06d6bSBaptiste Daroussin case ROFFT_BODY: 146361d06d6bSBaptiste Daroussin if (n->end != ENDBODY_NOT) { 146461d06d6bSBaptiste Daroussin if (n->tok == MDOC_Bd && 146561d06d6bSBaptiste Daroussin n->body->parent->args == NULL) 146661d06d6bSBaptiste Daroussin roff_node_delete(mdoc, n); 146761d06d6bSBaptiste Daroussin } else if (n->child == NULL) 14687295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_BLK_EMPTY, n->line, n->pos, 14697295610fSBaptiste Daroussin "%s", roff_name[n->tok]); 147061d06d6bSBaptiste Daroussin else if (n->tok == MDOC_D1) 147161d06d6bSBaptiste Daroussin post_hyph(mdoc); 147261d06d6bSBaptiste Daroussin break; 147361d06d6bSBaptiste Daroussin case ROFFT_BLOCK: 147461d06d6bSBaptiste Daroussin if (n->tok == MDOC_Bd) { 147561d06d6bSBaptiste Daroussin if (n->args == NULL) { 147661d06d6bSBaptiste Daroussin mandoc_msg(MANDOCERR_BD_NOARG, 14777295610fSBaptiste Daroussin n->line, n->pos, "Bd"); 147861d06d6bSBaptiste Daroussin mdoc->next = ROFF_NEXT_SIBLING; 147961d06d6bSBaptiste Daroussin while (n->body->child != NULL) 14807295610fSBaptiste Daroussin roff_node_relink(mdoc, 148161d06d6bSBaptiste Daroussin n->body->child); 148261d06d6bSBaptiste Daroussin roff_node_delete(mdoc, n); 148361d06d6bSBaptiste Daroussin break; 148461d06d6bSBaptiste Daroussin } 148561d06d6bSBaptiste Daroussin post_bd(mdoc); 148661d06d6bSBaptiste Daroussin post_prevpar(mdoc); 148761d06d6bSBaptiste Daroussin } 148861d06d6bSBaptiste Daroussin for (np = n->parent; np != NULL; np = np->parent) { 148961d06d6bSBaptiste Daroussin if (np->type == ROFFT_BLOCK && np->tok == MDOC_Bd) { 14907295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_BD_NEST, n->line, 14917295610fSBaptiste Daroussin n->pos, "%s in Bd", roff_name[n->tok]); 149261d06d6bSBaptiste Daroussin break; 149361d06d6bSBaptiste Daroussin } 149461d06d6bSBaptiste Daroussin } 149561d06d6bSBaptiste Daroussin break; 149661d06d6bSBaptiste Daroussin default: 149761d06d6bSBaptiste Daroussin break; 149861d06d6bSBaptiste Daroussin } 149961d06d6bSBaptiste Daroussin } 150061d06d6bSBaptiste Daroussin 150161d06d6bSBaptiste Daroussin static void 150261d06d6bSBaptiste Daroussin post_defaults(POST_ARGS) 150361d06d6bSBaptiste Daroussin { 15046d38604fSBaptiste Daroussin struct roff_node *n; 150561d06d6bSBaptiste Daroussin 15066d38604fSBaptiste Daroussin n = mdoc->last; 15076d38604fSBaptiste Daroussin if (n->child != NULL) { 150861d06d6bSBaptiste Daroussin post_delim_nb(mdoc); 150961d06d6bSBaptiste Daroussin return; 151061d06d6bSBaptiste Daroussin } 151161d06d6bSBaptiste Daroussin mdoc->next = ROFF_NEXT_CHILD; 15126d38604fSBaptiste Daroussin switch (n->tok) { 15136d38604fSBaptiste Daroussin case MDOC_Ar: 15146d38604fSBaptiste Daroussin roff_word_alloc(mdoc, n->line, n->pos, "file"); 151561d06d6bSBaptiste Daroussin mdoc->last->flags |= NODE_NOSRC; 15166d38604fSBaptiste Daroussin roff_word_alloc(mdoc, n->line, n->pos, "..."); 151761d06d6bSBaptiste Daroussin break; 151861d06d6bSBaptiste Daroussin case MDOC_Pa: 151961d06d6bSBaptiste Daroussin case MDOC_Mt: 15206d38604fSBaptiste Daroussin roff_word_alloc(mdoc, n->line, n->pos, "~"); 152161d06d6bSBaptiste Daroussin break; 152261d06d6bSBaptiste Daroussin default: 152361d06d6bSBaptiste Daroussin abort(); 152461d06d6bSBaptiste Daroussin } 15256d38604fSBaptiste Daroussin mdoc->last->flags |= NODE_NOSRC; 15266d38604fSBaptiste Daroussin mdoc->last = n; 152761d06d6bSBaptiste Daroussin } 152861d06d6bSBaptiste Daroussin 152961d06d6bSBaptiste Daroussin static void 153061d06d6bSBaptiste Daroussin post_at(POST_ARGS) 153161d06d6bSBaptiste Daroussin { 153261d06d6bSBaptiste Daroussin struct roff_node *n, *nch; 153361d06d6bSBaptiste Daroussin const char *att; 153461d06d6bSBaptiste Daroussin 153561d06d6bSBaptiste Daroussin n = mdoc->last; 153661d06d6bSBaptiste Daroussin nch = n->child; 153761d06d6bSBaptiste Daroussin 153861d06d6bSBaptiste Daroussin /* 153961d06d6bSBaptiste Daroussin * If we have a child, look it up in the standard keys. If a 154061d06d6bSBaptiste Daroussin * key exist, use that instead of the child; if it doesn't, 154161d06d6bSBaptiste Daroussin * prefix "AT&T UNIX " to the existing data. 154261d06d6bSBaptiste Daroussin */ 154361d06d6bSBaptiste Daroussin 154461d06d6bSBaptiste Daroussin att = NULL; 154561d06d6bSBaptiste Daroussin if (nch != NULL && ((att = mdoc_a2att(nch->string)) == NULL)) 15467295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_AT_BAD, 154761d06d6bSBaptiste Daroussin nch->line, nch->pos, "At %s", nch->string); 154861d06d6bSBaptiste Daroussin 154961d06d6bSBaptiste Daroussin mdoc->next = ROFF_NEXT_CHILD; 155061d06d6bSBaptiste Daroussin if (att != NULL) { 155161d06d6bSBaptiste Daroussin roff_word_alloc(mdoc, nch->line, nch->pos, att); 155261d06d6bSBaptiste Daroussin nch->flags |= NODE_NOPRT; 155361d06d6bSBaptiste Daroussin } else 155461d06d6bSBaptiste Daroussin roff_word_alloc(mdoc, n->line, n->pos, "AT&T UNIX"); 155561d06d6bSBaptiste Daroussin mdoc->last->flags |= NODE_NOSRC; 155661d06d6bSBaptiste Daroussin mdoc->last = n; 155761d06d6bSBaptiste Daroussin } 155861d06d6bSBaptiste Daroussin 155961d06d6bSBaptiste Daroussin static void 156061d06d6bSBaptiste Daroussin post_an(POST_ARGS) 156161d06d6bSBaptiste Daroussin { 156261d06d6bSBaptiste Daroussin struct roff_node *np, *nch; 156361d06d6bSBaptiste Daroussin 156461d06d6bSBaptiste Daroussin post_an_norm(mdoc); 156561d06d6bSBaptiste Daroussin 156661d06d6bSBaptiste Daroussin np = mdoc->last; 156761d06d6bSBaptiste Daroussin nch = np->child; 156861d06d6bSBaptiste Daroussin if (np->norm->An.auth == AUTH__NONE) { 156961d06d6bSBaptiste Daroussin if (nch == NULL) 15707295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_MACRO_EMPTY, 157161d06d6bSBaptiste Daroussin np->line, np->pos, "An"); 157261d06d6bSBaptiste Daroussin else 157361d06d6bSBaptiste Daroussin post_delim_nb(mdoc); 157461d06d6bSBaptiste Daroussin } else if (nch != NULL) 15757295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_ARG_EXCESS, 157661d06d6bSBaptiste Daroussin nch->line, nch->pos, "An ... %s", nch->string); 157761d06d6bSBaptiste Daroussin } 157861d06d6bSBaptiste Daroussin 157961d06d6bSBaptiste Daroussin static void 15806d38604fSBaptiste Daroussin post_em(POST_ARGS) 15816d38604fSBaptiste Daroussin { 15826d38604fSBaptiste Daroussin post_tag(mdoc); 15836d38604fSBaptiste Daroussin tag_put(NULL, TAG_FALLBACK, mdoc->last); 15846d38604fSBaptiste Daroussin } 15856d38604fSBaptiste Daroussin 15866d38604fSBaptiste Daroussin static void 158761d06d6bSBaptiste Daroussin post_en(POST_ARGS) 158861d06d6bSBaptiste Daroussin { 158961d06d6bSBaptiste Daroussin post_obsolete(mdoc); 159061d06d6bSBaptiste Daroussin if (mdoc->last->type == ROFFT_BLOCK) 159161d06d6bSBaptiste Daroussin mdoc->last->norm->Es = mdoc->last_es; 159261d06d6bSBaptiste Daroussin } 159361d06d6bSBaptiste Daroussin 159461d06d6bSBaptiste Daroussin static void 15956d38604fSBaptiste Daroussin post_er(POST_ARGS) 15966d38604fSBaptiste Daroussin { 15976d38604fSBaptiste Daroussin struct roff_node *n; 15986d38604fSBaptiste Daroussin 15996d38604fSBaptiste Daroussin n = mdoc->last; 16006d38604fSBaptiste Daroussin if (n->sec == SEC_ERRORS && 16016d38604fSBaptiste Daroussin (n->parent->tok == MDOC_It || 16026d38604fSBaptiste Daroussin (n->parent->tok == MDOC_Bq && 16036d38604fSBaptiste Daroussin n->parent->parent->parent->tok == MDOC_It))) 16046d38604fSBaptiste Daroussin tag_put(NULL, TAG_STRONG, n); 16056d38604fSBaptiste Daroussin post_delim_nb(mdoc); 16066d38604fSBaptiste Daroussin } 16076d38604fSBaptiste Daroussin 16086d38604fSBaptiste Daroussin static void 16096d38604fSBaptiste Daroussin post_tag(POST_ARGS) 16106d38604fSBaptiste Daroussin { 16116d38604fSBaptiste Daroussin struct roff_node *n; 16126d38604fSBaptiste Daroussin 16136d38604fSBaptiste Daroussin n = mdoc->last; 16146d38604fSBaptiste Daroussin if ((n->prev == NULL || 16156d38604fSBaptiste Daroussin (n->prev->type == ROFFT_TEXT && 16166d38604fSBaptiste Daroussin strcmp(n->prev->string, "|") == 0)) && 16176d38604fSBaptiste Daroussin (n->parent->tok == MDOC_It || 16186d38604fSBaptiste Daroussin (n->parent->tok == MDOC_Xo && 16196d38604fSBaptiste Daroussin n->parent->parent->prev == NULL && 16206d38604fSBaptiste Daroussin n->parent->parent->parent->tok == MDOC_It))) 16216d38604fSBaptiste Daroussin tag_put(NULL, TAG_STRONG, n); 16226d38604fSBaptiste Daroussin post_delim_nb(mdoc); 16236d38604fSBaptiste Daroussin } 16246d38604fSBaptiste Daroussin 16256d38604fSBaptiste Daroussin static void 162661d06d6bSBaptiste Daroussin post_es(POST_ARGS) 162761d06d6bSBaptiste Daroussin { 162861d06d6bSBaptiste Daroussin post_obsolete(mdoc); 162961d06d6bSBaptiste Daroussin mdoc->last_es = mdoc->last; 163061d06d6bSBaptiste Daroussin } 163161d06d6bSBaptiste Daroussin 163261d06d6bSBaptiste Daroussin static void 16336d38604fSBaptiste Daroussin post_fl(POST_ARGS) 16346d38604fSBaptiste Daroussin { 16356d38604fSBaptiste Daroussin struct roff_node *n; 16366d38604fSBaptiste Daroussin char *cp; 16376d38604fSBaptiste Daroussin 16386d38604fSBaptiste Daroussin /* 16396d38604fSBaptiste Daroussin * Transform ".Fl Fl long" to ".Fl \-long", 16406d38604fSBaptiste Daroussin * resulting for example in better HTML output. 16416d38604fSBaptiste Daroussin */ 16426d38604fSBaptiste Daroussin 16436d38604fSBaptiste Daroussin n = mdoc->last; 16446d38604fSBaptiste Daroussin if (n->prev != NULL && n->prev->tok == MDOC_Fl && 16456d38604fSBaptiste Daroussin n->prev->child == NULL && n->child != NULL && 16466d38604fSBaptiste Daroussin (n->flags & NODE_LINE) == 0) { 16476d38604fSBaptiste Daroussin mandoc_asprintf(&cp, "\\-%s", n->child->string); 16486d38604fSBaptiste Daroussin free(n->child->string); 16496d38604fSBaptiste Daroussin n->child->string = cp; 16506d38604fSBaptiste Daroussin roff_node_delete(mdoc, n->prev); 16516d38604fSBaptiste Daroussin } 16526d38604fSBaptiste Daroussin post_tag(mdoc); 16536d38604fSBaptiste Daroussin } 16546d38604fSBaptiste Daroussin 16556d38604fSBaptiste Daroussin static void 165661d06d6bSBaptiste Daroussin post_xx(POST_ARGS) 165761d06d6bSBaptiste Daroussin { 165861d06d6bSBaptiste Daroussin struct roff_node *n; 165961d06d6bSBaptiste Daroussin const char *os; 166061d06d6bSBaptiste Daroussin char *v; 166161d06d6bSBaptiste Daroussin 166261d06d6bSBaptiste Daroussin post_delim_nb(mdoc); 166361d06d6bSBaptiste Daroussin 166461d06d6bSBaptiste Daroussin n = mdoc->last; 166561d06d6bSBaptiste Daroussin switch (n->tok) { 166661d06d6bSBaptiste Daroussin case MDOC_Bsx: 166761d06d6bSBaptiste Daroussin os = "BSD/OS"; 166861d06d6bSBaptiste Daroussin break; 166961d06d6bSBaptiste Daroussin case MDOC_Dx: 167061d06d6bSBaptiste Daroussin os = "DragonFly"; 167161d06d6bSBaptiste Daroussin break; 167261d06d6bSBaptiste Daroussin case MDOC_Fx: 167361d06d6bSBaptiste Daroussin os = "FreeBSD"; 167461d06d6bSBaptiste Daroussin break; 167561d06d6bSBaptiste Daroussin case MDOC_Nx: 167661d06d6bSBaptiste Daroussin os = "NetBSD"; 167761d06d6bSBaptiste Daroussin if (n->child == NULL) 167861d06d6bSBaptiste Daroussin break; 167961d06d6bSBaptiste Daroussin v = n->child->string; 168061d06d6bSBaptiste Daroussin if ((v[0] != '0' && v[0] != '1') || v[1] != '.' || 168161d06d6bSBaptiste Daroussin v[2] < '0' || v[2] > '9' || 168261d06d6bSBaptiste Daroussin v[3] < 'a' || v[3] > 'z' || v[4] != '\0') 168361d06d6bSBaptiste Daroussin break; 168461d06d6bSBaptiste Daroussin n->child->flags |= NODE_NOPRT; 168561d06d6bSBaptiste Daroussin mdoc->next = ROFF_NEXT_CHILD; 168661d06d6bSBaptiste Daroussin roff_word_alloc(mdoc, n->child->line, n->child->pos, v); 168761d06d6bSBaptiste Daroussin v = mdoc->last->string; 168861d06d6bSBaptiste Daroussin v[3] = toupper((unsigned char)v[3]); 168961d06d6bSBaptiste Daroussin mdoc->last->flags |= NODE_NOSRC; 169061d06d6bSBaptiste Daroussin mdoc->last = n; 169161d06d6bSBaptiste Daroussin break; 169261d06d6bSBaptiste Daroussin case MDOC_Ox: 169361d06d6bSBaptiste Daroussin os = "OpenBSD"; 169461d06d6bSBaptiste Daroussin break; 169561d06d6bSBaptiste Daroussin case MDOC_Ux: 169661d06d6bSBaptiste Daroussin os = "UNIX"; 169761d06d6bSBaptiste Daroussin break; 169861d06d6bSBaptiste Daroussin default: 169961d06d6bSBaptiste Daroussin abort(); 170061d06d6bSBaptiste Daroussin } 170161d06d6bSBaptiste Daroussin mdoc->next = ROFF_NEXT_CHILD; 170261d06d6bSBaptiste Daroussin roff_word_alloc(mdoc, n->line, n->pos, os); 170361d06d6bSBaptiste Daroussin mdoc->last->flags |= NODE_NOSRC; 170461d06d6bSBaptiste Daroussin mdoc->last = n; 170561d06d6bSBaptiste Daroussin } 170661d06d6bSBaptiste Daroussin 170761d06d6bSBaptiste Daroussin static void 170861d06d6bSBaptiste Daroussin post_it(POST_ARGS) 170961d06d6bSBaptiste Daroussin { 171061d06d6bSBaptiste Daroussin struct roff_node *nbl, *nit, *nch; 171161d06d6bSBaptiste Daroussin int i, cols; 171261d06d6bSBaptiste Daroussin enum mdoc_list lt; 171361d06d6bSBaptiste Daroussin 171461d06d6bSBaptiste Daroussin post_prevpar(mdoc); 171561d06d6bSBaptiste Daroussin 171661d06d6bSBaptiste Daroussin nit = mdoc->last; 171761d06d6bSBaptiste Daroussin if (nit->type != ROFFT_BLOCK) 171861d06d6bSBaptiste Daroussin return; 171961d06d6bSBaptiste Daroussin 172061d06d6bSBaptiste Daroussin nbl = nit->parent->parent; 172161d06d6bSBaptiste Daroussin lt = nbl->norm->Bl.type; 172261d06d6bSBaptiste Daroussin 172361d06d6bSBaptiste Daroussin switch (lt) { 172461d06d6bSBaptiste Daroussin case LIST_tag: 172561d06d6bSBaptiste Daroussin case LIST_hang: 172661d06d6bSBaptiste Daroussin case LIST_ohang: 172761d06d6bSBaptiste Daroussin case LIST_inset: 172861d06d6bSBaptiste Daroussin case LIST_diag: 172961d06d6bSBaptiste Daroussin if (nit->head->child == NULL) 17307295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_IT_NOHEAD, 17317295610fSBaptiste Daroussin nit->line, nit->pos, "Bl -%s It", 173261d06d6bSBaptiste Daroussin mdoc_argnames[nbl->args->argv[0].arg]); 173361d06d6bSBaptiste Daroussin break; 173461d06d6bSBaptiste Daroussin case LIST_bullet: 173561d06d6bSBaptiste Daroussin case LIST_dash: 173661d06d6bSBaptiste Daroussin case LIST_enum: 173761d06d6bSBaptiste Daroussin case LIST_hyphen: 173861d06d6bSBaptiste Daroussin if (nit->body == NULL || nit->body->child == NULL) 17397295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_IT_NOBODY, 17407295610fSBaptiste Daroussin nit->line, nit->pos, "Bl -%s It", 174161d06d6bSBaptiste Daroussin mdoc_argnames[nbl->args->argv[0].arg]); 174261d06d6bSBaptiste Daroussin /* FALLTHROUGH */ 174361d06d6bSBaptiste Daroussin case LIST_item: 174461d06d6bSBaptiste Daroussin if ((nch = nit->head->child) != NULL) 17457295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_ARG_SKIP, 174661d06d6bSBaptiste Daroussin nit->line, nit->pos, "It %s", 17476d38604fSBaptiste Daroussin nch->type == ROFFT_TEXT ? nch->string : 17486d38604fSBaptiste Daroussin roff_name[nch->tok]); 174961d06d6bSBaptiste Daroussin break; 175061d06d6bSBaptiste Daroussin case LIST_column: 175161d06d6bSBaptiste Daroussin cols = (int)nbl->norm->Bl.ncols; 175261d06d6bSBaptiste Daroussin 175361d06d6bSBaptiste Daroussin assert(nit->head->child == NULL); 175461d06d6bSBaptiste Daroussin 175561d06d6bSBaptiste Daroussin if (nit->head->next->child == NULL && 175661d06d6bSBaptiste Daroussin nit->head->next->next == NULL) { 17577295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_MACRO_EMPTY, 175861d06d6bSBaptiste Daroussin nit->line, nit->pos, "It"); 175961d06d6bSBaptiste Daroussin roff_node_delete(mdoc, nit); 176061d06d6bSBaptiste Daroussin break; 176161d06d6bSBaptiste Daroussin } 176261d06d6bSBaptiste Daroussin 176361d06d6bSBaptiste Daroussin i = 0; 176461d06d6bSBaptiste Daroussin for (nch = nit->child; nch != NULL; nch = nch->next) { 176561d06d6bSBaptiste Daroussin if (nch->type != ROFFT_BODY) 176661d06d6bSBaptiste Daroussin continue; 176761d06d6bSBaptiste Daroussin if (i++ && nch->flags & NODE_LINE) 17687295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_TA_LINE, 176961d06d6bSBaptiste Daroussin nch->line, nch->pos, "Ta"); 177061d06d6bSBaptiste Daroussin } 177161d06d6bSBaptiste Daroussin if (i < cols || i > cols + 1) 17727295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_BL_COL, nit->line, nit->pos, 177361d06d6bSBaptiste Daroussin "%d columns, %d cells", cols, i); 177461d06d6bSBaptiste Daroussin else if (nit->head->next->child != NULL && 17757295610fSBaptiste Daroussin nit->head->next->child->flags & NODE_LINE) 17767295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_IT_NOARG, 177761d06d6bSBaptiste Daroussin nit->line, nit->pos, "Bl -column It"); 177861d06d6bSBaptiste Daroussin break; 177961d06d6bSBaptiste Daroussin default: 178061d06d6bSBaptiste Daroussin abort(); 178161d06d6bSBaptiste Daroussin } 178261d06d6bSBaptiste Daroussin } 178361d06d6bSBaptiste Daroussin 178461d06d6bSBaptiste Daroussin static void 178561d06d6bSBaptiste Daroussin post_bl_block(POST_ARGS) 178661d06d6bSBaptiste Daroussin { 178761d06d6bSBaptiste Daroussin struct roff_node *n, *ni, *nc; 178861d06d6bSBaptiste Daroussin 178961d06d6bSBaptiste Daroussin post_prevpar(mdoc); 179061d06d6bSBaptiste Daroussin 179161d06d6bSBaptiste Daroussin n = mdoc->last; 179261d06d6bSBaptiste Daroussin for (ni = n->body->child; ni != NULL; ni = ni->next) { 179361d06d6bSBaptiste Daroussin if (ni->body == NULL) 179461d06d6bSBaptiste Daroussin continue; 179561d06d6bSBaptiste Daroussin nc = ni->body->last; 179661d06d6bSBaptiste Daroussin while (nc != NULL) { 179761d06d6bSBaptiste Daroussin switch (nc->tok) { 179861d06d6bSBaptiste Daroussin case MDOC_Pp: 179961d06d6bSBaptiste Daroussin case ROFF_br: 180061d06d6bSBaptiste Daroussin break; 180161d06d6bSBaptiste Daroussin default: 180261d06d6bSBaptiste Daroussin nc = NULL; 180361d06d6bSBaptiste Daroussin continue; 180461d06d6bSBaptiste Daroussin } 180561d06d6bSBaptiste Daroussin if (ni->next == NULL) { 18067295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_PAR_MOVE, nc->line, 18077295610fSBaptiste Daroussin nc->pos, "%s", roff_name[nc->tok]); 18087295610fSBaptiste Daroussin roff_node_relink(mdoc, nc); 180961d06d6bSBaptiste Daroussin } else if (n->norm->Bl.comp == 0 && 181061d06d6bSBaptiste Daroussin n->norm->Bl.type != LIST_column) { 18117295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_PAR_SKIP, 18127295610fSBaptiste Daroussin nc->line, nc->pos, 181361d06d6bSBaptiste Daroussin "%s before It", roff_name[nc->tok]); 181461d06d6bSBaptiste Daroussin roff_node_delete(mdoc, nc); 181561d06d6bSBaptiste Daroussin } else 181661d06d6bSBaptiste Daroussin break; 181761d06d6bSBaptiste Daroussin nc = ni->body->last; 181861d06d6bSBaptiste Daroussin } 181961d06d6bSBaptiste Daroussin } 182061d06d6bSBaptiste Daroussin } 182161d06d6bSBaptiste Daroussin 182261d06d6bSBaptiste Daroussin /* 18239f6a619aSEric van Gyzen * If "in" begins with a dot, a word, and whitespace, return a dynamically 18249f6a619aSEric van Gyzen * allocated copy of "in" that skips all of those. Otherwise, return NULL. 18259f6a619aSEric van Gyzen * 18269f6a619aSEric van Gyzen * This is a partial workaround for the TODO list item beginning with: 18279f6a619aSEric van Gyzen * - When the -width string contains macros, the macros must be rendered 18289f6a619aSEric van Gyzen */ 18299f6a619aSEric van Gyzen static char * 18309f6a619aSEric van Gyzen skip_leading_dot_word(const char *in) 18319f6a619aSEric van Gyzen { 18329f6a619aSEric van Gyzen const char *iter = in; 18339f6a619aSEric van Gyzen const char *space; 18349f6a619aSEric van Gyzen 18359f6a619aSEric van Gyzen if (*iter != '.') 18369f6a619aSEric van Gyzen return NULL; 18379f6a619aSEric van Gyzen iter++; 18389f6a619aSEric van Gyzen 18399f6a619aSEric van Gyzen while (*iter != '\0' && !isspace(*iter)) 18409f6a619aSEric van Gyzen iter++; 18419f6a619aSEric van Gyzen /* 18429f6a619aSEric van Gyzen * If the dot was followed by space or NUL, 18439f6a619aSEric van Gyzen * do not skip anything. 18449f6a619aSEric van Gyzen */ 18459f6a619aSEric van Gyzen if (iter == in + 1) 18469f6a619aSEric van Gyzen return NULL; 18479f6a619aSEric van Gyzen 18489f6a619aSEric van Gyzen space = iter; 18499f6a619aSEric van Gyzen while (isspace(*iter)) 18509f6a619aSEric van Gyzen iter++; 18519f6a619aSEric van Gyzen /* 18529f6a619aSEric van Gyzen * If the word was not followed by space, 18539f6a619aSEric van Gyzen * do not skip anything. 18549f6a619aSEric van Gyzen */ 18559f6a619aSEric van Gyzen if (iter == space) 18569f6a619aSEric van Gyzen return NULL; 18579f6a619aSEric van Gyzen 18589f6a619aSEric van Gyzen return strdup(iter); 18599f6a619aSEric van Gyzen } 18609f6a619aSEric van Gyzen 18619f6a619aSEric van Gyzen /* 186261d06d6bSBaptiste Daroussin * If the argument of -offset or -width is a macro, 186361d06d6bSBaptiste Daroussin * replace it with the associated default width. 186461d06d6bSBaptiste Daroussin */ 186561d06d6bSBaptiste Daroussin static void 186661d06d6bSBaptiste Daroussin rewrite_macro2len(struct roff_man *mdoc, char **arg) 186761d06d6bSBaptiste Daroussin { 186861d06d6bSBaptiste Daroussin size_t width; 186961d06d6bSBaptiste Daroussin enum roff_tok tok; 18709f6a619aSEric van Gyzen char *newarg; 187161d06d6bSBaptiste Daroussin 18729f6a619aSEric van Gyzen newarg = NULL; 187361d06d6bSBaptiste Daroussin if (*arg == NULL) 187461d06d6bSBaptiste Daroussin return; 187561d06d6bSBaptiste Daroussin else if ( ! strcmp(*arg, "Ds")) 187661d06d6bSBaptiste Daroussin width = 6; 18779f6a619aSEric van Gyzen else if ((tok = roffhash_find(mdoc->mdocmac, *arg, 0)) != TOKEN_NONE) 187861d06d6bSBaptiste Daroussin width = macro2len(tok); 18799f6a619aSEric van Gyzen else if ((newarg = skip_leading_dot_word(*arg)) == NULL) 18809f6a619aSEric van Gyzen return; 188161d06d6bSBaptiste Daroussin 188261d06d6bSBaptiste Daroussin free(*arg); 18839f6a619aSEric van Gyzen if (newarg != NULL) 18849f6a619aSEric van Gyzen *arg = newarg; 18859f6a619aSEric van Gyzen else 188661d06d6bSBaptiste Daroussin mandoc_asprintf(arg, "%zun", width); 188761d06d6bSBaptiste Daroussin } 188861d06d6bSBaptiste Daroussin 188961d06d6bSBaptiste Daroussin static void 189061d06d6bSBaptiste Daroussin post_bl_head(POST_ARGS) 189161d06d6bSBaptiste Daroussin { 189261d06d6bSBaptiste Daroussin struct roff_node *nbl, *nh, *nch, *nnext; 189361d06d6bSBaptiste Daroussin struct mdoc_argv *argv; 189461d06d6bSBaptiste Daroussin int i, j; 189561d06d6bSBaptiste Daroussin 189661d06d6bSBaptiste Daroussin post_bl_norm(mdoc); 189761d06d6bSBaptiste Daroussin 189861d06d6bSBaptiste Daroussin nh = mdoc->last; 189961d06d6bSBaptiste Daroussin if (nh->norm->Bl.type != LIST_column) { 190061d06d6bSBaptiste Daroussin if ((nch = nh->child) == NULL) 190161d06d6bSBaptiste Daroussin return; 19027295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_ARG_EXCESS, 190361d06d6bSBaptiste Daroussin nch->line, nch->pos, "Bl ... %s", nch->string); 190461d06d6bSBaptiste Daroussin while (nch != NULL) { 190561d06d6bSBaptiste Daroussin roff_node_delete(mdoc, nch); 190661d06d6bSBaptiste Daroussin nch = nh->child; 190761d06d6bSBaptiste Daroussin } 190861d06d6bSBaptiste Daroussin return; 190961d06d6bSBaptiste Daroussin } 191061d06d6bSBaptiste Daroussin 191161d06d6bSBaptiste Daroussin /* 191261d06d6bSBaptiste Daroussin * Append old-style lists, where the column width specifiers 191361d06d6bSBaptiste Daroussin * trail as macro parameters, to the new-style ("normal-form") 191461d06d6bSBaptiste Daroussin * lists where they're argument values following -column. 191561d06d6bSBaptiste Daroussin */ 191661d06d6bSBaptiste Daroussin 191761d06d6bSBaptiste Daroussin if (nh->child == NULL) 191861d06d6bSBaptiste Daroussin return; 191961d06d6bSBaptiste Daroussin 192061d06d6bSBaptiste Daroussin nbl = nh->parent; 192161d06d6bSBaptiste Daroussin for (j = 0; j < (int)nbl->args->argc; j++) 192261d06d6bSBaptiste Daroussin if (nbl->args->argv[j].arg == MDOC_Column) 192361d06d6bSBaptiste Daroussin break; 192461d06d6bSBaptiste Daroussin 192561d06d6bSBaptiste Daroussin assert(j < (int)nbl->args->argc); 192661d06d6bSBaptiste Daroussin 192761d06d6bSBaptiste Daroussin /* 192861d06d6bSBaptiste Daroussin * Accommodate for new-style groff column syntax. Shuffle the 192961d06d6bSBaptiste Daroussin * child nodes, all of which must be TEXT, as arguments for the 193061d06d6bSBaptiste Daroussin * column field. Then, delete the head children. 193161d06d6bSBaptiste Daroussin */ 193261d06d6bSBaptiste Daroussin 193361d06d6bSBaptiste Daroussin argv = nbl->args->argv + j; 193461d06d6bSBaptiste Daroussin i = argv->sz; 193561d06d6bSBaptiste Daroussin for (nch = nh->child; nch != NULL; nch = nch->next) 193661d06d6bSBaptiste Daroussin argv->sz++; 193761d06d6bSBaptiste Daroussin argv->value = mandoc_reallocarray(argv->value, 193861d06d6bSBaptiste Daroussin argv->sz, sizeof(char *)); 193961d06d6bSBaptiste Daroussin 194061d06d6bSBaptiste Daroussin nh->norm->Bl.ncols = argv->sz; 194161d06d6bSBaptiste Daroussin nh->norm->Bl.cols = (void *)argv->value; 194261d06d6bSBaptiste Daroussin 194361d06d6bSBaptiste Daroussin for (nch = nh->child; nch != NULL; nch = nnext) { 194461d06d6bSBaptiste Daroussin argv->value[i++] = nch->string; 194561d06d6bSBaptiste Daroussin nch->string = NULL; 194661d06d6bSBaptiste Daroussin nnext = nch->next; 194761d06d6bSBaptiste Daroussin roff_node_delete(NULL, nch); 194861d06d6bSBaptiste Daroussin } 194961d06d6bSBaptiste Daroussin nh->child = NULL; 195061d06d6bSBaptiste Daroussin } 195161d06d6bSBaptiste Daroussin 195261d06d6bSBaptiste Daroussin static void 195361d06d6bSBaptiste Daroussin post_bl(POST_ARGS) 195461d06d6bSBaptiste Daroussin { 19556d38604fSBaptiste Daroussin struct roff_node *nbody; /* of the Bl */ 195661d06d6bSBaptiste Daroussin struct roff_node *nchild, *nnext; /* of the Bl body */ 195761d06d6bSBaptiste Daroussin const char *prev_Er; 195861d06d6bSBaptiste Daroussin int order; 195961d06d6bSBaptiste Daroussin 196061d06d6bSBaptiste Daroussin nbody = mdoc->last; 196161d06d6bSBaptiste Daroussin switch (nbody->type) { 196261d06d6bSBaptiste Daroussin case ROFFT_BLOCK: 196361d06d6bSBaptiste Daroussin post_bl_block(mdoc); 196461d06d6bSBaptiste Daroussin return; 196561d06d6bSBaptiste Daroussin case ROFFT_HEAD: 196661d06d6bSBaptiste Daroussin post_bl_head(mdoc); 196761d06d6bSBaptiste Daroussin return; 196861d06d6bSBaptiste Daroussin case ROFFT_BODY: 196961d06d6bSBaptiste Daroussin break; 197061d06d6bSBaptiste Daroussin default: 197161d06d6bSBaptiste Daroussin return; 197261d06d6bSBaptiste Daroussin } 197361d06d6bSBaptiste Daroussin if (nbody->end != ENDBODY_NOT) 197461d06d6bSBaptiste Daroussin return; 197561d06d6bSBaptiste Daroussin 19766d38604fSBaptiste Daroussin /* 19776d38604fSBaptiste Daroussin * Up to the first item, move nodes before the list, 19786d38604fSBaptiste Daroussin * but leave transparent nodes where they are 19796d38604fSBaptiste Daroussin * if they precede an item. 19806d38604fSBaptiste Daroussin * The next non-transparent node is kept in nchild. 19816d38604fSBaptiste Daroussin * It only needs to be updated after a non-transparent 19826d38604fSBaptiste Daroussin * node was moved out, and at the very beginning 19836d38604fSBaptiste Daroussin * when no node at all was moved yet. 19846d38604fSBaptiste Daroussin */ 19856d38604fSBaptiste Daroussin 19866d38604fSBaptiste Daroussin nchild = mdoc->last; 19876d38604fSBaptiste Daroussin for (;;) { 19886d38604fSBaptiste Daroussin if (nchild == mdoc->last) 19896d38604fSBaptiste Daroussin nchild = roff_node_child(nbody); 199061d06d6bSBaptiste Daroussin if (nchild == NULL) { 19916d38604fSBaptiste Daroussin mdoc->last = nbody; 19927295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_BLK_EMPTY, 199361d06d6bSBaptiste Daroussin nbody->line, nbody->pos, "Bl"); 199461d06d6bSBaptiste Daroussin return; 199561d06d6bSBaptiste Daroussin } 19966d38604fSBaptiste Daroussin if (nchild->tok == MDOC_It) { 19976d38604fSBaptiste Daroussin mdoc->last = nbody; 19986d38604fSBaptiste Daroussin break; 19996d38604fSBaptiste Daroussin } 20006d38604fSBaptiste Daroussin mandoc_msg(MANDOCERR_BL_MOVE, nbody->child->line, 20016d38604fSBaptiste Daroussin nbody->child->pos, "%s", roff_name[nbody->child->tok]); 20026d38604fSBaptiste Daroussin if (nbody->parent->prev == NULL) { 20036d38604fSBaptiste Daroussin mdoc->last = nbody->parent->parent; 20046d38604fSBaptiste Daroussin mdoc->next = ROFF_NEXT_CHILD; 20056d38604fSBaptiste Daroussin } else { 20066d38604fSBaptiste Daroussin mdoc->last = nbody->parent->prev; 20076d38604fSBaptiste Daroussin mdoc->next = ROFF_NEXT_SIBLING; 20086d38604fSBaptiste Daroussin } 20096d38604fSBaptiste Daroussin roff_node_relink(mdoc, nbody->child); 201061d06d6bSBaptiste Daroussin } 201161d06d6bSBaptiste Daroussin 201261d06d6bSBaptiste Daroussin /* 20136d38604fSBaptiste Daroussin * We have reached the first item, 20146d38604fSBaptiste Daroussin * so moving nodes out is no longer possible. 20156d38604fSBaptiste Daroussin * But in .Bl -column, the first rows may be implicit, 201661d06d6bSBaptiste Daroussin * that is, they may not start with .It macros. 201761d06d6bSBaptiste Daroussin * Such rows may be followed by nodes generated on the 20186d38604fSBaptiste Daroussin * roff level, for example .TS. 20196d38604fSBaptiste Daroussin * Wrap such roff nodes into an implicit row. 202061d06d6bSBaptiste Daroussin */ 202161d06d6bSBaptiste Daroussin 20226d38604fSBaptiste Daroussin while (nchild != NULL) { 20236d38604fSBaptiste Daroussin if (nchild->tok == MDOC_It) { 20246d38604fSBaptiste Daroussin nchild = roff_node_next(nchild); 20256d38604fSBaptiste Daroussin continue; 20266d38604fSBaptiste Daroussin } 20276d38604fSBaptiste Daroussin nnext = nchild->next; 20286d38604fSBaptiste Daroussin mdoc->last = nchild->prev; 202961d06d6bSBaptiste Daroussin mdoc->next = ROFF_NEXT_SIBLING; 20306d38604fSBaptiste Daroussin roff_block_alloc(mdoc, nchild->line, nchild->pos, MDOC_It); 20316d38604fSBaptiste Daroussin roff_head_alloc(mdoc, nchild->line, nchild->pos, MDOC_It); 203261d06d6bSBaptiste Daroussin mdoc->next = ROFF_NEXT_SIBLING; 20336d38604fSBaptiste Daroussin roff_body_alloc(mdoc, nchild->line, nchild->pos, MDOC_It); 203461d06d6bSBaptiste Daroussin while (nchild->tok != MDOC_It) { 20357295610fSBaptiste Daroussin roff_node_relink(mdoc, nchild); 20366d38604fSBaptiste Daroussin if (nnext == NULL) 203761d06d6bSBaptiste Daroussin break; 20386d38604fSBaptiste Daroussin nchild = nnext; 203961d06d6bSBaptiste Daroussin nnext = nchild->next; 204061d06d6bSBaptiste Daroussin mdoc->next = ROFF_NEXT_SIBLING; 204161d06d6bSBaptiste Daroussin } 204261d06d6bSBaptiste Daroussin mdoc->last = nbody; 204361d06d6bSBaptiste Daroussin } 204461d06d6bSBaptiste Daroussin 204561d06d6bSBaptiste Daroussin if (mdoc->meta.os_e != MANDOC_OS_NETBSD) 204661d06d6bSBaptiste Daroussin return; 204761d06d6bSBaptiste Daroussin 204861d06d6bSBaptiste Daroussin prev_Er = NULL; 204961d06d6bSBaptiste Daroussin for (nchild = nbody->child; nchild != NULL; nchild = nchild->next) { 205061d06d6bSBaptiste Daroussin if (nchild->tok != MDOC_It) 205161d06d6bSBaptiste Daroussin continue; 205261d06d6bSBaptiste Daroussin if ((nnext = nchild->head->child) == NULL) 205361d06d6bSBaptiste Daroussin continue; 205461d06d6bSBaptiste Daroussin if (nnext->type == ROFFT_BLOCK) 205561d06d6bSBaptiste Daroussin nnext = nnext->body->child; 205661d06d6bSBaptiste Daroussin if (nnext == NULL || nnext->tok != MDOC_Er) 205761d06d6bSBaptiste Daroussin continue; 205861d06d6bSBaptiste Daroussin nnext = nnext->child; 205961d06d6bSBaptiste Daroussin if (prev_Er != NULL) { 206061d06d6bSBaptiste Daroussin order = strcmp(prev_Er, nnext->string); 206161d06d6bSBaptiste Daroussin if (order > 0) 20627295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_ER_ORDER, 20637295610fSBaptiste Daroussin nnext->line, nnext->pos, 206461d06d6bSBaptiste Daroussin "Er %s %s (NetBSD)", 206561d06d6bSBaptiste Daroussin prev_Er, nnext->string); 206661d06d6bSBaptiste Daroussin else if (order == 0) 20677295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_ER_REP, 20687295610fSBaptiste Daroussin nnext->line, nnext->pos, 206961d06d6bSBaptiste Daroussin "Er %s (NetBSD)", prev_Er); 207061d06d6bSBaptiste Daroussin } 207161d06d6bSBaptiste Daroussin prev_Er = nnext->string; 207261d06d6bSBaptiste Daroussin } 207361d06d6bSBaptiste Daroussin } 207461d06d6bSBaptiste Daroussin 207561d06d6bSBaptiste Daroussin static void 207661d06d6bSBaptiste Daroussin post_bk(POST_ARGS) 207761d06d6bSBaptiste Daroussin { 207861d06d6bSBaptiste Daroussin struct roff_node *n; 207961d06d6bSBaptiste Daroussin 208061d06d6bSBaptiste Daroussin n = mdoc->last; 208161d06d6bSBaptiste Daroussin 208261d06d6bSBaptiste Daroussin if (n->type == ROFFT_BLOCK && n->body->child == NULL) { 20837295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_BLK_EMPTY, n->line, n->pos, "Bk"); 208461d06d6bSBaptiste Daroussin roff_node_delete(mdoc, n); 208561d06d6bSBaptiste Daroussin } 208661d06d6bSBaptiste Daroussin } 208761d06d6bSBaptiste Daroussin 208861d06d6bSBaptiste Daroussin static void 208961d06d6bSBaptiste Daroussin post_sm(POST_ARGS) 209061d06d6bSBaptiste Daroussin { 209161d06d6bSBaptiste Daroussin struct roff_node *nch; 209261d06d6bSBaptiste Daroussin 209361d06d6bSBaptiste Daroussin nch = mdoc->last->child; 209461d06d6bSBaptiste Daroussin 209561d06d6bSBaptiste Daroussin if (nch == NULL) { 209661d06d6bSBaptiste Daroussin mdoc->flags ^= MDOC_SMOFF; 209761d06d6bSBaptiste Daroussin return; 209861d06d6bSBaptiste Daroussin } 209961d06d6bSBaptiste Daroussin 210061d06d6bSBaptiste Daroussin assert(nch->type == ROFFT_TEXT); 210161d06d6bSBaptiste Daroussin 210261d06d6bSBaptiste Daroussin if ( ! strcmp(nch->string, "on")) { 210361d06d6bSBaptiste Daroussin mdoc->flags &= ~MDOC_SMOFF; 210461d06d6bSBaptiste Daroussin return; 210561d06d6bSBaptiste Daroussin } 210661d06d6bSBaptiste Daroussin if ( ! strcmp(nch->string, "off")) { 210761d06d6bSBaptiste Daroussin mdoc->flags |= MDOC_SMOFF; 210861d06d6bSBaptiste Daroussin return; 210961d06d6bSBaptiste Daroussin } 211061d06d6bSBaptiste Daroussin 21117295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_SM_BAD, nch->line, nch->pos, 211261d06d6bSBaptiste Daroussin "%s %s", roff_name[mdoc->last->tok], nch->string); 21137295610fSBaptiste Daroussin roff_node_relink(mdoc, nch); 211461d06d6bSBaptiste Daroussin return; 211561d06d6bSBaptiste Daroussin } 211661d06d6bSBaptiste Daroussin 211761d06d6bSBaptiste Daroussin static void 211861d06d6bSBaptiste Daroussin post_root(POST_ARGS) 211961d06d6bSBaptiste Daroussin { 212061d06d6bSBaptiste Daroussin struct roff_node *n; 212161d06d6bSBaptiste Daroussin 212261d06d6bSBaptiste Daroussin /* Add missing prologue data. */ 212361d06d6bSBaptiste Daroussin 212461d06d6bSBaptiste Daroussin if (mdoc->meta.date == NULL) 21256d38604fSBaptiste Daroussin mdoc->meta.date = mandoc_normdate(NULL, NULL); 212661d06d6bSBaptiste Daroussin 212761d06d6bSBaptiste Daroussin if (mdoc->meta.title == NULL) { 21287295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_DT_NOTITLE, 0, 0, "EOF"); 212961d06d6bSBaptiste Daroussin mdoc->meta.title = mandoc_strdup("UNTITLED"); 213061d06d6bSBaptiste Daroussin } 213161d06d6bSBaptiste Daroussin 213261d06d6bSBaptiste Daroussin if (mdoc->meta.vol == NULL) 213361d06d6bSBaptiste Daroussin mdoc->meta.vol = mandoc_strdup("LOCAL"); 213461d06d6bSBaptiste Daroussin 213561d06d6bSBaptiste Daroussin if (mdoc->meta.os == NULL) { 21367295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_OS_MISSING, 0, 0, NULL); 213761d06d6bSBaptiste Daroussin mdoc->meta.os = mandoc_strdup(""); 213861d06d6bSBaptiste Daroussin } else if (mdoc->meta.os_e && 213961d06d6bSBaptiste Daroussin (mdoc->meta.rcsids & (1 << mdoc->meta.os_e)) == 0) 21407295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_RCS_MISSING, 0, 0, 214161d06d6bSBaptiste Daroussin mdoc->meta.os_e == MANDOC_OS_OPENBSD ? 214261d06d6bSBaptiste Daroussin "(OpenBSD)" : "(NetBSD)"); 214361d06d6bSBaptiste Daroussin 214461d06d6bSBaptiste Daroussin if (mdoc->meta.arch != NULL && 21457295610fSBaptiste Daroussin arch_valid(mdoc->meta.arch, mdoc->meta.os_e) == 0) { 21467295610fSBaptiste Daroussin n = mdoc->meta.first->child; 214761d06d6bSBaptiste Daroussin while (n->tok != MDOC_Dt || 214861d06d6bSBaptiste Daroussin n->child == NULL || 214961d06d6bSBaptiste Daroussin n->child->next == NULL || 215061d06d6bSBaptiste Daroussin n->child->next->next == NULL) 215161d06d6bSBaptiste Daroussin n = n->next; 215261d06d6bSBaptiste Daroussin n = n->child->next->next; 21537295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_ARCH_BAD, n->line, n->pos, 215461d06d6bSBaptiste Daroussin "Dt ... %s %s", mdoc->meta.arch, 215561d06d6bSBaptiste Daroussin mdoc->meta.os_e == MANDOC_OS_OPENBSD ? 215661d06d6bSBaptiste Daroussin "(OpenBSD)" : "(NetBSD)"); 215761d06d6bSBaptiste Daroussin } 215861d06d6bSBaptiste Daroussin 215961d06d6bSBaptiste Daroussin /* Check that we begin with a proper `Sh'. */ 216061d06d6bSBaptiste Daroussin 21617295610fSBaptiste Daroussin n = mdoc->meta.first->child; 216261d06d6bSBaptiste Daroussin while (n != NULL && 216361d06d6bSBaptiste Daroussin (n->type == ROFFT_COMMENT || 216461d06d6bSBaptiste Daroussin (n->tok >= MDOC_Dd && 21657295610fSBaptiste Daroussin mdoc_macro(n->tok)->flags & MDOC_PROLOGUE))) 216661d06d6bSBaptiste Daroussin n = n->next; 216761d06d6bSBaptiste Daroussin 216861d06d6bSBaptiste Daroussin if (n == NULL) 21697295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_DOC_EMPTY, 0, 0, NULL); 217061d06d6bSBaptiste Daroussin else if (n->tok != MDOC_Sh) 21717295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_SEC_BEFORE, n->line, n->pos, 21727295610fSBaptiste Daroussin "%s", roff_name[n->tok]); 217361d06d6bSBaptiste Daroussin } 217461d06d6bSBaptiste Daroussin 217561d06d6bSBaptiste Daroussin static void 217661d06d6bSBaptiste Daroussin post_rs(POST_ARGS) 217761d06d6bSBaptiste Daroussin { 217861d06d6bSBaptiste Daroussin struct roff_node *np, *nch, *next, *prev; 217961d06d6bSBaptiste Daroussin int i, j; 218061d06d6bSBaptiste Daroussin 218161d06d6bSBaptiste Daroussin np = mdoc->last; 218261d06d6bSBaptiste Daroussin 218361d06d6bSBaptiste Daroussin if (np->type != ROFFT_BODY) 218461d06d6bSBaptiste Daroussin return; 218561d06d6bSBaptiste Daroussin 218661d06d6bSBaptiste Daroussin if (np->child == NULL) { 21877295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_RS_EMPTY, np->line, np->pos, "Rs"); 218861d06d6bSBaptiste Daroussin return; 218961d06d6bSBaptiste Daroussin } 219061d06d6bSBaptiste Daroussin 219161d06d6bSBaptiste Daroussin /* 219261d06d6bSBaptiste Daroussin * The full `Rs' block needs special handling to order the 219361d06d6bSBaptiste Daroussin * sub-elements according to `rsord'. Pick through each element 219461d06d6bSBaptiste Daroussin * and correctly order it. This is an insertion sort. 219561d06d6bSBaptiste Daroussin */ 219661d06d6bSBaptiste Daroussin 219761d06d6bSBaptiste Daroussin next = NULL; 219861d06d6bSBaptiste Daroussin for (nch = np->child->next; nch != NULL; nch = next) { 219961d06d6bSBaptiste Daroussin /* Determine order number of this child. */ 220061d06d6bSBaptiste Daroussin for (i = 0; i < RSORD_MAX; i++) 220161d06d6bSBaptiste Daroussin if (rsord[i] == nch->tok) 220261d06d6bSBaptiste Daroussin break; 220361d06d6bSBaptiste Daroussin 220461d06d6bSBaptiste Daroussin if (i == RSORD_MAX) { 22057295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_RS_BAD, nch->line, nch->pos, 22067295610fSBaptiste Daroussin "%s", roff_name[nch->tok]); 220761d06d6bSBaptiste Daroussin i = -1; 220861d06d6bSBaptiste Daroussin } else if (nch->tok == MDOC__J || nch->tok == MDOC__B) 220961d06d6bSBaptiste Daroussin np->norm->Rs.quote_T++; 221061d06d6bSBaptiste Daroussin 221161d06d6bSBaptiste Daroussin /* 221261d06d6bSBaptiste Daroussin * Remove this child from the chain. This somewhat 221361d06d6bSBaptiste Daroussin * repeats roff_node_unlink(), but since we're 221461d06d6bSBaptiste Daroussin * just re-ordering, there's no need for the 221561d06d6bSBaptiste Daroussin * full unlink process. 221661d06d6bSBaptiste Daroussin */ 221761d06d6bSBaptiste Daroussin 221861d06d6bSBaptiste Daroussin if ((next = nch->next) != NULL) 221961d06d6bSBaptiste Daroussin next->prev = nch->prev; 222061d06d6bSBaptiste Daroussin 222161d06d6bSBaptiste Daroussin if ((prev = nch->prev) != NULL) 222261d06d6bSBaptiste Daroussin prev->next = nch->next; 222361d06d6bSBaptiste Daroussin 222461d06d6bSBaptiste Daroussin nch->prev = nch->next = NULL; 222561d06d6bSBaptiste Daroussin 222661d06d6bSBaptiste Daroussin /* 222761d06d6bSBaptiste Daroussin * Scan back until we reach a node that's 222861d06d6bSBaptiste Daroussin * to be ordered before this child. 222961d06d6bSBaptiste Daroussin */ 223061d06d6bSBaptiste Daroussin 223161d06d6bSBaptiste Daroussin for ( ; prev ; prev = prev->prev) { 223261d06d6bSBaptiste Daroussin /* Determine order of `prev'. */ 223361d06d6bSBaptiste Daroussin for (j = 0; j < RSORD_MAX; j++) 223461d06d6bSBaptiste Daroussin if (rsord[j] == prev->tok) 223561d06d6bSBaptiste Daroussin break; 223661d06d6bSBaptiste Daroussin if (j == RSORD_MAX) 223761d06d6bSBaptiste Daroussin j = -1; 223861d06d6bSBaptiste Daroussin 223961d06d6bSBaptiste Daroussin if (j <= i) 224061d06d6bSBaptiste Daroussin break; 224161d06d6bSBaptiste Daroussin } 224261d06d6bSBaptiste Daroussin 224361d06d6bSBaptiste Daroussin /* 224461d06d6bSBaptiste Daroussin * Set this child back into its correct place 224561d06d6bSBaptiste Daroussin * in front of the `prev' node. 224661d06d6bSBaptiste Daroussin */ 224761d06d6bSBaptiste Daroussin 224861d06d6bSBaptiste Daroussin nch->prev = prev; 224961d06d6bSBaptiste Daroussin 225061d06d6bSBaptiste Daroussin if (prev == NULL) { 225161d06d6bSBaptiste Daroussin np->child->prev = nch; 225261d06d6bSBaptiste Daroussin nch->next = np->child; 225361d06d6bSBaptiste Daroussin np->child = nch; 225461d06d6bSBaptiste Daroussin } else { 225561d06d6bSBaptiste Daroussin if (prev->next) 225661d06d6bSBaptiste Daroussin prev->next->prev = nch; 225761d06d6bSBaptiste Daroussin nch->next = prev->next; 225861d06d6bSBaptiste Daroussin prev->next = nch; 225961d06d6bSBaptiste Daroussin } 226061d06d6bSBaptiste Daroussin } 226161d06d6bSBaptiste Daroussin } 226261d06d6bSBaptiste Daroussin 226361d06d6bSBaptiste Daroussin /* 226461d06d6bSBaptiste Daroussin * For some arguments of some macros, 226561d06d6bSBaptiste Daroussin * convert all breakable hyphens into ASCII_HYPH. 226661d06d6bSBaptiste Daroussin */ 226761d06d6bSBaptiste Daroussin static void 226861d06d6bSBaptiste Daroussin post_hyph(POST_ARGS) 226961d06d6bSBaptiste Daroussin { 22706d38604fSBaptiste Daroussin struct roff_node *n, *nch; 227161d06d6bSBaptiste Daroussin char *cp; 227261d06d6bSBaptiste Daroussin 22736d38604fSBaptiste Daroussin n = mdoc->last; 22746d38604fSBaptiste Daroussin for (nch = n->child; nch != NULL; nch = nch->next) { 227561d06d6bSBaptiste Daroussin if (nch->type != ROFFT_TEXT) 227661d06d6bSBaptiste Daroussin continue; 227761d06d6bSBaptiste Daroussin cp = nch->string; 227861d06d6bSBaptiste Daroussin if (*cp == '\0') 227961d06d6bSBaptiste Daroussin continue; 228061d06d6bSBaptiste Daroussin while (*(++cp) != '\0') 228161d06d6bSBaptiste Daroussin if (*cp == '-' && 228261d06d6bSBaptiste Daroussin isalpha((unsigned char)cp[-1]) && 22836d38604fSBaptiste Daroussin isalpha((unsigned char)cp[1])) { 22846d38604fSBaptiste Daroussin if (n->tag == NULL && n->flags & NODE_ID) 22856d38604fSBaptiste Daroussin n->tag = mandoc_strdup(nch->string); 228661d06d6bSBaptiste Daroussin *cp = ASCII_HYPH; 228761d06d6bSBaptiste Daroussin } 228861d06d6bSBaptiste Daroussin } 22896d38604fSBaptiste Daroussin } 229061d06d6bSBaptiste Daroussin 229161d06d6bSBaptiste Daroussin static void 229261d06d6bSBaptiste Daroussin post_ns(POST_ARGS) 229361d06d6bSBaptiste Daroussin { 229461d06d6bSBaptiste Daroussin struct roff_node *n; 229561d06d6bSBaptiste Daroussin 229661d06d6bSBaptiste Daroussin n = mdoc->last; 229761d06d6bSBaptiste Daroussin if (n->flags & NODE_LINE || 229861d06d6bSBaptiste Daroussin (n->next != NULL && n->next->flags & NODE_DELIMC)) 22997295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_NS_SKIP, n->line, n->pos, NULL); 230061d06d6bSBaptiste Daroussin } 230161d06d6bSBaptiste Daroussin 230261d06d6bSBaptiste Daroussin static void 230361d06d6bSBaptiste Daroussin post_sx(POST_ARGS) 230461d06d6bSBaptiste Daroussin { 230561d06d6bSBaptiste Daroussin post_delim(mdoc); 230661d06d6bSBaptiste Daroussin post_hyph(mdoc); 230761d06d6bSBaptiste Daroussin } 230861d06d6bSBaptiste Daroussin 230961d06d6bSBaptiste Daroussin static void 231061d06d6bSBaptiste Daroussin post_sh(POST_ARGS) 231161d06d6bSBaptiste Daroussin { 23126d38604fSBaptiste Daroussin post_section(mdoc); 231361d06d6bSBaptiste Daroussin 231461d06d6bSBaptiste Daroussin switch (mdoc->last->type) { 231561d06d6bSBaptiste Daroussin case ROFFT_HEAD: 231661d06d6bSBaptiste Daroussin post_sh_head(mdoc); 231761d06d6bSBaptiste Daroussin break; 231861d06d6bSBaptiste Daroussin case ROFFT_BODY: 231961d06d6bSBaptiste Daroussin switch (mdoc->lastsec) { 232061d06d6bSBaptiste Daroussin case SEC_NAME: 232161d06d6bSBaptiste Daroussin post_sh_name(mdoc); 232261d06d6bSBaptiste Daroussin break; 232361d06d6bSBaptiste Daroussin case SEC_SEE_ALSO: 232461d06d6bSBaptiste Daroussin post_sh_see_also(mdoc); 232561d06d6bSBaptiste Daroussin break; 232661d06d6bSBaptiste Daroussin case SEC_AUTHORS: 232761d06d6bSBaptiste Daroussin post_sh_authors(mdoc); 232861d06d6bSBaptiste Daroussin break; 232961d06d6bSBaptiste Daroussin default: 233061d06d6bSBaptiste Daroussin break; 233161d06d6bSBaptiste Daroussin } 233261d06d6bSBaptiste Daroussin break; 233361d06d6bSBaptiste Daroussin default: 233461d06d6bSBaptiste Daroussin break; 233561d06d6bSBaptiste Daroussin } 233661d06d6bSBaptiste Daroussin } 233761d06d6bSBaptiste Daroussin 233861d06d6bSBaptiste Daroussin static void 233961d06d6bSBaptiste Daroussin post_sh_name(POST_ARGS) 234061d06d6bSBaptiste Daroussin { 234161d06d6bSBaptiste Daroussin struct roff_node *n; 234261d06d6bSBaptiste Daroussin int hasnm, hasnd; 234361d06d6bSBaptiste Daroussin 234461d06d6bSBaptiste Daroussin hasnm = hasnd = 0; 234561d06d6bSBaptiste Daroussin 234661d06d6bSBaptiste Daroussin for (n = mdoc->last->child; n != NULL; n = n->next) { 234761d06d6bSBaptiste Daroussin switch (n->tok) { 234861d06d6bSBaptiste Daroussin case MDOC_Nm: 234961d06d6bSBaptiste Daroussin if (hasnm && n->child != NULL) 23507295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_NAMESEC_PUNCT, 23517295610fSBaptiste Daroussin n->line, n->pos, 235261d06d6bSBaptiste Daroussin "Nm %s", n->child->string); 235361d06d6bSBaptiste Daroussin hasnm = 1; 235461d06d6bSBaptiste Daroussin continue; 235561d06d6bSBaptiste Daroussin case MDOC_Nd: 235661d06d6bSBaptiste Daroussin hasnd = 1; 235761d06d6bSBaptiste Daroussin if (n->next != NULL) 235861d06d6bSBaptiste Daroussin mandoc_msg(MANDOCERR_NAMESEC_ND, 23597295610fSBaptiste Daroussin n->line, n->pos, NULL); 236061d06d6bSBaptiste Daroussin break; 236161d06d6bSBaptiste Daroussin case TOKEN_NONE: 236261d06d6bSBaptiste Daroussin if (n->type == ROFFT_TEXT && 236361d06d6bSBaptiste Daroussin n->string[0] == ',' && n->string[1] == '\0' && 236461d06d6bSBaptiste Daroussin n->next != NULL && n->next->tok == MDOC_Nm) { 236561d06d6bSBaptiste Daroussin n = n->next; 236661d06d6bSBaptiste Daroussin continue; 236761d06d6bSBaptiste Daroussin } 236861d06d6bSBaptiste Daroussin /* FALLTHROUGH */ 236961d06d6bSBaptiste Daroussin default: 23707295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_NAMESEC_BAD, 23717295610fSBaptiste Daroussin n->line, n->pos, "%s", roff_name[n->tok]); 237261d06d6bSBaptiste Daroussin continue; 237361d06d6bSBaptiste Daroussin } 237461d06d6bSBaptiste Daroussin break; 237561d06d6bSBaptiste Daroussin } 237661d06d6bSBaptiste Daroussin 237761d06d6bSBaptiste Daroussin if ( ! hasnm) 23787295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_NAMESEC_NONM, 237961d06d6bSBaptiste Daroussin mdoc->last->line, mdoc->last->pos, NULL); 238061d06d6bSBaptiste Daroussin if ( ! hasnd) 23817295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_NAMESEC_NOND, 238261d06d6bSBaptiste Daroussin mdoc->last->line, mdoc->last->pos, NULL); 238361d06d6bSBaptiste Daroussin } 238461d06d6bSBaptiste Daroussin 238561d06d6bSBaptiste Daroussin static void 238661d06d6bSBaptiste Daroussin post_sh_see_also(POST_ARGS) 238761d06d6bSBaptiste Daroussin { 238861d06d6bSBaptiste Daroussin const struct roff_node *n; 238961d06d6bSBaptiste Daroussin const char *name, *sec; 239061d06d6bSBaptiste Daroussin const char *lastname, *lastsec, *lastpunct; 239161d06d6bSBaptiste Daroussin int cmp; 239261d06d6bSBaptiste Daroussin 239361d06d6bSBaptiste Daroussin n = mdoc->last->child; 239461d06d6bSBaptiste Daroussin lastname = lastsec = lastpunct = NULL; 239561d06d6bSBaptiste Daroussin while (n != NULL) { 239661d06d6bSBaptiste Daroussin if (n->tok != MDOC_Xr || 239761d06d6bSBaptiste Daroussin n->child == NULL || 239861d06d6bSBaptiste Daroussin n->child->next == NULL) 239961d06d6bSBaptiste Daroussin break; 240061d06d6bSBaptiste Daroussin 240161d06d6bSBaptiste Daroussin /* Process one .Xr node. */ 240261d06d6bSBaptiste Daroussin 240361d06d6bSBaptiste Daroussin name = n->child->string; 240461d06d6bSBaptiste Daroussin sec = n->child->next->string; 240561d06d6bSBaptiste Daroussin if (lastsec != NULL) { 240661d06d6bSBaptiste Daroussin if (lastpunct[0] != ',' || lastpunct[1] != '\0') 24077295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_XR_PUNCT, n->line, 24087295610fSBaptiste Daroussin n->pos, "%s before %s(%s)", 24097295610fSBaptiste Daroussin lastpunct, name, sec); 241061d06d6bSBaptiste Daroussin cmp = strcmp(lastsec, sec); 241161d06d6bSBaptiste Daroussin if (cmp > 0) 24127295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_XR_ORDER, n->line, 24137295610fSBaptiste Daroussin n->pos, "%s(%s) after %s(%s)", 24147295610fSBaptiste Daroussin name, sec, lastname, lastsec); 241561d06d6bSBaptiste Daroussin else if (cmp == 0 && 241661d06d6bSBaptiste Daroussin strcasecmp(lastname, name) > 0) 24177295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_XR_ORDER, n->line, 24187295610fSBaptiste Daroussin n->pos, "%s after %s", name, lastname); 241961d06d6bSBaptiste Daroussin } 242061d06d6bSBaptiste Daroussin lastname = name; 242161d06d6bSBaptiste Daroussin lastsec = sec; 242261d06d6bSBaptiste Daroussin 242361d06d6bSBaptiste Daroussin /* Process the following node. */ 242461d06d6bSBaptiste Daroussin 242561d06d6bSBaptiste Daroussin n = n->next; 242661d06d6bSBaptiste Daroussin if (n == NULL) 242761d06d6bSBaptiste Daroussin break; 242861d06d6bSBaptiste Daroussin if (n->tok == MDOC_Xr) { 242961d06d6bSBaptiste Daroussin lastpunct = "none"; 243061d06d6bSBaptiste Daroussin continue; 243161d06d6bSBaptiste Daroussin } 243261d06d6bSBaptiste Daroussin if (n->type != ROFFT_TEXT) 243361d06d6bSBaptiste Daroussin break; 243461d06d6bSBaptiste Daroussin for (name = n->string; *name != '\0'; name++) 243561d06d6bSBaptiste Daroussin if (isalpha((const unsigned char)*name)) 243661d06d6bSBaptiste Daroussin return; 243761d06d6bSBaptiste Daroussin lastpunct = n->string; 243861d06d6bSBaptiste Daroussin if (n->next == NULL || n->next->tok == MDOC_Rs) 24397295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_XR_PUNCT, n->line, 24407295610fSBaptiste Daroussin n->pos, "%s after %s(%s)", 244161d06d6bSBaptiste Daroussin lastpunct, lastname, lastsec); 244261d06d6bSBaptiste Daroussin n = n->next; 244361d06d6bSBaptiste Daroussin } 244461d06d6bSBaptiste Daroussin } 244561d06d6bSBaptiste Daroussin 244661d06d6bSBaptiste Daroussin static int 244761d06d6bSBaptiste Daroussin child_an(const struct roff_node *n) 244861d06d6bSBaptiste Daroussin { 244961d06d6bSBaptiste Daroussin 245061d06d6bSBaptiste Daroussin for (n = n->child; n != NULL; n = n->next) 245161d06d6bSBaptiste Daroussin if ((n->tok == MDOC_An && n->child != NULL) || child_an(n)) 245261d06d6bSBaptiste Daroussin return 1; 245361d06d6bSBaptiste Daroussin return 0; 245461d06d6bSBaptiste Daroussin } 245561d06d6bSBaptiste Daroussin 245661d06d6bSBaptiste Daroussin static void 245761d06d6bSBaptiste Daroussin post_sh_authors(POST_ARGS) 245861d06d6bSBaptiste Daroussin { 245961d06d6bSBaptiste Daroussin 246061d06d6bSBaptiste Daroussin if ( ! child_an(mdoc->last)) 24617295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_AN_MISSING, 246261d06d6bSBaptiste Daroussin mdoc->last->line, mdoc->last->pos, NULL); 246361d06d6bSBaptiste Daroussin } 246461d06d6bSBaptiste Daroussin 246561d06d6bSBaptiste Daroussin /* 246661d06d6bSBaptiste Daroussin * Return an upper bound for the string distance (allowing 246761d06d6bSBaptiste Daroussin * transpositions). Not a full Levenshtein implementation 246861d06d6bSBaptiste Daroussin * because Levenshtein is quadratic in the string length 246961d06d6bSBaptiste Daroussin * and this function is called for every standard name, 247061d06d6bSBaptiste Daroussin * so the check for each custom name would be cubic. 247161d06d6bSBaptiste Daroussin * The following crude heuristics is linear, resulting 247261d06d6bSBaptiste Daroussin * in quadratic behaviour for checking one custom name, 247361d06d6bSBaptiste Daroussin * which does not cause measurable slowdown. 247461d06d6bSBaptiste Daroussin */ 247561d06d6bSBaptiste Daroussin static int 247661d06d6bSBaptiste Daroussin similar(const char *s1, const char *s2) 247761d06d6bSBaptiste Daroussin { 247861d06d6bSBaptiste Daroussin const int maxdist = 3; 247961d06d6bSBaptiste Daroussin int dist = 0; 248061d06d6bSBaptiste Daroussin 248161d06d6bSBaptiste Daroussin while (s1[0] != '\0' && s2[0] != '\0') { 248261d06d6bSBaptiste Daroussin if (s1[0] == s2[0]) { 248361d06d6bSBaptiste Daroussin s1++; 248461d06d6bSBaptiste Daroussin s2++; 248561d06d6bSBaptiste Daroussin continue; 248661d06d6bSBaptiste Daroussin } 248761d06d6bSBaptiste Daroussin if (++dist > maxdist) 248861d06d6bSBaptiste Daroussin return INT_MAX; 248961d06d6bSBaptiste Daroussin if (s1[1] == s2[1]) { /* replacement */ 249061d06d6bSBaptiste Daroussin s1++; 249161d06d6bSBaptiste Daroussin s2++; 249261d06d6bSBaptiste Daroussin } else if (s1[0] == s2[1] && s1[1] == s2[0]) { 249361d06d6bSBaptiste Daroussin s1 += 2; /* transposition */ 249461d06d6bSBaptiste Daroussin s2 += 2; 249561d06d6bSBaptiste Daroussin } else if (s1[0] == s2[1]) /* insertion */ 249661d06d6bSBaptiste Daroussin s2++; 249761d06d6bSBaptiste Daroussin else if (s1[1] == s2[0]) /* deletion */ 249861d06d6bSBaptiste Daroussin s1++; 249961d06d6bSBaptiste Daroussin else 250061d06d6bSBaptiste Daroussin return INT_MAX; 250161d06d6bSBaptiste Daroussin } 250261d06d6bSBaptiste Daroussin dist += strlen(s1) + strlen(s2); 250361d06d6bSBaptiste Daroussin return dist > maxdist ? INT_MAX : dist; 250461d06d6bSBaptiste Daroussin } 250561d06d6bSBaptiste Daroussin 250661d06d6bSBaptiste Daroussin static void 250761d06d6bSBaptiste Daroussin post_sh_head(POST_ARGS) 250861d06d6bSBaptiste Daroussin { 250961d06d6bSBaptiste Daroussin struct roff_node *nch; 251061d06d6bSBaptiste Daroussin const char *goodsec; 251161d06d6bSBaptiste Daroussin const char *const *testsec; 251261d06d6bSBaptiste Daroussin int dist, mindist; 251361d06d6bSBaptiste Daroussin enum roff_sec sec; 251461d06d6bSBaptiste Daroussin 251561d06d6bSBaptiste Daroussin /* 251661d06d6bSBaptiste Daroussin * Process a new section. Sections are either "named" or 251761d06d6bSBaptiste Daroussin * "custom". Custom sections are user-defined, while named ones 251861d06d6bSBaptiste Daroussin * follow a conventional order and may only appear in certain 251961d06d6bSBaptiste Daroussin * manual sections. 252061d06d6bSBaptiste Daroussin */ 252161d06d6bSBaptiste Daroussin 252261d06d6bSBaptiste Daroussin sec = mdoc->last->sec; 252361d06d6bSBaptiste Daroussin 252461d06d6bSBaptiste Daroussin /* The NAME should be first. */ 252561d06d6bSBaptiste Daroussin 252661d06d6bSBaptiste Daroussin if (sec != SEC_NAME && mdoc->lastnamed == SEC_NONE) 25277295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_NAMESEC_FIRST, 252861d06d6bSBaptiste Daroussin mdoc->last->line, mdoc->last->pos, "Sh %s", 252961d06d6bSBaptiste Daroussin sec != SEC_CUSTOM ? secnames[sec] : 253061d06d6bSBaptiste Daroussin (nch = mdoc->last->child) == NULL ? "" : 253161d06d6bSBaptiste Daroussin nch->type == ROFFT_TEXT ? nch->string : 253261d06d6bSBaptiste Daroussin roff_name[nch->tok]); 253361d06d6bSBaptiste Daroussin 253461d06d6bSBaptiste Daroussin /* The SYNOPSIS gets special attention in other areas. */ 253561d06d6bSBaptiste Daroussin 253661d06d6bSBaptiste Daroussin if (sec == SEC_SYNOPSIS) { 253761d06d6bSBaptiste Daroussin roff_setreg(mdoc->roff, "nS", 1, '='); 253861d06d6bSBaptiste Daroussin mdoc->flags |= MDOC_SYNOPSIS; 253961d06d6bSBaptiste Daroussin } else { 254061d06d6bSBaptiste Daroussin roff_setreg(mdoc->roff, "nS", 0, '='); 254161d06d6bSBaptiste Daroussin mdoc->flags &= ~MDOC_SYNOPSIS; 254261d06d6bSBaptiste Daroussin } 25436d38604fSBaptiste Daroussin if (sec == SEC_DESCRIPTION) 25446d38604fSBaptiste Daroussin fn_prio = TAG_STRONG; 254561d06d6bSBaptiste Daroussin 254661d06d6bSBaptiste Daroussin /* Mark our last section. */ 254761d06d6bSBaptiste Daroussin 254861d06d6bSBaptiste Daroussin mdoc->lastsec = sec; 254961d06d6bSBaptiste Daroussin 255061d06d6bSBaptiste Daroussin /* We don't care about custom sections after this. */ 255161d06d6bSBaptiste Daroussin 255261d06d6bSBaptiste Daroussin if (sec == SEC_CUSTOM) { 255361d06d6bSBaptiste Daroussin if ((nch = mdoc->last->child) == NULL || 255461d06d6bSBaptiste Daroussin nch->type != ROFFT_TEXT || nch->next != NULL) 255561d06d6bSBaptiste Daroussin return; 255661d06d6bSBaptiste Daroussin goodsec = NULL; 255761d06d6bSBaptiste Daroussin mindist = INT_MAX; 255861d06d6bSBaptiste Daroussin for (testsec = secnames + 1; *testsec != NULL; testsec++) { 255961d06d6bSBaptiste Daroussin dist = similar(nch->string, *testsec); 256061d06d6bSBaptiste Daroussin if (dist < mindist) { 256161d06d6bSBaptiste Daroussin goodsec = *testsec; 256261d06d6bSBaptiste Daroussin mindist = dist; 256361d06d6bSBaptiste Daroussin } 256461d06d6bSBaptiste Daroussin } 256561d06d6bSBaptiste Daroussin if (goodsec != NULL) 25667295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_SEC_TYPO, nch->line, nch->pos, 25677295610fSBaptiste Daroussin "Sh %s instead of %s", nch->string, goodsec); 256861d06d6bSBaptiste Daroussin return; 256961d06d6bSBaptiste Daroussin } 257061d06d6bSBaptiste Daroussin 257161d06d6bSBaptiste Daroussin /* 257261d06d6bSBaptiste Daroussin * Check whether our non-custom section is being repeated or is 257361d06d6bSBaptiste Daroussin * out of order. 257461d06d6bSBaptiste Daroussin */ 257561d06d6bSBaptiste Daroussin 257661d06d6bSBaptiste Daroussin if (sec == mdoc->lastnamed) 25777295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_SEC_REP, mdoc->last->line, 25787295610fSBaptiste Daroussin mdoc->last->pos, "Sh %s", secnames[sec]); 257961d06d6bSBaptiste Daroussin 258061d06d6bSBaptiste Daroussin if (sec < mdoc->lastnamed) 25817295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_SEC_ORDER, mdoc->last->line, 25827295610fSBaptiste Daroussin mdoc->last->pos, "Sh %s", secnames[sec]); 258361d06d6bSBaptiste Daroussin 258461d06d6bSBaptiste Daroussin /* Mark the last named section. */ 258561d06d6bSBaptiste Daroussin 258661d06d6bSBaptiste Daroussin mdoc->lastnamed = sec; 258761d06d6bSBaptiste Daroussin 258861d06d6bSBaptiste Daroussin /* Check particular section/manual conventions. */ 258961d06d6bSBaptiste Daroussin 259061d06d6bSBaptiste Daroussin if (mdoc->meta.msec == NULL) 259161d06d6bSBaptiste Daroussin return; 259261d06d6bSBaptiste Daroussin 259361d06d6bSBaptiste Daroussin goodsec = NULL; 259461d06d6bSBaptiste Daroussin switch (sec) { 259561d06d6bSBaptiste Daroussin case SEC_ERRORS: 259661d06d6bSBaptiste Daroussin if (*mdoc->meta.msec == '4') 259761d06d6bSBaptiste Daroussin break; 259861d06d6bSBaptiste Daroussin goodsec = "2, 3, 4, 9"; 259961d06d6bSBaptiste Daroussin /* FALLTHROUGH */ 260061d06d6bSBaptiste Daroussin case SEC_RETURN_VALUES: 260161d06d6bSBaptiste Daroussin case SEC_LIBRARY: 260261d06d6bSBaptiste Daroussin if (*mdoc->meta.msec == '2') 260361d06d6bSBaptiste Daroussin break; 260461d06d6bSBaptiste Daroussin if (*mdoc->meta.msec == '3') 260561d06d6bSBaptiste Daroussin break; 260661d06d6bSBaptiste Daroussin if (NULL == goodsec) 260761d06d6bSBaptiste Daroussin goodsec = "2, 3, 9"; 260861d06d6bSBaptiste Daroussin /* FALLTHROUGH */ 260961d06d6bSBaptiste Daroussin case SEC_CONTEXT: 261061d06d6bSBaptiste Daroussin if (*mdoc->meta.msec == '9') 261161d06d6bSBaptiste Daroussin break; 261261d06d6bSBaptiste Daroussin if (NULL == goodsec) 261361d06d6bSBaptiste Daroussin goodsec = "9"; 26147295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_SEC_MSEC, 261561d06d6bSBaptiste Daroussin mdoc->last->line, mdoc->last->pos, 261661d06d6bSBaptiste Daroussin "Sh %s for %s only", secnames[sec], goodsec); 261761d06d6bSBaptiste Daroussin break; 261861d06d6bSBaptiste Daroussin default: 261961d06d6bSBaptiste Daroussin break; 262061d06d6bSBaptiste Daroussin } 262161d06d6bSBaptiste Daroussin } 262261d06d6bSBaptiste Daroussin 262361d06d6bSBaptiste Daroussin static void 262461d06d6bSBaptiste Daroussin post_xr(POST_ARGS) 262561d06d6bSBaptiste Daroussin { 262661d06d6bSBaptiste Daroussin struct roff_node *n, *nch; 262761d06d6bSBaptiste Daroussin 262861d06d6bSBaptiste Daroussin n = mdoc->last; 262961d06d6bSBaptiste Daroussin nch = n->child; 263061d06d6bSBaptiste Daroussin if (nch->next == NULL) { 26317295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_XR_NOSEC, 263261d06d6bSBaptiste Daroussin n->line, n->pos, "Xr %s", nch->string); 263361d06d6bSBaptiste Daroussin } else { 263461d06d6bSBaptiste Daroussin assert(nch->next == n->last); 263561d06d6bSBaptiste Daroussin if(mandoc_xr_add(nch->next->string, nch->string, 263661d06d6bSBaptiste Daroussin nch->line, nch->pos)) 26377295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_XR_SELF, 263861d06d6bSBaptiste Daroussin nch->line, nch->pos, "Xr %s %s", 263961d06d6bSBaptiste Daroussin nch->string, nch->next->string); 264061d06d6bSBaptiste Daroussin } 264161d06d6bSBaptiste Daroussin post_delim_nb(mdoc); 264261d06d6bSBaptiste Daroussin } 264361d06d6bSBaptiste Daroussin 264461d06d6bSBaptiste Daroussin static void 26456d38604fSBaptiste Daroussin post_section(POST_ARGS) 264661d06d6bSBaptiste Daroussin { 26476d38604fSBaptiste Daroussin struct roff_node *n, *nch; 26486d38604fSBaptiste Daroussin char *cp, *tag; 264961d06d6bSBaptiste Daroussin 26506d38604fSBaptiste Daroussin n = mdoc->last; 26516d38604fSBaptiste Daroussin switch (n->type) { 265261d06d6bSBaptiste Daroussin case ROFFT_BLOCK: 265361d06d6bSBaptiste Daroussin post_prevpar(mdoc); 265461d06d6bSBaptiste Daroussin return; 265561d06d6bSBaptiste Daroussin case ROFFT_HEAD: 26566d38604fSBaptiste Daroussin tag = NULL; 26576d38604fSBaptiste Daroussin deroff(&tag, n); 26586d38604fSBaptiste Daroussin if (tag != NULL) { 26596d38604fSBaptiste Daroussin for (cp = tag; *cp != '\0'; cp++) 26606d38604fSBaptiste Daroussin if (*cp == ' ') 26616d38604fSBaptiste Daroussin *cp = '_'; 26626d38604fSBaptiste Daroussin if ((nch = n->child) != NULL && 26636d38604fSBaptiste Daroussin nch->type == ROFFT_TEXT && 26646d38604fSBaptiste Daroussin strcmp(nch->string, tag) == 0) 26656d38604fSBaptiste Daroussin tag_put(NULL, TAG_STRONG, n); 26666d38604fSBaptiste Daroussin else 26676d38604fSBaptiste Daroussin tag_put(tag, TAG_FALLBACK, n); 26686d38604fSBaptiste Daroussin free(tag); 26696d38604fSBaptiste Daroussin } 267061d06d6bSBaptiste Daroussin post_delim(mdoc); 267161d06d6bSBaptiste Daroussin post_hyph(mdoc); 267261d06d6bSBaptiste Daroussin return; 267361d06d6bSBaptiste Daroussin case ROFFT_BODY: 267461d06d6bSBaptiste Daroussin break; 267561d06d6bSBaptiste Daroussin default: 267661d06d6bSBaptiste Daroussin return; 267761d06d6bSBaptiste Daroussin } 26786d38604fSBaptiste Daroussin if ((nch = n->child) != NULL && 26796d38604fSBaptiste Daroussin (nch->tok == MDOC_Pp || nch->tok == ROFF_br || 26806d38604fSBaptiste Daroussin nch->tok == ROFF_sp)) { 26816d38604fSBaptiste Daroussin mandoc_msg(MANDOCERR_PAR_SKIP, nch->line, nch->pos, 26826d38604fSBaptiste Daroussin "%s after %s", roff_name[nch->tok], 26836d38604fSBaptiste Daroussin roff_name[n->tok]); 26846d38604fSBaptiste Daroussin roff_node_delete(mdoc, nch); 268561d06d6bSBaptiste Daroussin } 26866d38604fSBaptiste Daroussin if ((nch = n->last) != NULL && 26876d38604fSBaptiste Daroussin (nch->tok == MDOC_Pp || nch->tok == ROFF_br)) { 26886d38604fSBaptiste Daroussin mandoc_msg(MANDOCERR_PAR_SKIP, nch->line, nch->pos, 26896d38604fSBaptiste Daroussin "%s at the end of %s", roff_name[nch->tok], 26906d38604fSBaptiste Daroussin roff_name[n->tok]); 26916d38604fSBaptiste Daroussin roff_node_delete(mdoc, nch); 269261d06d6bSBaptiste Daroussin } 269361d06d6bSBaptiste Daroussin } 269461d06d6bSBaptiste Daroussin 269561d06d6bSBaptiste Daroussin static void 269661d06d6bSBaptiste Daroussin post_prevpar(POST_ARGS) 269761d06d6bSBaptiste Daroussin { 26986d38604fSBaptiste Daroussin struct roff_node *n, *np; 269961d06d6bSBaptiste Daroussin 270061d06d6bSBaptiste Daroussin n = mdoc->last; 270161d06d6bSBaptiste Daroussin if (n->type != ROFFT_ELEM && n->type != ROFFT_BLOCK) 270261d06d6bSBaptiste Daroussin return; 27036d38604fSBaptiste Daroussin if ((np = roff_node_prev(n)) == NULL) 27046d38604fSBaptiste Daroussin return; 270561d06d6bSBaptiste Daroussin 270661d06d6bSBaptiste Daroussin /* 27077295610fSBaptiste Daroussin * Don't allow `Pp' prior to a paragraph-type 27087295610fSBaptiste Daroussin * block: `Pp' or non-compact `Bd' or `Bl'. 270961d06d6bSBaptiste Daroussin */ 271061d06d6bSBaptiste Daroussin 27116d38604fSBaptiste Daroussin if (np->tok != MDOC_Pp && np->tok != ROFF_br) 271261d06d6bSBaptiste Daroussin return; 271361d06d6bSBaptiste Daroussin if (n->tok == MDOC_Bl && n->norm->Bl.comp) 271461d06d6bSBaptiste Daroussin return; 271561d06d6bSBaptiste Daroussin if (n->tok == MDOC_Bd && n->norm->Bd.comp) 271661d06d6bSBaptiste Daroussin return; 271761d06d6bSBaptiste Daroussin if (n->tok == MDOC_It && n->parent->norm->Bl.comp) 271861d06d6bSBaptiste Daroussin return; 271961d06d6bSBaptiste Daroussin 27206d38604fSBaptiste Daroussin mandoc_msg(MANDOCERR_PAR_SKIP, np->line, np->pos, 27216d38604fSBaptiste Daroussin "%s before %s", roff_name[np->tok], roff_name[n->tok]); 27226d38604fSBaptiste Daroussin roff_node_delete(mdoc, np); 272361d06d6bSBaptiste Daroussin } 272461d06d6bSBaptiste Daroussin 272561d06d6bSBaptiste Daroussin static void 272661d06d6bSBaptiste Daroussin post_par(POST_ARGS) 272761d06d6bSBaptiste Daroussin { 272861d06d6bSBaptiste Daroussin struct roff_node *np; 272961d06d6bSBaptiste Daroussin 27306d38604fSBaptiste Daroussin fn_prio = TAG_STRONG; 273161d06d6bSBaptiste Daroussin post_prevpar(mdoc); 273261d06d6bSBaptiste Daroussin 27337295610fSBaptiste Daroussin np = mdoc->last; 27347295610fSBaptiste Daroussin if (np->child != NULL) 27357295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_ARG_SKIP, np->line, np->pos, 27367295610fSBaptiste Daroussin "%s %s", roff_name[np->tok], np->child->string); 273761d06d6bSBaptiste Daroussin } 273861d06d6bSBaptiste Daroussin 273961d06d6bSBaptiste Daroussin static void 274061d06d6bSBaptiste Daroussin post_dd(POST_ARGS) 274161d06d6bSBaptiste Daroussin { 274261d06d6bSBaptiste Daroussin struct roff_node *n; 274361d06d6bSBaptiste Daroussin 274461d06d6bSBaptiste Daroussin n = mdoc->last; 274561d06d6bSBaptiste Daroussin n->flags |= NODE_NOPRT; 274661d06d6bSBaptiste Daroussin 274761d06d6bSBaptiste Daroussin if (mdoc->meta.date != NULL) { 27487295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_PROLOG_REP, n->line, n->pos, "Dd"); 274961d06d6bSBaptiste Daroussin free(mdoc->meta.date); 275061d06d6bSBaptiste Daroussin } else if (mdoc->flags & MDOC_PBODY) 27517295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_PROLOG_LATE, n->line, n->pos, "Dd"); 275261d06d6bSBaptiste Daroussin else if (mdoc->meta.title != NULL) 27537295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_PROLOG_ORDER, 275461d06d6bSBaptiste Daroussin n->line, n->pos, "Dd after Dt"); 275561d06d6bSBaptiste Daroussin else if (mdoc->meta.os != NULL) 27567295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_PROLOG_ORDER, 275761d06d6bSBaptiste Daroussin n->line, n->pos, "Dd after Os"); 275861d06d6bSBaptiste Daroussin 27596d38604fSBaptiste Daroussin if (mdoc->quick && n != NULL) 27606d38604fSBaptiste Daroussin mdoc->meta.date = mandoc_strdup(""); 27616d38604fSBaptiste Daroussin else 27626d38604fSBaptiste Daroussin mdoc->meta.date = mandoc_normdate(n->child, n); 276361d06d6bSBaptiste Daroussin } 276461d06d6bSBaptiste Daroussin 276561d06d6bSBaptiste Daroussin static void 276661d06d6bSBaptiste Daroussin post_dt(POST_ARGS) 276761d06d6bSBaptiste Daroussin { 276861d06d6bSBaptiste Daroussin struct roff_node *nn, *n; 276961d06d6bSBaptiste Daroussin const char *cp; 277061d06d6bSBaptiste Daroussin char *p; 277161d06d6bSBaptiste Daroussin 277261d06d6bSBaptiste Daroussin n = mdoc->last; 277361d06d6bSBaptiste Daroussin n->flags |= NODE_NOPRT; 277461d06d6bSBaptiste Daroussin 277561d06d6bSBaptiste Daroussin if (mdoc->flags & MDOC_PBODY) { 27767295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_DT_LATE, n->line, n->pos, "Dt"); 277761d06d6bSBaptiste Daroussin return; 277861d06d6bSBaptiste Daroussin } 277961d06d6bSBaptiste Daroussin 278061d06d6bSBaptiste Daroussin if (mdoc->meta.title != NULL) 27817295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_PROLOG_REP, n->line, n->pos, "Dt"); 278261d06d6bSBaptiste Daroussin else if (mdoc->meta.os != NULL) 27837295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_PROLOG_ORDER, 278461d06d6bSBaptiste Daroussin n->line, n->pos, "Dt after Os"); 278561d06d6bSBaptiste Daroussin 278661d06d6bSBaptiste Daroussin free(mdoc->meta.title); 278761d06d6bSBaptiste Daroussin free(mdoc->meta.msec); 278861d06d6bSBaptiste Daroussin free(mdoc->meta.vol); 278961d06d6bSBaptiste Daroussin free(mdoc->meta.arch); 279061d06d6bSBaptiste Daroussin 279161d06d6bSBaptiste Daroussin mdoc->meta.title = NULL; 279261d06d6bSBaptiste Daroussin mdoc->meta.msec = NULL; 279361d06d6bSBaptiste Daroussin mdoc->meta.vol = NULL; 279461d06d6bSBaptiste Daroussin mdoc->meta.arch = NULL; 279561d06d6bSBaptiste Daroussin 279661d06d6bSBaptiste Daroussin /* Mandatory first argument: title. */ 279761d06d6bSBaptiste Daroussin 279861d06d6bSBaptiste Daroussin nn = n->child; 279961d06d6bSBaptiste Daroussin if (nn == NULL || *nn->string == '\0') { 28007295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_DT_NOTITLE, n->line, n->pos, "Dt"); 280161d06d6bSBaptiste Daroussin mdoc->meta.title = mandoc_strdup("UNTITLED"); 280261d06d6bSBaptiste Daroussin } else { 280361d06d6bSBaptiste Daroussin mdoc->meta.title = mandoc_strdup(nn->string); 280461d06d6bSBaptiste Daroussin 280561d06d6bSBaptiste Daroussin /* Check that all characters are uppercase. */ 280661d06d6bSBaptiste Daroussin 280761d06d6bSBaptiste Daroussin for (p = nn->string; *p != '\0'; p++) 280861d06d6bSBaptiste Daroussin if (islower((unsigned char)*p)) { 28097295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_TITLE_CASE, nn->line, 28107295610fSBaptiste Daroussin nn->pos + (int)(p - nn->string), 281161d06d6bSBaptiste Daroussin "Dt %s", nn->string); 281261d06d6bSBaptiste Daroussin break; 281361d06d6bSBaptiste Daroussin } 281461d06d6bSBaptiste Daroussin } 281561d06d6bSBaptiste Daroussin 281661d06d6bSBaptiste Daroussin /* Mandatory second argument: section. */ 281761d06d6bSBaptiste Daroussin 281861d06d6bSBaptiste Daroussin if (nn != NULL) 281961d06d6bSBaptiste Daroussin nn = nn->next; 282061d06d6bSBaptiste Daroussin 282161d06d6bSBaptiste Daroussin if (nn == NULL) { 28227295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_MSEC_MISSING, n->line, n->pos, 282361d06d6bSBaptiste Daroussin "Dt %s", mdoc->meta.title); 282461d06d6bSBaptiste Daroussin mdoc->meta.vol = mandoc_strdup("LOCAL"); 282561d06d6bSBaptiste Daroussin return; /* msec and arch remain NULL. */ 282661d06d6bSBaptiste Daroussin } 282761d06d6bSBaptiste Daroussin 282861d06d6bSBaptiste Daroussin mdoc->meta.msec = mandoc_strdup(nn->string); 282961d06d6bSBaptiste Daroussin 283061d06d6bSBaptiste Daroussin /* Infer volume title from section number. */ 283161d06d6bSBaptiste Daroussin 283261d06d6bSBaptiste Daroussin cp = mandoc_a2msec(nn->string); 283361d06d6bSBaptiste Daroussin if (cp == NULL) { 28347295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_MSEC_BAD, 283561d06d6bSBaptiste Daroussin nn->line, nn->pos, "Dt ... %s", nn->string); 283661d06d6bSBaptiste Daroussin mdoc->meta.vol = mandoc_strdup(nn->string); 28376d38604fSBaptiste Daroussin } else { 283861d06d6bSBaptiste Daroussin mdoc->meta.vol = mandoc_strdup(cp); 28396d38604fSBaptiste Daroussin if (mdoc->filesec != '\0' && 28406d38604fSBaptiste Daroussin mdoc->filesec != *nn->string && 28416d38604fSBaptiste Daroussin *nn->string >= '1' && *nn->string <= '9') 28426d38604fSBaptiste Daroussin mandoc_msg(MANDOCERR_MSEC_FILE, nn->line, nn->pos, 28436d38604fSBaptiste Daroussin "*.%c vs Dt ... %c", mdoc->filesec, *nn->string); 28446d38604fSBaptiste Daroussin } 284561d06d6bSBaptiste Daroussin 284661d06d6bSBaptiste Daroussin /* Optional third argument: architecture. */ 284761d06d6bSBaptiste Daroussin 284861d06d6bSBaptiste Daroussin if ((nn = nn->next) == NULL) 284961d06d6bSBaptiste Daroussin return; 285061d06d6bSBaptiste Daroussin 285161d06d6bSBaptiste Daroussin for (p = nn->string; *p != '\0'; p++) 285261d06d6bSBaptiste Daroussin *p = tolower((unsigned char)*p); 285361d06d6bSBaptiste Daroussin mdoc->meta.arch = mandoc_strdup(nn->string); 285461d06d6bSBaptiste Daroussin 285561d06d6bSBaptiste Daroussin /* Ignore fourth and later arguments. */ 285661d06d6bSBaptiste Daroussin 285761d06d6bSBaptiste Daroussin if ((nn = nn->next) != NULL) 28587295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_ARG_EXCESS, 285961d06d6bSBaptiste Daroussin nn->line, nn->pos, "Dt ... %s", nn->string); 286061d06d6bSBaptiste Daroussin } 286161d06d6bSBaptiste Daroussin 286261d06d6bSBaptiste Daroussin static void 286361d06d6bSBaptiste Daroussin post_bx(POST_ARGS) 286461d06d6bSBaptiste Daroussin { 286561d06d6bSBaptiste Daroussin struct roff_node *n, *nch; 286661d06d6bSBaptiste Daroussin const char *macro; 286761d06d6bSBaptiste Daroussin 286861d06d6bSBaptiste Daroussin post_delim_nb(mdoc); 286961d06d6bSBaptiste Daroussin 287061d06d6bSBaptiste Daroussin n = mdoc->last; 287161d06d6bSBaptiste Daroussin nch = n->child; 287261d06d6bSBaptiste Daroussin 287361d06d6bSBaptiste Daroussin if (nch != NULL) { 287461d06d6bSBaptiste Daroussin macro = !strcmp(nch->string, "Open") ? "Ox" : 287561d06d6bSBaptiste Daroussin !strcmp(nch->string, "Net") ? "Nx" : 287661d06d6bSBaptiste Daroussin !strcmp(nch->string, "Free") ? "Fx" : 287761d06d6bSBaptiste Daroussin !strcmp(nch->string, "DragonFly") ? "Dx" : NULL; 287861d06d6bSBaptiste Daroussin if (macro != NULL) 28797295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_BX, 28807295610fSBaptiste Daroussin n->line, n->pos, "%s", macro); 288161d06d6bSBaptiste Daroussin mdoc->last = nch; 288261d06d6bSBaptiste Daroussin nch = nch->next; 288361d06d6bSBaptiste Daroussin mdoc->next = ROFF_NEXT_SIBLING; 288461d06d6bSBaptiste Daroussin roff_elem_alloc(mdoc, n->line, n->pos, MDOC_Ns); 288561d06d6bSBaptiste Daroussin mdoc->last->flags |= NODE_NOSRC; 288661d06d6bSBaptiste Daroussin mdoc->next = ROFF_NEXT_SIBLING; 288761d06d6bSBaptiste Daroussin } else 288861d06d6bSBaptiste Daroussin mdoc->next = ROFF_NEXT_CHILD; 288961d06d6bSBaptiste Daroussin roff_word_alloc(mdoc, n->line, n->pos, "BSD"); 289061d06d6bSBaptiste Daroussin mdoc->last->flags |= NODE_NOSRC; 289161d06d6bSBaptiste Daroussin 289261d06d6bSBaptiste Daroussin if (nch == NULL) { 289361d06d6bSBaptiste Daroussin mdoc->last = n; 289461d06d6bSBaptiste Daroussin return; 289561d06d6bSBaptiste Daroussin } 289661d06d6bSBaptiste Daroussin 289761d06d6bSBaptiste Daroussin roff_elem_alloc(mdoc, n->line, n->pos, MDOC_Ns); 289861d06d6bSBaptiste Daroussin mdoc->last->flags |= NODE_NOSRC; 289961d06d6bSBaptiste Daroussin mdoc->next = ROFF_NEXT_SIBLING; 290061d06d6bSBaptiste Daroussin roff_word_alloc(mdoc, n->line, n->pos, "-"); 290161d06d6bSBaptiste Daroussin mdoc->last->flags |= NODE_NOSRC; 290261d06d6bSBaptiste Daroussin roff_elem_alloc(mdoc, n->line, n->pos, MDOC_Ns); 290361d06d6bSBaptiste Daroussin mdoc->last->flags |= NODE_NOSRC; 290461d06d6bSBaptiste Daroussin mdoc->last = n; 290561d06d6bSBaptiste Daroussin 290661d06d6bSBaptiste Daroussin /* 290761d06d6bSBaptiste Daroussin * Make `Bx's second argument always start with an uppercase 290861d06d6bSBaptiste Daroussin * letter. Groff checks if it's an "accepted" term, but we just 290961d06d6bSBaptiste Daroussin * uppercase blindly. 291061d06d6bSBaptiste Daroussin */ 291161d06d6bSBaptiste Daroussin 291261d06d6bSBaptiste Daroussin *nch->string = (char)toupper((unsigned char)*nch->string); 291361d06d6bSBaptiste Daroussin } 291461d06d6bSBaptiste Daroussin 291561d06d6bSBaptiste Daroussin static void 291661d06d6bSBaptiste Daroussin post_os(POST_ARGS) 291761d06d6bSBaptiste Daroussin { 291861d06d6bSBaptiste Daroussin #ifndef OSNAME 291961d06d6bSBaptiste Daroussin struct utsname utsname; 292061d06d6bSBaptiste Daroussin #endif 292161d06d6bSBaptiste Daroussin struct roff_node *n; 292261d06d6bSBaptiste Daroussin 292361d06d6bSBaptiste Daroussin n = mdoc->last; 292461d06d6bSBaptiste Daroussin n->flags |= NODE_NOPRT; 292561d06d6bSBaptiste Daroussin 292661d06d6bSBaptiste Daroussin if (mdoc->meta.os != NULL) 29277295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_PROLOG_REP, n->line, n->pos, "Os"); 292861d06d6bSBaptiste Daroussin else if (mdoc->flags & MDOC_PBODY) 29297295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_PROLOG_LATE, n->line, n->pos, "Os"); 293061d06d6bSBaptiste Daroussin 293161d06d6bSBaptiste Daroussin post_delim(mdoc); 293261d06d6bSBaptiste Daroussin 293361d06d6bSBaptiste Daroussin /* 293461d06d6bSBaptiste Daroussin * Set the operating system by way of the `Os' macro. 293561d06d6bSBaptiste Daroussin * The order of precedence is: 293661d06d6bSBaptiste Daroussin * 1. the argument of the `Os' macro, unless empty 293761d06d6bSBaptiste Daroussin * 2. the -Ios=foo command line argument, if provided 293861d06d6bSBaptiste Daroussin * 3. -DOSNAME="\"foo\"", if provided during compilation 293961d06d6bSBaptiste Daroussin * 4. "sysname release" from uname(3) 294061d06d6bSBaptiste Daroussin */ 294161d06d6bSBaptiste Daroussin 294261d06d6bSBaptiste Daroussin free(mdoc->meta.os); 294361d06d6bSBaptiste Daroussin mdoc->meta.os = NULL; 294461d06d6bSBaptiste Daroussin deroff(&mdoc->meta.os, n); 294561d06d6bSBaptiste Daroussin if (mdoc->meta.os) 294661d06d6bSBaptiste Daroussin goto out; 294761d06d6bSBaptiste Daroussin 294861d06d6bSBaptiste Daroussin if (mdoc->os_s != NULL) { 294961d06d6bSBaptiste Daroussin mdoc->meta.os = mandoc_strdup(mdoc->os_s); 295061d06d6bSBaptiste Daroussin goto out; 295161d06d6bSBaptiste Daroussin } 295261d06d6bSBaptiste Daroussin 295361d06d6bSBaptiste Daroussin #ifdef OSNAME 295461d06d6bSBaptiste Daroussin mdoc->meta.os = mandoc_strdup(OSNAME); 295561d06d6bSBaptiste Daroussin #else /*!OSNAME */ 2956*c1c95addSBrooks Davis if (mdoc->os_r == NULL) { 295761d06d6bSBaptiste Daroussin if (uname(&utsname) == -1) { 29587295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_OS_UNAME, n->line, n->pos, "Os"); 2959*c1c95addSBrooks Davis mdoc->os_r = mandoc_strdup("UNKNOWN"); 296061d06d6bSBaptiste Daroussin } else 2961*c1c95addSBrooks Davis mandoc_asprintf(&mdoc->os_r, "%s %s", 296261d06d6bSBaptiste Daroussin utsname.sysname, utsname.release); 296361d06d6bSBaptiste Daroussin } 2964*c1c95addSBrooks Davis mdoc->meta.os = mandoc_strdup(mdoc->os_r); 296561d06d6bSBaptiste Daroussin #endif /*!OSNAME*/ 296661d06d6bSBaptiste Daroussin 296761d06d6bSBaptiste Daroussin out: 296861d06d6bSBaptiste Daroussin if (mdoc->meta.os_e == MANDOC_OS_OTHER) { 296961d06d6bSBaptiste Daroussin if (strstr(mdoc->meta.os, "OpenBSD") != NULL) 297061d06d6bSBaptiste Daroussin mdoc->meta.os_e = MANDOC_OS_OPENBSD; 297161d06d6bSBaptiste Daroussin else if (strstr(mdoc->meta.os, "NetBSD") != NULL) 297261d06d6bSBaptiste Daroussin mdoc->meta.os_e = MANDOC_OS_NETBSD; 297361d06d6bSBaptiste Daroussin } 297461d06d6bSBaptiste Daroussin 297561d06d6bSBaptiste Daroussin /* 297661d06d6bSBaptiste Daroussin * This is the earliest point where we can check 297761d06d6bSBaptiste Daroussin * Mdocdate conventions because we don't know 297861d06d6bSBaptiste Daroussin * the operating system earlier. 297961d06d6bSBaptiste Daroussin */ 298061d06d6bSBaptiste Daroussin 298161d06d6bSBaptiste Daroussin if (n->child != NULL) 29827295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_OS_ARG, n->child->line, n->child->pos, 298361d06d6bSBaptiste Daroussin "Os %s (%s)", n->child->string, 298461d06d6bSBaptiste Daroussin mdoc->meta.os_e == MANDOC_OS_OPENBSD ? 298561d06d6bSBaptiste Daroussin "OpenBSD" : "NetBSD"); 298661d06d6bSBaptiste Daroussin 298761d06d6bSBaptiste Daroussin while (n->tok != MDOC_Dd) 298861d06d6bSBaptiste Daroussin if ((n = n->prev) == NULL) 298961d06d6bSBaptiste Daroussin return; 299061d06d6bSBaptiste Daroussin if ((n = n->child) == NULL) 299161d06d6bSBaptiste Daroussin return; 299261d06d6bSBaptiste Daroussin if (strncmp(n->string, "$" "Mdocdate", 9)) { 299361d06d6bSBaptiste Daroussin if (mdoc->meta.os_e == MANDOC_OS_OPENBSD) 29947295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_MDOCDATE_MISSING, n->line, 29957295610fSBaptiste Daroussin n->pos, "Dd %s (OpenBSD)", n->string); 299661d06d6bSBaptiste Daroussin } else { 299761d06d6bSBaptiste Daroussin if (mdoc->meta.os_e == MANDOC_OS_NETBSD) 29987295610fSBaptiste Daroussin mandoc_msg(MANDOCERR_MDOCDATE, n->line, 29997295610fSBaptiste Daroussin n->pos, "Dd %s (NetBSD)", n->string); 300061d06d6bSBaptiste Daroussin } 300161d06d6bSBaptiste Daroussin } 300261d06d6bSBaptiste Daroussin 300361d06d6bSBaptiste Daroussin enum roff_sec 300461d06d6bSBaptiste Daroussin mdoc_a2sec(const char *p) 300561d06d6bSBaptiste Daroussin { 300661d06d6bSBaptiste Daroussin int i; 300761d06d6bSBaptiste Daroussin 300861d06d6bSBaptiste Daroussin for (i = 0; i < (int)SEC__MAX; i++) 300961d06d6bSBaptiste Daroussin if (secnames[i] && 0 == strcmp(p, secnames[i])) 301061d06d6bSBaptiste Daroussin return (enum roff_sec)i; 301161d06d6bSBaptiste Daroussin 301261d06d6bSBaptiste Daroussin return SEC_CUSTOM; 301361d06d6bSBaptiste Daroussin } 301461d06d6bSBaptiste Daroussin 301561d06d6bSBaptiste Daroussin static size_t 301661d06d6bSBaptiste Daroussin macro2len(enum roff_tok macro) 301761d06d6bSBaptiste Daroussin { 301861d06d6bSBaptiste Daroussin 301961d06d6bSBaptiste Daroussin switch (macro) { 302061d06d6bSBaptiste Daroussin case MDOC_Ad: 302161d06d6bSBaptiste Daroussin return 12; 302261d06d6bSBaptiste Daroussin case MDOC_Ao: 302361d06d6bSBaptiste Daroussin return 12; 302461d06d6bSBaptiste Daroussin case MDOC_An: 302561d06d6bSBaptiste Daroussin return 12; 302661d06d6bSBaptiste Daroussin case MDOC_Aq: 302761d06d6bSBaptiste Daroussin return 12; 302861d06d6bSBaptiste Daroussin case MDOC_Ar: 302961d06d6bSBaptiste Daroussin return 12; 303061d06d6bSBaptiste Daroussin case MDOC_Bo: 303161d06d6bSBaptiste Daroussin return 12; 303261d06d6bSBaptiste Daroussin case MDOC_Bq: 303361d06d6bSBaptiste Daroussin return 12; 303461d06d6bSBaptiste Daroussin case MDOC_Cd: 303561d06d6bSBaptiste Daroussin return 12; 303661d06d6bSBaptiste Daroussin case MDOC_Cm: 303761d06d6bSBaptiste Daroussin return 10; 303861d06d6bSBaptiste Daroussin case MDOC_Do: 303961d06d6bSBaptiste Daroussin return 10; 304061d06d6bSBaptiste Daroussin case MDOC_Dq: 304161d06d6bSBaptiste Daroussin return 12; 304261d06d6bSBaptiste Daroussin case MDOC_Dv: 304361d06d6bSBaptiste Daroussin return 12; 304461d06d6bSBaptiste Daroussin case MDOC_Eo: 304561d06d6bSBaptiste Daroussin return 12; 304661d06d6bSBaptiste Daroussin case MDOC_Em: 304761d06d6bSBaptiste Daroussin return 10; 304861d06d6bSBaptiste Daroussin case MDOC_Er: 304961d06d6bSBaptiste Daroussin return 17; 305061d06d6bSBaptiste Daroussin case MDOC_Ev: 305161d06d6bSBaptiste Daroussin return 15; 305261d06d6bSBaptiste Daroussin case MDOC_Fa: 305361d06d6bSBaptiste Daroussin return 12; 305461d06d6bSBaptiste Daroussin case MDOC_Fl: 305561d06d6bSBaptiste Daroussin return 10; 305661d06d6bSBaptiste Daroussin case MDOC_Fo: 305761d06d6bSBaptiste Daroussin return 16; 305861d06d6bSBaptiste Daroussin case MDOC_Fn: 305961d06d6bSBaptiste Daroussin return 16; 306061d06d6bSBaptiste Daroussin case MDOC_Ic: 306161d06d6bSBaptiste Daroussin return 10; 306261d06d6bSBaptiste Daroussin case MDOC_Li: 306361d06d6bSBaptiste Daroussin return 16; 306461d06d6bSBaptiste Daroussin case MDOC_Ms: 306561d06d6bSBaptiste Daroussin return 6; 306661d06d6bSBaptiste Daroussin case MDOC_Nm: 306761d06d6bSBaptiste Daroussin return 10; 306861d06d6bSBaptiste Daroussin case MDOC_No: 306961d06d6bSBaptiste Daroussin return 12; 307061d06d6bSBaptiste Daroussin case MDOC_Oo: 307161d06d6bSBaptiste Daroussin return 10; 307261d06d6bSBaptiste Daroussin case MDOC_Op: 307361d06d6bSBaptiste Daroussin return 14; 307461d06d6bSBaptiste Daroussin case MDOC_Pa: 307561d06d6bSBaptiste Daroussin return 32; 307661d06d6bSBaptiste Daroussin case MDOC_Pf: 307761d06d6bSBaptiste Daroussin return 12; 307861d06d6bSBaptiste Daroussin case MDOC_Po: 307961d06d6bSBaptiste Daroussin return 12; 308061d06d6bSBaptiste Daroussin case MDOC_Pq: 308161d06d6bSBaptiste Daroussin return 12; 308261d06d6bSBaptiste Daroussin case MDOC_Ql: 308361d06d6bSBaptiste Daroussin return 16; 308461d06d6bSBaptiste Daroussin case MDOC_Qo: 308561d06d6bSBaptiste Daroussin return 12; 308661d06d6bSBaptiste Daroussin case MDOC_So: 308761d06d6bSBaptiste Daroussin return 12; 308861d06d6bSBaptiste Daroussin case MDOC_Sq: 308961d06d6bSBaptiste Daroussin return 12; 309061d06d6bSBaptiste Daroussin case MDOC_Sy: 309161d06d6bSBaptiste Daroussin return 6; 309261d06d6bSBaptiste Daroussin case MDOC_Sx: 309361d06d6bSBaptiste Daroussin return 16; 309461d06d6bSBaptiste Daroussin case MDOC_Tn: 309561d06d6bSBaptiste Daroussin return 10; 309661d06d6bSBaptiste Daroussin case MDOC_Va: 309761d06d6bSBaptiste Daroussin return 12; 309861d06d6bSBaptiste Daroussin case MDOC_Vt: 309961d06d6bSBaptiste Daroussin return 12; 310061d06d6bSBaptiste Daroussin case MDOC_Xr: 310161d06d6bSBaptiste Daroussin return 10; 310261d06d6bSBaptiste Daroussin default: 310361d06d6bSBaptiste Daroussin break; 310461d06d6bSBaptiste Daroussin }; 310561d06d6bSBaptiste Daroussin return 0; 310661d06d6bSBaptiste Daroussin } 3107