1*1d0823adSschwarze /* $OpenBSD: mdoc_validate.c,v 1.191 2015/02/06 07:12:34 schwarze Exp $ */ 2f73abda9Skristaps /* 322972b14Sschwarze * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv> 42d266539Sschwarze * Copyright (c) 2010-2015 Ingo Schwarze <schwarze@openbsd.org> 539c2a57eSschwarze * Copyright (c) 2010 Joerg Sonnenberger <joerg@netbsd.org> 6f73abda9Skristaps * 7f73abda9Skristaps * Permission to use, copy, modify, and distribute this software for any 8a6464425Sschwarze * purpose with or without fee is hereby granted, provided that the above 9a6464425Sschwarze * copyright notice and this permission notice appear in all copies. 10f73abda9Skristaps * 11a6464425Sschwarze * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12a6464425Sschwarze * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13a6464425Sschwarze * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14a6464425Sschwarze * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15a6464425Sschwarze * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16a6464425Sschwarze * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17a6464425Sschwarze * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18f73abda9Skristaps */ 19dadc3a61Sschwarze #include <sys/types.h> 2020fa2881Sschwarze #ifndef OSNAME 2120fa2881Sschwarze #include <sys/utsname.h> 2220fa2881Sschwarze #endif 2320fa2881Sschwarze 24f73abda9Skristaps #include <assert.h> 25f73abda9Skristaps #include <ctype.h> 26d92dc4efSschwarze #include <limits.h> 273216dddfSschwarze #include <stdio.h> 28f73abda9Skristaps #include <stdlib.h> 29f73abda9Skristaps #include <string.h> 3020fa2881Sschwarze #include <time.h> 31f73abda9Skristaps 32a35fc07aSschwarze #include "mdoc.h" 336e03d529Sschwarze #include "mandoc.h" 344f4f7972Sschwarze #include "mandoc_aux.h" 35f73abda9Skristaps #include "libmdoc.h" 36f6854d5cSschwarze #include "libmandoc.h" 37f73abda9Skristaps 38f73abda9Skristaps /* FIXME: .Bl -diag can't have non-text children in HEAD. */ 39f73abda9Skristaps 406093755cSschwarze #define PRE_ARGS struct mdoc *mdoc, struct mdoc_node *n 41f73abda9Skristaps #define POST_ARGS struct mdoc *mdoc 42f73abda9Skristaps 437c2be9f8Sschwarze enum check_ineq { 447c2be9f8Sschwarze CHECK_LT, 457c2be9f8Sschwarze CHECK_GT, 467c2be9f8Sschwarze CHECK_EQ 477c2be9f8Sschwarze }; 487c2be9f8Sschwarze 4998b8f00aSschwarze typedef void (*v_pre)(PRE_ARGS); 5098b8f00aSschwarze typedef void (*v_post)(POST_ARGS); 51f73abda9Skristaps 52f73abda9Skristaps struct valids { 53d52d1586Sschwarze v_pre pre; 54753701eeSschwarze v_post post; 55f73abda9Skristaps }; 56f73abda9Skristaps 5720fa2881Sschwarze static void check_text(struct mdoc *, int, int, char *); 5820fa2881Sschwarze static void check_argv(struct mdoc *, 5931e23753Sschwarze struct mdoc_node *, struct mdoc_argv *); 6020fa2881Sschwarze static void check_args(struct mdoc *, struct mdoc_node *); 61cd6c268fSschwarze static int child_an(const struct mdoc_node *); 6219a69263Sschwarze static enum mdoc_sec a2sec(const char *); 6319a69263Sschwarze static size_t macro2len(enum mdoct); 6490d52a15Sschwarze static void rewrite_macro2len(char **); 6567c719adSschwarze 6698b8f00aSschwarze static void post_an(POST_ARGS); 6798b8f00aSschwarze static void post_at(POST_ARGS); 6898b8f00aSschwarze static void post_bf(POST_ARGS); 6998b8f00aSschwarze static void post_bk(POST_ARGS); 7098b8f00aSschwarze static void post_bl(POST_ARGS); 7198b8f00aSschwarze static void post_bl_block(POST_ARGS); 7298b8f00aSschwarze static void post_bl_block_tag(POST_ARGS); 7398b8f00aSschwarze static void post_bl_head(POST_ARGS); 7498b8f00aSschwarze static void post_bx(POST_ARGS); 7598b8f00aSschwarze static void post_d1(POST_ARGS); 7698b8f00aSschwarze static void post_defaults(POST_ARGS); 7798b8f00aSschwarze static void post_dd(POST_ARGS); 7898b8f00aSschwarze static void post_dt(POST_ARGS); 7998b8f00aSschwarze static void post_en(POST_ARGS); 8098b8f00aSschwarze static void post_es(POST_ARGS); 8198b8f00aSschwarze static void post_eoln(POST_ARGS); 8298b8f00aSschwarze static void post_ex(POST_ARGS); 8398b8f00aSschwarze static void post_fa(POST_ARGS); 8498b8f00aSschwarze static void post_fn(POST_ARGS); 8598b8f00aSschwarze static void post_fname(POST_ARGS); 8698b8f00aSschwarze static void post_fo(POST_ARGS); 8798b8f00aSschwarze static void post_hyph(POST_ARGS); 8898b8f00aSschwarze static void post_ignpar(POST_ARGS); 8998b8f00aSschwarze static void post_it(POST_ARGS); 9098b8f00aSschwarze static void post_lb(POST_ARGS); 9198b8f00aSschwarze static void post_literal(POST_ARGS); 9298b8f00aSschwarze static void post_nd(POST_ARGS); 9398b8f00aSschwarze static void post_nm(POST_ARGS); 9498b8f00aSschwarze static void post_ns(POST_ARGS); 9598b8f00aSschwarze static void post_os(POST_ARGS); 9698b8f00aSschwarze static void post_par(POST_ARGS); 9798b8f00aSschwarze static void post_root(POST_ARGS); 9898b8f00aSschwarze static void post_rs(POST_ARGS); 9998b8f00aSschwarze static void post_sh(POST_ARGS); 10098b8f00aSschwarze static void post_sh_head(POST_ARGS); 10198b8f00aSschwarze static void post_sh_name(POST_ARGS); 10298b8f00aSschwarze static void post_sh_see_also(POST_ARGS); 10398b8f00aSschwarze static void post_sh_authors(POST_ARGS); 10498b8f00aSschwarze static void post_sm(POST_ARGS); 10598b8f00aSschwarze static void post_st(POST_ARGS); 10698b8f00aSschwarze static void post_vt(POST_ARGS); 10798b8f00aSschwarze 10898b8f00aSschwarze static void pre_an(PRE_ARGS); 10998b8f00aSschwarze static void pre_bd(PRE_ARGS); 11098b8f00aSschwarze static void pre_bl(PRE_ARGS); 11198b8f00aSschwarze static void pre_dd(PRE_ARGS); 11298b8f00aSschwarze static void pre_display(PRE_ARGS); 11398b8f00aSschwarze static void pre_dt(PRE_ARGS); 11498b8f00aSschwarze static void pre_literal(PRE_ARGS); 11598b8f00aSschwarze static void pre_obsolete(PRE_ARGS); 11698b8f00aSschwarze static void pre_os(PRE_ARGS); 11798b8f00aSschwarze static void pre_par(PRE_ARGS); 11898b8f00aSschwarze static void pre_std(PRE_ARGS); 119f73abda9Skristaps 12019a69263Sschwarze static const struct valids mdoc_valids[MDOC_MAX] = { 121099cfa7eSschwarze { NULL, NULL }, /* Ap */ 122753701eeSschwarze { pre_dd, post_dd }, /* Dd */ 123753701eeSschwarze { pre_dt, post_dt }, /* Dt */ 124753701eeSschwarze { pre_os, post_os }, /* Os */ 125753701eeSschwarze { NULL, post_sh }, /* Sh */ 126753701eeSschwarze { NULL, post_ignpar }, /* Ss */ 127753701eeSschwarze { pre_par, post_par }, /* Pp */ 128753701eeSschwarze { pre_display, post_d1 }, /* D1 */ 129753701eeSschwarze { pre_literal, post_literal }, /* Dl */ 130753701eeSschwarze { pre_bd, post_literal }, /* Bd */ 131f73abda9Skristaps { NULL, NULL }, /* Ed */ 132753701eeSschwarze { pre_bl, post_bl }, /* Bl */ 133f73abda9Skristaps { NULL, NULL }, /* El */ 134753701eeSschwarze { pre_par, post_it }, /* It */ 135e7a93ef3Sschwarze { NULL, NULL }, /* Ad */ 136753701eeSschwarze { pre_an, post_an }, /* An */ 137753701eeSschwarze { NULL, post_defaults }, /* Ar */ 138e7a93ef3Sschwarze { NULL, NULL }, /* Cd */ 139f73abda9Skristaps { NULL, NULL }, /* Cm */ 140f73abda9Skristaps { NULL, NULL }, /* Dv */ 1414039b21cSschwarze { NULL, NULL }, /* Er */ 142f73abda9Skristaps { NULL, NULL }, /* Ev */ 143753701eeSschwarze { pre_std, post_ex }, /* Ex */ 1447e92c062Sschwarze { NULL, post_fa }, /* Fa */ 145afcd1f03Sschwarze { NULL, NULL }, /* Fd */ 146f73abda9Skristaps { NULL, NULL }, /* Fl */ 1470c5064e3Sschwarze { NULL, post_fn }, /* Fn */ 148e7a93ef3Sschwarze { NULL, NULL }, /* Ft */ 149e7a93ef3Sschwarze { NULL, NULL }, /* Ic */ 150b6df9df3Sschwarze { NULL, NULL }, /* In */ 151753701eeSschwarze { NULL, post_defaults }, /* Li */ 152753701eeSschwarze { NULL, post_nd }, /* Nd */ 153753701eeSschwarze { NULL, post_nm }, /* Nm */ 154bca76d61Sschwarze { NULL, NULL }, /* Op */ 155d52d1586Sschwarze { pre_obsolete, NULL }, /* Ot */ 156753701eeSschwarze { NULL, post_defaults }, /* Pa */ 157d52d1586Sschwarze { pre_std, NULL }, /* Rv */ 158753701eeSschwarze { NULL, post_st }, /* St */ 159f73abda9Skristaps { NULL, NULL }, /* Va */ 160753701eeSschwarze { NULL, post_vt }, /* Vt */ 161b6df9df3Sschwarze { NULL, NULL }, /* Xr */ 162*1d0823adSschwarze { NULL, NULL }, /* %A */ 163*1d0823adSschwarze { NULL, post_hyph }, /* %B */ /* FIXME: can be used outside Rs/Re. */ 164*1d0823adSschwarze { NULL, NULL }, /* %D */ 165*1d0823adSschwarze { NULL, NULL }, /* %I */ 166*1d0823adSschwarze { NULL, NULL }, /* %J */ 167*1d0823adSschwarze { NULL, post_hyph }, /* %N */ 168*1d0823adSschwarze { NULL, post_hyph }, /* %O */ 169*1d0823adSschwarze { NULL, NULL }, /* %P */ 170*1d0823adSschwarze { NULL, post_hyph }, /* %R */ 171*1d0823adSschwarze { NULL, post_hyph }, /* %T */ /* FIXME: can be used outside Rs/Re. */ 172*1d0823adSschwarze { NULL, NULL }, /* %V */ 173f73abda9Skristaps { NULL, NULL }, /* Ac */ 174f73abda9Skristaps { NULL, NULL }, /* Ao */ 175bca76d61Sschwarze { NULL, NULL }, /* Aq */ 176753701eeSschwarze { NULL, post_at }, /* At */ 177f73abda9Skristaps { NULL, NULL }, /* Bc */ 178753701eeSschwarze { NULL, post_bf }, /* Bf */ 179f73abda9Skristaps { NULL, NULL }, /* Bo */ 180bca76d61Sschwarze { NULL, NULL }, /* Bq */ 181f73abda9Skristaps { NULL, NULL }, /* Bsx */ 182753701eeSschwarze { NULL, post_bx }, /* Bx */ 18378bbbab4Sschwarze { pre_obsolete, NULL }, /* Db */ 184f73abda9Skristaps { NULL, NULL }, /* Dc */ 185f73abda9Skristaps { NULL, NULL }, /* Do */ 186bca76d61Sschwarze { NULL, NULL }, /* Dq */ 187f73abda9Skristaps { NULL, NULL }, /* Ec */ 188f73abda9Skristaps { NULL, NULL }, /* Ef */ 189f73abda9Skristaps { NULL, NULL }, /* Em */ 190f73abda9Skristaps { NULL, NULL }, /* Eo */ 191f73abda9Skristaps { NULL, NULL }, /* Fx */ 192e7a93ef3Sschwarze { NULL, NULL }, /* Ms */ 1936f9818f6Sschwarze { NULL, NULL }, /* No */ 194753701eeSschwarze { NULL, post_ns }, /* Ns */ 195f73abda9Skristaps { NULL, NULL }, /* Nx */ 196f73abda9Skristaps { NULL, NULL }, /* Ox */ 197f73abda9Skristaps { NULL, NULL }, /* Pc */ 19888fc1858Sschwarze { NULL, NULL }, /* Pf */ 199f73abda9Skristaps { NULL, NULL }, /* Po */ 200bca76d61Sschwarze { NULL, NULL }, /* Pq */ 201f73abda9Skristaps { NULL, NULL }, /* Qc */ 202bca76d61Sschwarze { NULL, NULL }, /* Ql */ 203f73abda9Skristaps { NULL, NULL }, /* Qo */ 204bca76d61Sschwarze { NULL, NULL }, /* Qq */ 205f73abda9Skristaps { NULL, NULL }, /* Re */ 206753701eeSschwarze { NULL, post_rs }, /* Rs */ 207f73abda9Skristaps { NULL, NULL }, /* Sc */ 208f73abda9Skristaps { NULL, NULL }, /* So */ 209bca76d61Sschwarze { NULL, NULL }, /* Sq */ 21078bbbab4Sschwarze { NULL, post_sm }, /* Sm */ 211753701eeSschwarze { NULL, post_hyph }, /* Sx */ 212e7a93ef3Sschwarze { NULL, NULL }, /* Sy */ 213e7a93ef3Sschwarze { NULL, NULL }, /* Tn */ 214f73abda9Skristaps { NULL, NULL }, /* Ux */ 215f73abda9Skristaps { NULL, NULL }, /* Xc */ 216f73abda9Skristaps { NULL, NULL }, /* Xo */ 217753701eeSschwarze { NULL, post_fo }, /* Fo */ 218f73abda9Skristaps { NULL, NULL }, /* Fc */ 219f73abda9Skristaps { NULL, NULL }, /* Oo */ 220f73abda9Skristaps { NULL, NULL }, /* Oc */ 221753701eeSschwarze { NULL, post_bk }, /* Bk */ 222f73abda9Skristaps { NULL, NULL }, /* Ek */ 223753701eeSschwarze { NULL, post_eoln }, /* Bt */ 224f73abda9Skristaps { NULL, NULL }, /* Hf */ 225d52d1586Sschwarze { pre_obsolete, NULL }, /* Fr */ 226753701eeSschwarze { NULL, post_eoln }, /* Ud */ 227753701eeSschwarze { NULL, post_lb }, /* Lb */ 228753701eeSschwarze { pre_par, post_par }, /* Lp */ 229e7a93ef3Sschwarze { NULL, NULL }, /* Lk */ 230753701eeSschwarze { NULL, post_defaults }, /* Mt */ 231bca76d61Sschwarze { NULL, NULL }, /* Brq */ 232f73abda9Skristaps { NULL, NULL }, /* Bro */ 233f73abda9Skristaps { NULL, NULL }, /* Brc */ 234*1d0823adSschwarze { NULL, NULL }, /* %C */ 235753701eeSschwarze { pre_obsolete, post_es }, /* Es */ 236753701eeSschwarze { pre_obsolete, post_en }, /* En */ 237f73abda9Skristaps { NULL, NULL }, /* Dx */ 238*1d0823adSschwarze { NULL, NULL }, /* %Q */ 239753701eeSschwarze { NULL, post_par }, /* br */ 240753701eeSschwarze { NULL, post_par }, /* sp */ 241*1d0823adSschwarze { NULL, NULL }, /* %U */ 2426093755cSschwarze { NULL, NULL }, /* Ta */ 2435281506aSschwarze { NULL, NULL }, /* ll */ 244f73abda9Skristaps }; 245f73abda9Skristaps 24620fa2881Sschwarze #define RSORD_MAX 14 /* Number of `Rs' blocks. */ 24720fa2881Sschwarze 24820fa2881Sschwarze static const enum mdoct rsord[RSORD_MAX] = { 24920fa2881Sschwarze MDOC__A, 25020fa2881Sschwarze MDOC__T, 25120fa2881Sschwarze MDOC__B, 25220fa2881Sschwarze MDOC__I, 25320fa2881Sschwarze MDOC__J, 25420fa2881Sschwarze MDOC__R, 25520fa2881Sschwarze MDOC__N, 25620fa2881Sschwarze MDOC__V, 2570397c682Sschwarze MDOC__U, 25820fa2881Sschwarze MDOC__P, 25920fa2881Sschwarze MDOC__Q, 2604e32ec8fSschwarze MDOC__C, 26120fa2881Sschwarze MDOC__D, 2624e32ec8fSschwarze MDOC__O 26320fa2881Sschwarze }; 26420fa2881Sschwarze 26519a69263Sschwarze static const char * const secnames[SEC__MAX] = { 26619a69263Sschwarze NULL, 26719a69263Sschwarze "NAME", 26819a69263Sschwarze "LIBRARY", 26919a69263Sschwarze "SYNOPSIS", 27019a69263Sschwarze "DESCRIPTION", 27103ab2f23Sdlg "CONTEXT", 27219a69263Sschwarze "IMPLEMENTATION NOTES", 27319a69263Sschwarze "RETURN VALUES", 27419a69263Sschwarze "ENVIRONMENT", 27519a69263Sschwarze "FILES", 27619a69263Sschwarze "EXIT STATUS", 27719a69263Sschwarze "EXAMPLES", 27819a69263Sschwarze "DIAGNOSTICS", 27919a69263Sschwarze "COMPATIBILITY", 28019a69263Sschwarze "ERRORS", 28119a69263Sschwarze "SEE ALSO", 28219a69263Sschwarze "STANDARDS", 28319a69263Sschwarze "HISTORY", 28419a69263Sschwarze "AUTHORS", 28519a69263Sschwarze "CAVEATS", 28619a69263Sschwarze "BUGS", 28719a69263Sschwarze "SECURITY CONSIDERATIONS", 28819a69263Sschwarze NULL 28919a69263Sschwarze }; 290f73abda9Skristaps 29149aff9f8Sschwarze 29298b8f00aSschwarze void 2936093755cSschwarze mdoc_valid_pre(struct mdoc *mdoc, struct mdoc_node *n) 294f73abda9Skristaps { 295d52d1586Sschwarze v_pre p; 296f73abda9Skristaps 2972791bd1cSschwarze switch (n->type) { 29849aff9f8Sschwarze case MDOC_TEXT: 299d52d1586Sschwarze check_text(mdoc, n->line, n->pos, n->string); 3002791bd1cSschwarze /* FALLTHROUGH */ 30149aff9f8Sschwarze case MDOC_TBL: 3022791bd1cSschwarze /* FALLTHROUGH */ 30349aff9f8Sschwarze case MDOC_EQN: 3048d973ab1Sschwarze /* FALLTHROUGH */ 30549aff9f8Sschwarze case MDOC_ROOT: 30698b8f00aSschwarze return; 3072791bd1cSschwarze default: 3082791bd1cSschwarze break; 309f73abda9Skristaps } 310f73abda9Skristaps 31120fa2881Sschwarze check_args(mdoc, n); 312d52d1586Sschwarze p = mdoc_valids[n->tok].pre; 31398b8f00aSschwarze if (*p) 31498b8f00aSschwarze (*p)(mdoc, n); 315f73abda9Skristaps } 316f73abda9Skristaps 31798b8f00aSschwarze void 318f73abda9Skristaps mdoc_valid_post(struct mdoc *mdoc) 319f73abda9Skristaps { 320753701eeSschwarze struct mdoc_node *n; 321753701eeSschwarze v_post p; 322f73abda9Skristaps 323753701eeSschwarze n = mdoc->last; 324753701eeSschwarze if (n->flags & MDOC_VALID) 32598b8f00aSschwarze return; 326753701eeSschwarze n->flags |= MDOC_VALID; 327f73abda9Skristaps 328753701eeSschwarze switch (n->type) { 32949aff9f8Sschwarze case MDOC_TEXT: 3302791bd1cSschwarze /* FALLTHROUGH */ 33149aff9f8Sschwarze case MDOC_EQN: 3328d973ab1Sschwarze /* FALLTHROUGH */ 33349aff9f8Sschwarze case MDOC_TBL: 33498b8f00aSschwarze break; 33549aff9f8Sschwarze case MDOC_ROOT: 33698b8f00aSschwarze post_root(mdoc); 33798b8f00aSschwarze break; 3382791bd1cSschwarze default: 3396f9818f6Sschwarze 3406f9818f6Sschwarze /* 3416f9818f6Sschwarze * Closing delimiters are not special at the 3426f9818f6Sschwarze * beginning of a block, opening delimiters 3436f9818f6Sschwarze * are not special at the end. 3446f9818f6Sschwarze */ 3456f9818f6Sschwarze 3466f9818f6Sschwarze if (n->child != NULL) 3476f9818f6Sschwarze n->child->flags &= ~MDOC_DELIMC; 3486f9818f6Sschwarze if (n->last != NULL) 3496f9818f6Sschwarze n->last->flags &= ~MDOC_DELIMO; 3506f9818f6Sschwarze 3516f9818f6Sschwarze /* Call the macro's postprocessor. */ 3526f9818f6Sschwarze 353753701eeSschwarze p = mdoc_valids[n->tok].post; 35498b8f00aSschwarze if (*p) 35598b8f00aSschwarze (*p)(mdoc); 35698b8f00aSschwarze break; 3572791bd1cSschwarze } 358f73abda9Skristaps } 359f73abda9Skristaps 36098b8f00aSschwarze static void 3617ead8a4eSschwarze check_args(struct mdoc *mdoc, struct mdoc_node *n) 362f73abda9Skristaps { 363f73abda9Skristaps int i; 364f73abda9Skristaps 365f73abda9Skristaps if (NULL == n->args) 36620fa2881Sschwarze return; 367f73abda9Skristaps 368f73abda9Skristaps assert(n->args->argc); 369f73abda9Skristaps for (i = 0; i < (int)n->args->argc; i++) 3707ead8a4eSschwarze check_argv(mdoc, n, &n->args->argv[i]); 371f73abda9Skristaps } 372f73abda9Skristaps 37320fa2881Sschwarze static void 3747ead8a4eSschwarze check_argv(struct mdoc *mdoc, struct mdoc_node *n, struct mdoc_argv *v) 375f73abda9Skristaps { 376f73abda9Skristaps int i; 377f73abda9Skristaps 378f73abda9Skristaps for (i = 0; i < (int)v->sz; i++) 3797ead8a4eSschwarze check_text(mdoc, v->line, v->pos, v->value[i]); 380f73abda9Skristaps } 381f73abda9Skristaps 38220fa2881Sschwarze static void 3837ead8a4eSschwarze check_text(struct mdoc *mdoc, int ln, int pos, char *p) 384f73abda9Skristaps { 38504e980cbSschwarze char *cp; 386769ee804Sschwarze 3877ead8a4eSschwarze if (MDOC_LITERAL & mdoc->flags) 3881cdbf331Sschwarze return; 3891cdbf331Sschwarze 3901cdbf331Sschwarze for (cp = p; NULL != (p = strchr(p, '\t')); p++) 391dd5b31c3Sschwarze mandoc_msg(MANDOCERR_FI_TAB, mdoc->parse, 392dd5b31c3Sschwarze ln, pos + (int)(p - cp), NULL); 393f73abda9Skristaps } 394f73abda9Skristaps 39598b8f00aSschwarze static void 396f73abda9Skristaps pre_display(PRE_ARGS) 397f73abda9Skristaps { 398f73abda9Skristaps struct mdoc_node *node; 399f73abda9Skristaps 400f73abda9Skristaps if (MDOC_BLOCK != n->type) 40198b8f00aSschwarze return; 402f73abda9Skristaps 403f73abda9Skristaps for (node = mdoc->last->parent; node; node = node->parent) 404f73abda9Skristaps if (MDOC_BLOCK == node->type) 405f73abda9Skristaps if (MDOC_Bd == node->tok) 406f73abda9Skristaps break; 40720fa2881Sschwarze 40805c39368Sschwarze if (node) 409b723eac2Sschwarze mandoc_vmsg(MANDOCERR_BD_NEST, 410b723eac2Sschwarze mdoc->parse, n->line, n->pos, 411b723eac2Sschwarze "%s in Bd", mdoc_macronames[n->tok]); 412f73abda9Skristaps } 413f73abda9Skristaps 41498b8f00aSschwarze static void 415f73abda9Skristaps pre_bl(PRE_ARGS) 416f73abda9Skristaps { 417769ee804Sschwarze struct mdoc_node *np; 418aa99c14fSschwarze struct mdoc_argv *argv, *wa; 4194a9f685fSschwarze int i; 420aa99c14fSschwarze enum mdocargt mdoclt; 4214a9f685fSschwarze enum mdoc_list lt; 422f73abda9Skristaps 4236093755cSschwarze if (MDOC_BLOCK != n->type) { 424769ee804Sschwarze if (ENDBODY_NOT != n->end) { 425769ee804Sschwarze assert(n->pending); 426769ee804Sschwarze np = n->pending->parent; 427769ee804Sschwarze } else 428769ee804Sschwarze np = n->parent; 429769ee804Sschwarze 430769ee804Sschwarze assert(np); 431769ee804Sschwarze assert(MDOC_BLOCK == np->type); 432769ee804Sschwarze assert(MDOC_Bl == np->tok); 43398b8f00aSschwarze return; 4346e03d529Sschwarze } 435f73abda9Skristaps 4366093755cSschwarze /* 4376093755cSschwarze * First figure out which kind of list to use: bind ourselves to 4386093755cSschwarze * the first mentioned list type and warn about any remaining 4396093755cSschwarze * ones. If we find no list type, we default to LIST_item. 4406093755cSschwarze */ 441f73abda9Skristaps 442dadc3a61Sschwarze wa = (n->args == NULL) ? NULL : n->args->argv; 443aa99c14fSschwarze mdoclt = MDOC_ARG_MAX; 4446093755cSschwarze for (i = 0; n->args && i < (int)n->args->argc; i++) { 4454a9f685fSschwarze argv = n->args->argv + i; 4466093755cSschwarze lt = LIST__NONE; 4474a9f685fSschwarze switch (argv->arg) { 4486093755cSschwarze /* Set list types. */ 44949aff9f8Sschwarze case MDOC_Bullet: 4506093755cSschwarze lt = LIST_bullet; 4516093755cSschwarze break; 45249aff9f8Sschwarze case MDOC_Dash: 4536093755cSschwarze lt = LIST_dash; 4546093755cSschwarze break; 45549aff9f8Sschwarze case MDOC_Enum: 4566093755cSschwarze lt = LIST_enum; 4576093755cSschwarze break; 45849aff9f8Sschwarze case MDOC_Hyphen: 4596093755cSschwarze lt = LIST_hyphen; 4606093755cSschwarze break; 46149aff9f8Sschwarze case MDOC_Item: 4626093755cSschwarze lt = LIST_item; 4636093755cSschwarze break; 46449aff9f8Sschwarze case MDOC_Tag: 4656093755cSschwarze lt = LIST_tag; 4666093755cSschwarze break; 46749aff9f8Sschwarze case MDOC_Diag: 4686093755cSschwarze lt = LIST_diag; 4696093755cSschwarze break; 47049aff9f8Sschwarze case MDOC_Hang: 4716093755cSschwarze lt = LIST_hang; 4726093755cSschwarze break; 47349aff9f8Sschwarze case MDOC_Ohang: 4746093755cSschwarze lt = LIST_ohang; 4756093755cSschwarze break; 47649aff9f8Sschwarze case MDOC_Inset: 4776093755cSschwarze lt = LIST_inset; 4786093755cSschwarze break; 47949aff9f8Sschwarze case MDOC_Column: 4806093755cSschwarze lt = LIST_column; 48164d728e4Sschwarze break; 4826093755cSschwarze /* Set list arguments. */ 48349aff9f8Sschwarze case MDOC_Compact: 4844a9f685fSschwarze if (n->norm->Bl.comp) 4854a9f685fSschwarze mandoc_msg(MANDOCERR_ARG_REP, 4864a9f685fSschwarze mdoc->parse, argv->line, 4874a9f685fSschwarze argv->pos, "Bl -compact"); 4884a9f685fSschwarze n->norm->Bl.comp = 1; 48950e63e03Sschwarze break; 49049aff9f8Sschwarze case MDOC_Width: 491aa99c14fSschwarze wa = argv; 4924a9f685fSschwarze if (0 == argv->sz) { 4934a9f685fSschwarze mandoc_msg(MANDOCERR_ARG_EMPTY, 4944a9f685fSschwarze mdoc->parse, argv->line, 4954a9f685fSschwarze argv->pos, "Bl -width"); 4964a9f685fSschwarze n->norm->Bl.width = "0n"; 49722972b14Sschwarze break; 49822972b14Sschwarze } 4994a9f685fSschwarze if (NULL != n->norm->Bl.width) 5004a9f685fSschwarze mandoc_vmsg(MANDOCERR_ARG_REP, 5014a9f685fSschwarze mdoc->parse, argv->line, 5024a9f685fSschwarze argv->pos, "Bl -width %s", 5034a9f685fSschwarze argv->value[0]); 50490d52a15Sschwarze rewrite_macro2len(argv->value); 5054a9f685fSschwarze n->norm->Bl.width = argv->value[0]; 50664d728e4Sschwarze break; 50749aff9f8Sschwarze case MDOC_Offset: 5084a9f685fSschwarze if (0 == argv->sz) { 5094a9f685fSschwarze mandoc_msg(MANDOCERR_ARG_EMPTY, 5104a9f685fSschwarze mdoc->parse, argv->line, 5114a9f685fSschwarze argv->pos, "Bl -offset"); 51231e23753Sschwarze break; 51331e23753Sschwarze } 5144a9f685fSschwarze if (NULL != n->norm->Bl.offs) 5154a9f685fSschwarze mandoc_vmsg(MANDOCERR_ARG_REP, 5164a9f685fSschwarze mdoc->parse, argv->line, 5174a9f685fSschwarze argv->pos, "Bl -offset %s", 5184a9f685fSschwarze argv->value[0]); 51990d52a15Sschwarze rewrite_macro2len(argv->value); 5204a9f685fSschwarze n->norm->Bl.offs = argv->value[0]; 521f73abda9Skristaps break; 522ddce0b0cSschwarze default: 523ddce0b0cSschwarze continue; 524f73abda9Skristaps } 525dc0d8bb2Sschwarze if (LIST__NONE == lt) 526dc0d8bb2Sschwarze continue; 527aa99c14fSschwarze mdoclt = argv->arg; 528f73abda9Skristaps 5296093755cSschwarze /* Check: multiple list types. */ 5306093755cSschwarze 531dc0d8bb2Sschwarze if (LIST__NONE != n->norm->Bl.type) { 532bd594191Sschwarze mandoc_vmsg(MANDOCERR_BL_REP, 533dc0d8bb2Sschwarze mdoc->parse, n->line, n->pos, 534bd594191Sschwarze "Bl -%s", mdoc_argnames[argv->arg]); 535dc0d8bb2Sschwarze continue; 536769ee804Sschwarze } 5376093755cSschwarze 5386093755cSschwarze /* The list type should come first. */ 5396093755cSschwarze 5408c62fbf5Sschwarze if (n->norm->Bl.width || 5418c62fbf5Sschwarze n->norm->Bl.offs || 5428c62fbf5Sschwarze n->norm->Bl.comp) 543bd594191Sschwarze mandoc_vmsg(MANDOCERR_BL_LATETYPE, 544bd594191Sschwarze mdoc->parse, n->line, n->pos, "Bl -%s", 54566788495Sschwarze mdoc_argnames[n->args->argv[0].arg]); 546dc0d8bb2Sschwarze 547dc0d8bb2Sschwarze n->norm->Bl.type = lt; 548dc0d8bb2Sschwarze if (LIST_column == lt) { 549dc0d8bb2Sschwarze n->norm->Bl.ncols = argv->sz; 550dc0d8bb2Sschwarze n->norm->Bl.cols = (void *)argv->value; 551dc0d8bb2Sschwarze } 5526093755cSschwarze } 5536093755cSschwarze 5546093755cSschwarze /* Allow lists to default to LIST_item. */ 5556093755cSschwarze 5568c62fbf5Sschwarze if (LIST__NONE == n->norm->Bl.type) { 557bd594191Sschwarze mandoc_msg(MANDOCERR_BL_NOTYPE, mdoc->parse, 558bd594191Sschwarze n->line, n->pos, "Bl"); 5598c62fbf5Sschwarze n->norm->Bl.type = LIST_item; 5606e03d529Sschwarze } 561f73abda9Skristaps 56264d728e4Sschwarze /* 56364d728e4Sschwarze * Validate the width field. Some list types don't need width 56464d728e4Sschwarze * types and should be warned about them. Others should have it 5655eced068Sschwarze * and must also be warned. Yet others have a default and need 5665eced068Sschwarze * no warning. 56764d728e4Sschwarze */ 56864d728e4Sschwarze 5698c62fbf5Sschwarze switch (n->norm->Bl.type) { 57049aff9f8Sschwarze case LIST_tag: 5715eced068Sschwarze if (NULL == n->norm->Bl.width) 572bd594191Sschwarze mandoc_msg(MANDOCERR_BL_NOWIDTH, mdoc->parse, 573bd594191Sschwarze n->line, n->pos, "Bl -tag"); 574f73abda9Skristaps break; 57549aff9f8Sschwarze case LIST_column: 5766093755cSschwarze /* FALLTHROUGH */ 57749aff9f8Sschwarze case LIST_diag: 5786093755cSschwarze /* FALLTHROUGH */ 57949aff9f8Sschwarze case LIST_ohang: 5806093755cSschwarze /* FALLTHROUGH */ 58149aff9f8Sschwarze case LIST_inset: 5826093755cSschwarze /* FALLTHROUGH */ 58349aff9f8Sschwarze case LIST_item: 5848c62fbf5Sschwarze if (n->norm->Bl.width) 585aa99c14fSschwarze mandoc_vmsg(MANDOCERR_BL_SKIPW, mdoc->parse, 586aa99c14fSschwarze wa->line, wa->pos, "Bl -%s", 587aa99c14fSschwarze mdoc_argnames[mdoclt]); 5886093755cSschwarze break; 58949aff9f8Sschwarze case LIST_bullet: 5905eced068Sschwarze /* FALLTHROUGH */ 59149aff9f8Sschwarze case LIST_dash: 5925eced068Sschwarze /* FALLTHROUGH */ 59349aff9f8Sschwarze case LIST_hyphen: 5945eced068Sschwarze if (NULL == n->norm->Bl.width) 5955eced068Sschwarze n->norm->Bl.width = "2n"; 5965eced068Sschwarze break; 59749aff9f8Sschwarze case LIST_enum: 5985eced068Sschwarze if (NULL == n->norm->Bl.width) 5995eced068Sschwarze n->norm->Bl.width = "3n"; 6005eced068Sschwarze break; 60164d728e4Sschwarze default: 602f73abda9Skristaps break; 60364d728e4Sschwarze } 60498b8f00aSschwarze pre_par(mdoc, n); 605f73abda9Skristaps } 606f73abda9Skristaps 60798b8f00aSschwarze static void 608f73abda9Skristaps pre_bd(PRE_ARGS) 609f73abda9Skristaps { 610769ee804Sschwarze struct mdoc_node *np; 6114a9f685fSschwarze struct mdoc_argv *argv; 6124a9f685fSschwarze int i; 6134a9f685fSschwarze enum mdoc_disp dt; 614f73abda9Skristaps 615d52d1586Sschwarze pre_literal(mdoc, n); 616d52d1586Sschwarze 61731e23753Sschwarze if (MDOC_BLOCK != n->type) { 618769ee804Sschwarze if (ENDBODY_NOT != n->end) { 619769ee804Sschwarze assert(n->pending); 620769ee804Sschwarze np = n->pending->parent; 621769ee804Sschwarze } else 622769ee804Sschwarze np = n->parent; 623769ee804Sschwarze 624769ee804Sschwarze assert(np); 625769ee804Sschwarze assert(MDOC_BLOCK == np->type); 626769ee804Sschwarze assert(MDOC_Bd == np->tok); 62798b8f00aSschwarze return; 6286e03d529Sschwarze } 629f73abda9Skristaps 63031e23753Sschwarze for (i = 0; n->args && i < (int)n->args->argc; i++) { 6314a9f685fSschwarze argv = n->args->argv + i; 63231e23753Sschwarze dt = DISP__NONE; 63331e23753Sschwarze 6344a9f685fSschwarze switch (argv->arg) { 63549aff9f8Sschwarze case MDOC_Centred: 6362065e47aSschwarze dt = DISP_centered; 63731e23753Sschwarze break; 63849aff9f8Sschwarze case MDOC_Ragged: 63931e23753Sschwarze dt = DISP_ragged; 64031e23753Sschwarze break; 64149aff9f8Sschwarze case MDOC_Unfilled: 64231e23753Sschwarze dt = DISP_unfilled; 64331e23753Sschwarze break; 64449aff9f8Sschwarze case MDOC_Filled: 64531e23753Sschwarze dt = DISP_filled; 64631e23753Sschwarze break; 64749aff9f8Sschwarze case MDOC_Literal: 64831e23753Sschwarze dt = DISP_literal; 649f73abda9Skristaps break; 65049aff9f8Sschwarze case MDOC_File: 651bd594191Sschwarze mandoc_msg(MANDOCERR_BD_FILE, mdoc->parse, 652bd594191Sschwarze n->line, n->pos, NULL); 6531164a325Sschwarze break; 65449aff9f8Sschwarze case MDOC_Offset: 6554a9f685fSschwarze if (0 == argv->sz) { 6564a9f685fSschwarze mandoc_msg(MANDOCERR_ARG_EMPTY, 6574a9f685fSschwarze mdoc->parse, argv->line, 6584a9f685fSschwarze argv->pos, "Bd -offset"); 659f73abda9Skristaps break; 660f73abda9Skristaps } 6614a9f685fSschwarze if (NULL != n->norm->Bd.offs) 6624a9f685fSschwarze mandoc_vmsg(MANDOCERR_ARG_REP, 6634a9f685fSschwarze mdoc->parse, argv->line, 6644a9f685fSschwarze argv->pos, "Bd -offset %s", 6654a9f685fSschwarze argv->value[0]); 66690d52a15Sschwarze rewrite_macro2len(argv->value); 6674a9f685fSschwarze n->norm->Bd.offs = argv->value[0]; 66831e23753Sschwarze break; 66949aff9f8Sschwarze case MDOC_Compact: 6704a9f685fSschwarze if (n->norm->Bd.comp) 6714a9f685fSschwarze mandoc_msg(MANDOCERR_ARG_REP, 6724a9f685fSschwarze mdoc->parse, argv->line, 6734a9f685fSschwarze argv->pos, "Bd -compact"); 6744a9f685fSschwarze n->norm->Bd.comp = 1; 67531e23753Sschwarze break; 67631e23753Sschwarze default: 67731e23753Sschwarze abort(); 67831e23753Sschwarze /* NOTREACHED */ 67931e23753Sschwarze } 680dc0d8bb2Sschwarze if (DISP__NONE == dt) 681dc0d8bb2Sschwarze continue; 68231e23753Sschwarze 683dc0d8bb2Sschwarze if (DISP__NONE == n->norm->Bd.type) 6848c62fbf5Sschwarze n->norm->Bd.type = dt; 685dc0d8bb2Sschwarze else 686bd594191Sschwarze mandoc_vmsg(MANDOCERR_BD_REP, 687dc0d8bb2Sschwarze mdoc->parse, n->line, n->pos, 688bd594191Sschwarze "Bd -%s", mdoc_argnames[argv->arg]); 68931e23753Sschwarze } 69031e23753Sschwarze 6918c62fbf5Sschwarze if (DISP__NONE == n->norm->Bd.type) { 692bd594191Sschwarze mandoc_msg(MANDOCERR_BD_NOTYPE, mdoc->parse, 693bd594191Sschwarze n->line, n->pos, "Bd"); 6948c62fbf5Sschwarze n->norm->Bd.type = DISP_ragged; 69531e23753Sschwarze } 69698b8f00aSschwarze pre_par(mdoc, n); 697f73abda9Skristaps } 698f73abda9Skristaps 69998b8f00aSschwarze static void 700f73abda9Skristaps pre_an(PRE_ARGS) 701f73abda9Skristaps { 702aa99c14fSschwarze struct mdoc_argv *argv; 703aa99c14fSschwarze size_t i; 704f73abda9Skristaps 705aa99c14fSschwarze if (n->args == NULL) 70698b8f00aSschwarze return; 707769ee804Sschwarze 708aa99c14fSschwarze for (i = 1; i < n->args->argc; i++) { 709aa99c14fSschwarze argv = n->args->argv + i; 710aa99c14fSschwarze mandoc_vmsg(MANDOCERR_AN_REP, 711aa99c14fSschwarze mdoc->parse, argv->line, argv->pos, 712aa99c14fSschwarze "An -%s", mdoc_argnames[argv->arg]); 713aa99c14fSschwarze } 7147c2be9f8Sschwarze 715aa99c14fSschwarze argv = n->args->argv; 716aa99c14fSschwarze if (argv->arg == MDOC_Split) 7178c62fbf5Sschwarze n->norm->An.auth = AUTH_split; 718aa99c14fSschwarze else if (argv->arg == MDOC_Nosplit) 7198c62fbf5Sschwarze n->norm->An.auth = AUTH_nosplit; 720769ee804Sschwarze else 721769ee804Sschwarze abort(); 722f73abda9Skristaps } 723f73abda9Skristaps 72498b8f00aSschwarze static void 72520fa2881Sschwarze pre_std(PRE_ARGS) 726f73abda9Skristaps { 727f73abda9Skristaps 72820fa2881Sschwarze if (n->args && 1 == n->args->argc) 72920fa2881Sschwarze if (MDOC_Std == n->args->argv[0].arg) 73098b8f00aSschwarze return; 731f73abda9Skristaps 73266788495Sschwarze mandoc_msg(MANDOCERR_ARG_STD, mdoc->parse, 73366788495Sschwarze n->line, n->pos, mdoc_macronames[n->tok]); 7346093755cSschwarze } 7356093755cSschwarze 73698b8f00aSschwarze static void 737551cd4a8Sschwarze pre_obsolete(PRE_ARGS) 738551cd4a8Sschwarze { 739551cd4a8Sschwarze 740551cd4a8Sschwarze if (MDOC_ELEM == n->type || MDOC_BLOCK == n->type) 741551cd4a8Sschwarze mandoc_msg(MANDOCERR_MACRO_OBS, mdoc->parse, 742551cd4a8Sschwarze n->line, n->pos, mdoc_macronames[n->tok]); 743551cd4a8Sschwarze } 744551cd4a8Sschwarze 74598b8f00aSschwarze static void 746f73abda9Skristaps pre_dt(PRE_ARGS) 747f73abda9Skristaps { 748f73abda9Skristaps 7493fdead0cSschwarze if (mdoc->meta.title != NULL) 75051fcab2fSschwarze mandoc_msg(MANDOCERR_PROLOG_REP, mdoc->parse, 75151fcab2fSschwarze n->line, n->pos, "Dt"); 7523fdead0cSschwarze else if (mdoc->meta.os != NULL) 7533fdead0cSschwarze mandoc_msg(MANDOCERR_PROLOG_ORDER, mdoc->parse, 7543fdead0cSschwarze n->line, n->pos, "Dt after Os"); 755f73abda9Skristaps } 756f73abda9Skristaps 75798b8f00aSschwarze static void 758f73abda9Skristaps pre_os(PRE_ARGS) 759f73abda9Skristaps { 760f73abda9Skristaps 7613fdead0cSschwarze if (mdoc->meta.os != NULL) 76251fcab2fSschwarze mandoc_msg(MANDOCERR_PROLOG_REP, mdoc->parse, 76351fcab2fSschwarze n->line, n->pos, "Os"); 7643fdead0cSschwarze else if (mdoc->flags & MDOC_PBODY) 7653fdead0cSschwarze mandoc_msg(MANDOCERR_PROLOG_LATE, mdoc->parse, 7663fdead0cSschwarze n->line, n->pos, "Os"); 767f73abda9Skristaps } 768f73abda9Skristaps 76998b8f00aSschwarze static void 770f73abda9Skristaps pre_dd(PRE_ARGS) 771f73abda9Skristaps { 772f73abda9Skristaps 7733fdead0cSschwarze if (mdoc->meta.date != NULL) 77451fcab2fSschwarze mandoc_msg(MANDOCERR_PROLOG_REP, mdoc->parse, 77551fcab2fSschwarze n->line, n->pos, "Dd"); 7763fdead0cSschwarze else if (mdoc->flags & MDOC_PBODY) 7773fdead0cSschwarze mandoc_msg(MANDOCERR_PROLOG_LATE, mdoc->parse, 7783fdead0cSschwarze n->line, n->pos, "Dd"); 7793fdead0cSschwarze else if (mdoc->meta.title != NULL) 7803fdead0cSschwarze mandoc_msg(MANDOCERR_PROLOG_ORDER, mdoc->parse, 7813fdead0cSschwarze n->line, n->pos, "Dd after Dt"); 7823fdead0cSschwarze else if (mdoc->meta.os != NULL) 7833fdead0cSschwarze mandoc_msg(MANDOCERR_PROLOG_ORDER, mdoc->parse, 7843fdead0cSschwarze n->line, n->pos, "Dd after Os"); 785f73abda9Skristaps } 786f73abda9Skristaps 78798b8f00aSschwarze static void 788f73abda9Skristaps post_bf(POST_ARGS) 789f73abda9Skristaps { 790ecb10c32Sschwarze struct mdoc_node *np, *nch; 791ddce0b0cSschwarze enum mdocargt arg; 792f73abda9Skristaps 793769ee804Sschwarze /* 794769ee804Sschwarze * Unlike other data pointers, these are "housed" by the HEAD 795769ee804Sschwarze * element, which contains the goods. 796769ee804Sschwarze */ 797769ee804Sschwarze 798769ee804Sschwarze if (MDOC_HEAD != mdoc->last->type) { 799769ee804Sschwarze if (ENDBODY_NOT != mdoc->last->end) { 800769ee804Sschwarze assert(mdoc->last->pending); 801769ee804Sschwarze np = mdoc->last->pending->parent->head; 802769ee804Sschwarze } else if (MDOC_BLOCK != mdoc->last->type) { 803769ee804Sschwarze np = mdoc->last->parent->head; 804769ee804Sschwarze } else 805769ee804Sschwarze np = mdoc->last->head; 806769ee804Sschwarze 807769ee804Sschwarze assert(np); 808769ee804Sschwarze assert(MDOC_HEAD == np->type); 809769ee804Sschwarze assert(MDOC_Bf == np->tok); 81098b8f00aSschwarze return; 8116e03d529Sschwarze } 812f73abda9Skristaps 813769ee804Sschwarze np = mdoc->last; 814769ee804Sschwarze assert(MDOC_BLOCK == np->parent->type); 815769ee804Sschwarze assert(MDOC_Bf == np->parent->tok); 81650d41253Sschwarze 817ecb10c32Sschwarze /* Check the number of arguments. */ 818f73abda9Skristaps 819ecb10c32Sschwarze nch = np->child; 820ecb10c32Sschwarze if (NULL == np->parent->args) { 821ecb10c32Sschwarze if (NULL == nch) { 822bd594191Sschwarze mandoc_msg(MANDOCERR_BF_NOFONT, mdoc->parse, 823bd594191Sschwarze np->line, np->pos, "Bf"); 82498b8f00aSschwarze return; 82520fa2881Sschwarze } 826ecb10c32Sschwarze nch = nch->next; 827ecb10c32Sschwarze } 828ecb10c32Sschwarze if (NULL != nch) 829ecb10c32Sschwarze mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse, 830ecb10c32Sschwarze nch->line, nch->pos, "Bf ... %s", nch->string); 831769ee804Sschwarze 832769ee804Sschwarze /* Extract argument into data. */ 833769ee804Sschwarze 834769ee804Sschwarze if (np->parent->args) { 835769ee804Sschwarze arg = np->parent->args->argv[0].arg; 836769ee804Sschwarze if (MDOC_Emphasis == arg) 8378c62fbf5Sschwarze np->norm->Bf.font = FONT_Em; 838769ee804Sschwarze else if (MDOC_Literal == arg) 8398c62fbf5Sschwarze np->norm->Bf.font = FONT_Li; 840769ee804Sschwarze else if (MDOC_Symbolic == arg) 8418c62fbf5Sschwarze np->norm->Bf.font = FONT_Sy; 842769ee804Sschwarze else 843769ee804Sschwarze abort(); 84498b8f00aSschwarze return; 845769ee804Sschwarze } 846769ee804Sschwarze 847769ee804Sschwarze /* Extract parameter into data. */ 848769ee804Sschwarze 849769ee804Sschwarze if (0 == strcmp(np->child->string, "Em")) 8508c62fbf5Sschwarze np->norm->Bf.font = FONT_Em; 851769ee804Sschwarze else if (0 == strcmp(np->child->string, "Li")) 8528c62fbf5Sschwarze np->norm->Bf.font = FONT_Li; 853769ee804Sschwarze else if (0 == strcmp(np->child->string, "Sy")) 8548c62fbf5Sschwarze np->norm->Bf.font = FONT_Sy; 85520fa2881Sschwarze else 856ecb10c32Sschwarze mandoc_vmsg(MANDOCERR_BF_BADFONT, mdoc->parse, 857ecb10c32Sschwarze np->child->line, np->child->pos, 858ecb10c32Sschwarze "Bf %s", np->child->string); 859f73abda9Skristaps } 860f73abda9Skristaps 86198b8f00aSschwarze static void 86271719887Sschwarze post_lb(POST_ARGS) 86371719887Sschwarze { 86477e000ffSschwarze struct mdoc_node *n; 86577e000ffSschwarze char *libname; 86671719887Sschwarze 86777e000ffSschwarze n = mdoc->last->child; 86877e000ffSschwarze assert(MDOC_TEXT == n->type); 869aaad0dcfSschwarze mandoc_asprintf(&libname, "library \\(lq%s\\(rq", n->string); 87077e000ffSschwarze free(n->string); 87177e000ffSschwarze n->string = libname; 87220fa2881Sschwarze } 87371719887Sschwarze 87498b8f00aSschwarze static void 875b31af00dSschwarze post_eoln(POST_ARGS) 876b31af00dSschwarze { 877ecb10c32Sschwarze const struct mdoc_node *n; 878b31af00dSschwarze 879ecb10c32Sschwarze n = mdoc->last; 880ecb10c32Sschwarze if (n->child) 881ecb10c32Sschwarze mandoc_vmsg(MANDOCERR_ARG_SKIP, 882ecb10c32Sschwarze mdoc->parse, n->line, n->pos, 883ecb10c32Sschwarze "%s %s", mdoc_macronames[n->tok], 884ecb10c32Sschwarze n->child->string); 885b31af00dSschwarze } 886b31af00dSschwarze 88798b8f00aSschwarze static void 8880c5064e3Sschwarze post_fname(POST_ARGS) 8890c5064e3Sschwarze { 8900c5064e3Sschwarze const struct mdoc_node *n; 8910ff14c71Sschwarze const char *cp; 8920c5064e3Sschwarze size_t pos; 8930c5064e3Sschwarze 8940c5064e3Sschwarze n = mdoc->last->child; 8950c5064e3Sschwarze pos = strcspn(n->string, "()"); 8960ff14c71Sschwarze cp = n->string + pos; 8970ff14c71Sschwarze if ( ! (cp[0] == '\0' || (cp[0] == '(' && cp[1] == '*'))) 8980c5064e3Sschwarze mandoc_msg(MANDOCERR_FN_PAREN, mdoc->parse, 8990c5064e3Sschwarze n->line, n->pos + pos, n->string); 9000c5064e3Sschwarze } 9010c5064e3Sschwarze 90298b8f00aSschwarze static void 9030c5064e3Sschwarze post_fn(POST_ARGS) 9040c5064e3Sschwarze { 9050c5064e3Sschwarze 9060c5064e3Sschwarze post_fname(mdoc); 9070c5064e3Sschwarze post_fa(mdoc); 9080c5064e3Sschwarze } 9090c5064e3Sschwarze 91098b8f00aSschwarze static void 911753701eeSschwarze post_fo(POST_ARGS) 912753701eeSschwarze { 913afcd1f03Sschwarze const struct mdoc_node *n; 914753701eeSschwarze 915afcd1f03Sschwarze n = mdoc->last; 916afcd1f03Sschwarze 917afcd1f03Sschwarze if (n->type != MDOC_HEAD) 918afcd1f03Sschwarze return; 919afcd1f03Sschwarze 920afcd1f03Sschwarze if (n->child == NULL) { 921afcd1f03Sschwarze mandoc_msg(MANDOCERR_FO_NOHEAD, mdoc->parse, 922afcd1f03Sschwarze n->line, n->pos, "Fo"); 923afcd1f03Sschwarze return; 924afcd1f03Sschwarze } 925afcd1f03Sschwarze if (n->child != n->last) { 926afcd1f03Sschwarze mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse, 927afcd1f03Sschwarze n->child->next->line, n->child->next->pos, 928afcd1f03Sschwarze "Fo ... %s", n->child->next->string); 929afcd1f03Sschwarze while (n->child != n->last) 930afcd1f03Sschwarze mdoc_node_delete(mdoc, n->last); 931afcd1f03Sschwarze } 932afcd1f03Sschwarze 9330c5064e3Sschwarze post_fname(mdoc); 934753701eeSschwarze } 935753701eeSschwarze 93698b8f00aSschwarze static void 9377e92c062Sschwarze post_fa(POST_ARGS) 9387e92c062Sschwarze { 9397e92c062Sschwarze const struct mdoc_node *n; 9407e92c062Sschwarze const char *cp; 9417e92c062Sschwarze 9427e92c062Sschwarze for (n = mdoc->last->child; n != NULL; n = n->next) { 9437e92c062Sschwarze for (cp = n->string; *cp != '\0'; cp++) { 9447e92c062Sschwarze /* Ignore callbacks and alterations. */ 9457e92c062Sschwarze if (*cp == '(' || *cp == '{') 9467e92c062Sschwarze break; 9477e92c062Sschwarze if (*cp != ',') 9487e92c062Sschwarze continue; 9497e92c062Sschwarze mandoc_msg(MANDOCERR_FA_COMMA, mdoc->parse, 9507e92c062Sschwarze n->line, n->pos + (cp - n->string), 9517e92c062Sschwarze n->string); 9527e92c062Sschwarze break; 9537e92c062Sschwarze } 9547e92c062Sschwarze } 9557e92c062Sschwarze } 9567e92c062Sschwarze 95798b8f00aSschwarze static void 9588521b0bcSschwarze post_vt(POST_ARGS) 9598521b0bcSschwarze { 9608521b0bcSschwarze const struct mdoc_node *n; 9618521b0bcSschwarze 9628521b0bcSschwarze /* 9638521b0bcSschwarze * The Vt macro comes in both ELEM and BLOCK form, both of which 9648521b0bcSschwarze * have different syntaxes (yet more context-sensitive 965e7a93ef3Sschwarze * behaviour). ELEM types must have a child, which is already 966e7a93ef3Sschwarze * guaranteed by the in_line parsing routine; BLOCK types, 9678521b0bcSschwarze * specifically the BODY, should only have TEXT children. 9688521b0bcSschwarze */ 9698521b0bcSschwarze 9708521b0bcSschwarze if (MDOC_BODY != mdoc->last->type) 97198b8f00aSschwarze return; 9728521b0bcSschwarze 9738521b0bcSschwarze for (n = mdoc->last->child; n; n = n->next) 974bc49dbe1Sschwarze if (MDOC_TEXT != n->type) 975dd25b57cSschwarze mandoc_msg(MANDOCERR_VT_CHILD, mdoc->parse, 976dd25b57cSschwarze n->line, n->pos, mdoc_macronames[n->tok]); 9778521b0bcSschwarze } 9788521b0bcSschwarze 97998b8f00aSschwarze static void 980f73abda9Skristaps post_nm(POST_ARGS) 981f73abda9Skristaps { 9822d266539Sschwarze struct mdoc_node *n; 9832d266539Sschwarze 9842d266539Sschwarze n = mdoc->last; 9852d266539Sschwarze 9862d266539Sschwarze if (n->last != NULL && 9872d266539Sschwarze (n->last->tok == MDOC_Pp || 9882d266539Sschwarze n->last->tok == MDOC_Lp)) 9892d266539Sschwarze mdoc_node_relink(mdoc, n->last); 99020fa2881Sschwarze 991160ac481Sschwarze if (NULL != mdoc->meta.name) 99298b8f00aSschwarze return; 99320fa2881Sschwarze 9942d266539Sschwarze mdoc_deroff(&mdoc->meta.name, n); 99520fa2881Sschwarze 996e214f641Sschwarze if (NULL == mdoc->meta.name) 997bd594191Sschwarze mandoc_msg(MANDOCERR_NM_NONAME, mdoc->parse, 9982d266539Sschwarze n->line, n->pos, "Nm"); 99920fa2881Sschwarze } 100020fa2881Sschwarze 100198b8f00aSschwarze static void 1002753701eeSschwarze post_nd(POST_ARGS) 1003753701eeSschwarze { 10041570daf1Sschwarze struct mdoc_node *n; 1005753701eeSschwarze 10061570daf1Sschwarze n = mdoc->last; 10071570daf1Sschwarze 10081570daf1Sschwarze if (n->type != MDOC_BODY) 10091570daf1Sschwarze return; 10101570daf1Sschwarze 10111570daf1Sschwarze if (n->child == NULL) 10121570daf1Sschwarze mandoc_msg(MANDOCERR_ND_EMPTY, mdoc->parse, 10131570daf1Sschwarze n->line, n->pos, "Nd"); 10141570daf1Sschwarze 101598b8f00aSschwarze post_hyph(mdoc); 1016753701eeSschwarze } 1017753701eeSschwarze 101898b8f00aSschwarze static void 1019753701eeSschwarze post_d1(POST_ARGS) 1020753701eeSschwarze { 1021b7530f2fSschwarze struct mdoc_node *n; 1022753701eeSschwarze 1023b7530f2fSschwarze n = mdoc->last; 1024b7530f2fSschwarze 1025b7530f2fSschwarze if (n->type != MDOC_BODY) 1026b7530f2fSschwarze return; 1027b7530f2fSschwarze 1028b7530f2fSschwarze if (n->child == NULL) 1029*1d0823adSschwarze mandoc_msg(MANDOCERR_BLK_EMPTY, mdoc->parse, 1030b7530f2fSschwarze n->line, n->pos, "D1"); 1031b7530f2fSschwarze 103298b8f00aSschwarze post_hyph(mdoc); 1033753701eeSschwarze } 1034753701eeSschwarze 103598b8f00aSschwarze static void 103620fa2881Sschwarze post_literal(POST_ARGS) 103720fa2881Sschwarze { 1038b7530f2fSschwarze struct mdoc_node *n; 103920fa2881Sschwarze 1040b7530f2fSschwarze n = mdoc->last; 1041753701eeSschwarze 1042b7530f2fSschwarze if (n->type != MDOC_BODY) 1043b7530f2fSschwarze return; 104420fa2881Sschwarze 1045b7530f2fSschwarze if (n->child == NULL) 1046*1d0823adSschwarze mandoc_msg(MANDOCERR_BLK_EMPTY, mdoc->parse, 1047b7530f2fSschwarze n->line, n->pos, mdoc_macronames[n->tok]); 1048b7530f2fSschwarze 1049b7530f2fSschwarze if (n->tok == MDOC_Bd && 1050b7530f2fSschwarze n->norm->Bd.type != DISP_literal && 1051b7530f2fSschwarze n->norm->Bd.type != DISP_unfilled) 1052b7530f2fSschwarze return; 1053b7530f2fSschwarze 105420fa2881Sschwarze mdoc->flags &= ~MDOC_LITERAL; 105520fa2881Sschwarze } 105620fa2881Sschwarze 105798b8f00aSschwarze static void 105820fa2881Sschwarze post_defaults(POST_ARGS) 105920fa2881Sschwarze { 106020fa2881Sschwarze struct mdoc_node *nn; 106120fa2881Sschwarze 106220fa2881Sschwarze /* 106320fa2881Sschwarze * The `Ar' defaults to "file ..." if no value is provided as an 106420fa2881Sschwarze * argument; the `Mt' and `Pa' macros use "~"; the `Li' just 106520fa2881Sschwarze * gets an empty string. 106620fa2881Sschwarze */ 1067f73abda9Skristaps 1068f73abda9Skristaps if (mdoc->last->child) 106998b8f00aSschwarze return; 107020fa2881Sschwarze 107120fa2881Sschwarze nn = mdoc->last; 107220fa2881Sschwarze mdoc->next = MDOC_NEXT_CHILD; 107320fa2881Sschwarze 107420fa2881Sschwarze switch (nn->tok) { 107549aff9f8Sschwarze case MDOC_Ar: 107698b8f00aSschwarze mdoc_word_alloc(mdoc, nn->line, nn->pos, "file"); 107798b8f00aSschwarze mdoc_word_alloc(mdoc, nn->line, nn->pos, "..."); 107820fa2881Sschwarze break; 107949aff9f8Sschwarze case MDOC_Pa: 108020fa2881Sschwarze /* FALLTHROUGH */ 108149aff9f8Sschwarze case MDOC_Mt: 108298b8f00aSschwarze mdoc_word_alloc(mdoc, nn->line, nn->pos, "~"); 108320fa2881Sschwarze break; 108420fa2881Sschwarze default: 108520fa2881Sschwarze abort(); 108620fa2881Sschwarze /* NOTREACHED */ 1087f73abda9Skristaps } 108820fa2881Sschwarze mdoc->last = nn; 108920fa2881Sschwarze } 1090f73abda9Skristaps 109198b8f00aSschwarze static void 1092f73abda9Skristaps post_at(POST_ARGS) 1093f73abda9Skristaps { 10940b2f1307Sschwarze struct mdoc_node *n; 10950b2f1307Sschwarze const char *std_att; 10960b2f1307Sschwarze char *att; 109720fa2881Sschwarze 1098753701eeSschwarze n = mdoc->last; 1099753701eeSschwarze if (n->child == NULL) { 1100753701eeSschwarze mdoc->next = MDOC_NEXT_CHILD; 110198b8f00aSschwarze mdoc_word_alloc(mdoc, n->line, n->pos, "AT&T UNIX"); 1102753701eeSschwarze mdoc->last = n; 110398b8f00aSschwarze return; 1104753701eeSschwarze } 1105753701eeSschwarze 110620fa2881Sschwarze /* 110720fa2881Sschwarze * If we have a child, look it up in the standard keys. If a 110820fa2881Sschwarze * key exist, use that instead of the child; if it doesn't, 110920fa2881Sschwarze * prefix "AT&T UNIX " to the existing data. 111020fa2881Sschwarze */ 1111f73abda9Skristaps 1112753701eeSschwarze n = n->child; 11130b2f1307Sschwarze assert(MDOC_TEXT == n->type); 11140b2f1307Sschwarze if (NULL == (std_att = mdoc_a2att(n->string))) { 1115bd594191Sschwarze mandoc_vmsg(MANDOCERR_AT_BAD, mdoc->parse, 1116bd594191Sschwarze n->line, n->pos, "At %s", n->string); 11170b2f1307Sschwarze mandoc_asprintf(&att, "AT&T UNIX %s", n->string); 11180b2f1307Sschwarze } else 11190b2f1307Sschwarze att = mandoc_strdup(std_att); 1120f73abda9Skristaps 11210b2f1307Sschwarze free(n->string); 11220b2f1307Sschwarze n->string = att; 112320fa2881Sschwarze } 1124f73abda9Skristaps 112598b8f00aSschwarze static void 1126f73abda9Skristaps post_an(POST_ARGS) 1127f73abda9Skristaps { 11283798fb25Sschwarze struct mdoc_node *np, *nch; 1129f73abda9Skristaps 1130769ee804Sschwarze np = mdoc->last; 1131cba50636Sschwarze nch = np->child; 1132cba50636Sschwarze if (np->norm->An.auth == AUTH__NONE) { 1133cba50636Sschwarze if (nch == NULL) 1134cba50636Sschwarze mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse, 1135cba50636Sschwarze np->line, np->pos, "An"); 1136cba50636Sschwarze } else if (nch != NULL) 11373798fb25Sschwarze mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse, 11383798fb25Sschwarze nch->line, nch->pos, "An ... %s", nch->string); 1139f73abda9Skristaps } 1140f73abda9Skristaps 114198b8f00aSschwarze static void 1142551cd4a8Sschwarze post_en(POST_ARGS) 1143551cd4a8Sschwarze { 1144551cd4a8Sschwarze 1145551cd4a8Sschwarze if (MDOC_BLOCK == mdoc->last->type) 1146551cd4a8Sschwarze mdoc->last->norm->Es = mdoc->last_es; 1147551cd4a8Sschwarze } 1148551cd4a8Sschwarze 114998b8f00aSschwarze static void 1150551cd4a8Sschwarze post_es(POST_ARGS) 1151551cd4a8Sschwarze { 1152551cd4a8Sschwarze 1153551cd4a8Sschwarze mdoc->last_es = mdoc->last; 1154551cd4a8Sschwarze } 1155551cd4a8Sschwarze 115698b8f00aSschwarze static void 1157f73abda9Skristaps post_it(POST_ARGS) 1158f73abda9Skristaps { 115919a69263Sschwarze int i, cols; 11606093755cSschwarze enum mdoc_list lt; 11619530682eSschwarze struct mdoc_node *nbl, *nit, *nch; 1162f73abda9Skristaps 11639530682eSschwarze nit = mdoc->last; 1164d26e35c2Sschwarze if (nit->type != MDOC_BLOCK) 116598b8f00aSschwarze return; 1166f73abda9Skristaps 11679530682eSschwarze nbl = nit->parent->parent; 11689530682eSschwarze lt = nbl->norm->Bl.type; 11696093755cSschwarze 11706093755cSschwarze switch (lt) { 117149aff9f8Sschwarze case LIST_tag: 11729530682eSschwarze /* FALLTHROUGH */ 117349aff9f8Sschwarze case LIST_hang: 1174f73abda9Skristaps /* FALLTHROUGH */ 117549aff9f8Sschwarze case LIST_ohang: 1176f73abda9Skristaps /* FALLTHROUGH */ 117749aff9f8Sschwarze case LIST_inset: 1178f73abda9Skristaps /* FALLTHROUGH */ 117949aff9f8Sschwarze case LIST_diag: 1180d26e35c2Sschwarze if (nit->head->child == NULL) 1181bd594191Sschwarze mandoc_vmsg(MANDOCERR_IT_NOHEAD, 11829530682eSschwarze mdoc->parse, nit->line, nit->pos, 1183bd594191Sschwarze "Bl -%s It", 11849530682eSschwarze mdoc_argnames[nbl->args->argv[0].arg]); 1185f73abda9Skristaps break; 118649aff9f8Sschwarze case LIST_bullet: 1187f73abda9Skristaps /* FALLTHROUGH */ 118849aff9f8Sschwarze case LIST_dash: 1189f73abda9Skristaps /* FALLTHROUGH */ 119049aff9f8Sschwarze case LIST_enum: 1191f73abda9Skristaps /* FALLTHROUGH */ 119249aff9f8Sschwarze case LIST_hyphen: 1193d26e35c2Sschwarze if (nit->body == NULL || nit->body->child == NULL) 1194bd594191Sschwarze mandoc_vmsg(MANDOCERR_IT_NOBODY, 119566788495Sschwarze mdoc->parse, nit->line, nit->pos, 1196bd594191Sschwarze "Bl -%s It", 119766788495Sschwarze mdoc_argnames[nbl->args->argv[0].arg]); 1198f73abda9Skristaps /* FALLTHROUGH */ 119949aff9f8Sschwarze case LIST_item: 1200d26e35c2Sschwarze if (nit->head->child != NULL) 1201ecb10c32Sschwarze mandoc_vmsg(MANDOCERR_ARG_SKIP, 1202ecb10c32Sschwarze mdoc->parse, nit->line, nit->pos, 1203ecb10c32Sschwarze "It %s", nit->head->child->string); 1204f73abda9Skristaps break; 120549aff9f8Sschwarze case LIST_column: 12069530682eSschwarze cols = (int)nbl->norm->Bl.ncols; 12076093755cSschwarze 1208d26e35c2Sschwarze assert(nit->head->child == NULL); 12096093755cSschwarze 12109530682eSschwarze for (i = 0, nch = nit->child; nch; nch = nch->next) 1211d26e35c2Sschwarze if (nch->type == MDOC_BODY) 1212f73abda9Skristaps i++; 121353292e81Sschwarze 1214e14c4c11Sschwarze if (i < cols || i > cols + 1) 1215e14c4c11Sschwarze mandoc_vmsg(MANDOCERR_ARGCOUNT, 1216e14c4c11Sschwarze mdoc->parse, nit->line, nit->pos, 12176e03d529Sschwarze "columns == %d (have %d)", cols, i); 1218e14c4c11Sschwarze break; 1219f73abda9Skristaps default: 122066788495Sschwarze abort(); 1221f73abda9Skristaps } 1222f73abda9Skristaps } 1223f73abda9Skristaps 122498b8f00aSschwarze static void 122520fa2881Sschwarze post_bl_block(POST_ARGS) 122620fa2881Sschwarze { 1227bb99f0faSschwarze struct mdoc_node *n, *ni, *nc; 122820fa2881Sschwarze 122920fa2881Sschwarze /* 123020fa2881Sschwarze * These are fairly complicated, so we've broken them into two 123120fa2881Sschwarze * functions. post_bl_block_tag() is called when a -tag is 123220fa2881Sschwarze * specified, but no -width (it must be guessed). The second 123320fa2881Sschwarze * when a -width is specified (macro indicators must be 123420fa2881Sschwarze * rewritten into real lengths). 123520fa2881Sschwarze */ 123620fa2881Sschwarze 123720fa2881Sschwarze n = mdoc->last; 123820fa2881Sschwarze 12398c62fbf5Sschwarze if (LIST_tag == n->norm->Bl.type && 12408c62fbf5Sschwarze NULL == n->norm->Bl.width) { 124198b8f00aSschwarze post_bl_block_tag(mdoc); 1242bb99f0faSschwarze assert(n->norm->Bl.width); 1243bb99f0faSschwarze } 1244bb99f0faSschwarze 1245bb99f0faSschwarze for (ni = n->body->child; ni; ni = ni->next) { 1246bb99f0faSschwarze if (NULL == ni->body) 1247bb99f0faSschwarze continue; 1248bb99f0faSschwarze nc = ni->body->last; 1249bb99f0faSschwarze while (NULL != nc) { 1250bb99f0faSschwarze switch (nc->tok) { 125149aff9f8Sschwarze case MDOC_Pp: 1252bb99f0faSschwarze /* FALLTHROUGH */ 125349aff9f8Sschwarze case MDOC_Lp: 1254bb99f0faSschwarze /* FALLTHROUGH */ 125549aff9f8Sschwarze case MDOC_br: 1256bb99f0faSschwarze break; 1257bb99f0faSschwarze default: 1258bb99f0faSschwarze nc = NULL; 1259bb99f0faSschwarze continue; 1260bb99f0faSschwarze } 1261bb99f0faSschwarze if (NULL == ni->next) { 126220369664Sschwarze mandoc_msg(MANDOCERR_PAR_MOVE, 126320369664Sschwarze mdoc->parse, nc->line, nc->pos, 126420369664Sschwarze mdoc_macronames[nc->tok]); 126598b8f00aSschwarze mdoc_node_relink(mdoc, nc); 1266bb99f0faSschwarze } else if (0 == n->norm->Bl.comp && 1267bb99f0faSschwarze LIST_column != n->norm->Bl.type) { 126820369664Sschwarze mandoc_vmsg(MANDOCERR_PAR_SKIP, 126920369664Sschwarze mdoc->parse, nc->line, nc->pos, 127020369664Sschwarze "%s before It", 127120369664Sschwarze mdoc_macronames[nc->tok]); 1272bb99f0faSschwarze mdoc_node_delete(mdoc, nc); 1273bb99f0faSschwarze } else 1274bb99f0faSschwarze break; 1275bb99f0faSschwarze nc = ni->body->last; 1276bb99f0faSschwarze } 1277bb99f0faSschwarze } 127820fa2881Sschwarze } 127920fa2881Sschwarze 128090d52a15Sschwarze /* 128190d52a15Sschwarze * If the argument of -offset or -width is a macro, 128290d52a15Sschwarze * replace it with the associated default width. 128390d52a15Sschwarze */ 128490d52a15Sschwarze void 128590d52a15Sschwarze rewrite_macro2len(char **arg) 128620fa2881Sschwarze { 128720fa2881Sschwarze size_t width; 128820fa2881Sschwarze enum mdoct tok; 128920fa2881Sschwarze 129090d52a15Sschwarze if (*arg == NULL) 129190d52a15Sschwarze return; 129290d52a15Sschwarze else if ( ! strcmp(*arg, "Ds")) 129320fa2881Sschwarze width = 6; 129490d52a15Sschwarze else if ((tok = mdoc_hash_find(*arg)) == MDOC_MAX) 129590d52a15Sschwarze return; 1296dc0d8bb2Sschwarze else 1297dc0d8bb2Sschwarze width = macro2len(tok); 129820fa2881Sschwarze 129990d52a15Sschwarze free(*arg); 130090d52a15Sschwarze mandoc_asprintf(arg, "%zun", width); 130120fa2881Sschwarze } 130220fa2881Sschwarze 130398b8f00aSschwarze static void 130420fa2881Sschwarze post_bl_block_tag(POST_ARGS) 130520fa2881Sschwarze { 130620fa2881Sschwarze struct mdoc_node *n, *nn; 130720fa2881Sschwarze size_t sz, ssz; 130820fa2881Sschwarze int i; 130947813146Sschwarze char buf[24]; 131020fa2881Sschwarze 131120fa2881Sschwarze /* 131220fa2881Sschwarze * Calculate the -width for a `Bl -tag' list if it hasn't been 131320fa2881Sschwarze * provided. Uses the first head macro. NOTE AGAIN: this is 131420fa2881Sschwarze * ONLY if the -width argument has NOT been provided. See 131590d52a15Sschwarze * rewrite_macro2len() for converting the -width string. 131620fa2881Sschwarze */ 131720fa2881Sschwarze 131820fa2881Sschwarze sz = 10; 131920fa2881Sschwarze n = mdoc->last; 132020fa2881Sschwarze 132120fa2881Sschwarze for (nn = n->body->child; nn; nn = nn->next) { 132220fa2881Sschwarze if (MDOC_It != nn->tok) 132320fa2881Sschwarze continue; 132420fa2881Sschwarze 132520fa2881Sschwarze assert(MDOC_BLOCK == nn->type); 132620fa2881Sschwarze nn = nn->head->child; 132720fa2881Sschwarze 132820fa2881Sschwarze if (nn == NULL) 132920fa2881Sschwarze break; 133020fa2881Sschwarze 133120fa2881Sschwarze if (MDOC_TEXT == nn->type) { 133220fa2881Sschwarze sz = strlen(nn->string) + 1; 133320fa2881Sschwarze break; 133420fa2881Sschwarze } 133520fa2881Sschwarze 133619a69263Sschwarze if (0 != (ssz = macro2len(nn->tok))) 133720fa2881Sschwarze sz = ssz; 133820fa2881Sschwarze 133920fa2881Sschwarze break; 134020fa2881Sschwarze } 134120fa2881Sschwarze 134220fa2881Sschwarze /* Defaults to ten ens. */ 134320fa2881Sschwarze 134447813146Sschwarze (void)snprintf(buf, sizeof(buf), "%un", (unsigned int)sz); 134520fa2881Sschwarze 134620fa2881Sschwarze /* 134720fa2881Sschwarze * We have to dynamically add this to the macro's argument list. 134820fa2881Sschwarze * We're guaranteed that a MDOC_Width doesn't already exist. 134920fa2881Sschwarze */ 135020fa2881Sschwarze 135120fa2881Sschwarze assert(n->args); 135220fa2881Sschwarze i = (int)(n->args->argc)++; 135320fa2881Sschwarze 13548286bf36Sschwarze n->args->argv = mandoc_reallocarray(n->args->argv, 13558286bf36Sschwarze n->args->argc, sizeof(struct mdoc_argv)); 135620fa2881Sschwarze 135720fa2881Sschwarze n->args->argv[i].arg = MDOC_Width; 135820fa2881Sschwarze n->args->argv[i].line = n->line; 135920fa2881Sschwarze n->args->argv[i].pos = n->pos; 136020fa2881Sschwarze n->args->argv[i].sz = 1; 136120fa2881Sschwarze n->args->argv[i].value = mandoc_malloc(sizeof(char *)); 136220fa2881Sschwarze n->args->argv[i].value[0] = mandoc_strdup(buf); 136320fa2881Sschwarze 136420fa2881Sschwarze /* Set our width! */ 13658c62fbf5Sschwarze n->norm->Bl.width = n->args->argv[i].value[0]; 136620fa2881Sschwarze } 136720fa2881Sschwarze 136898b8f00aSschwarze static void 1369395185ccSschwarze post_bl_head(POST_ARGS) 1370395185ccSschwarze { 13712588c917Sschwarze struct mdoc_node *nbl, *nh, *nch, *nnext; 1372f5174743Sschwarze struct mdoc_argv *argv; 137320fa2881Sschwarze int i, j; 1374395185ccSschwarze 13752588c917Sschwarze nh = mdoc->last; 13762588c917Sschwarze 13772588c917Sschwarze if (nh->norm->Bl.type != LIST_column) { 13782588c917Sschwarze if ((nch = nh->child) == NULL) 13792588c917Sschwarze return; 13802588c917Sschwarze mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse, 13812588c917Sschwarze nch->line, nch->pos, "Bl ... %s", nch->string); 13822588c917Sschwarze while (nch != NULL) { 13832588c917Sschwarze mdoc_node_delete(mdoc, nch); 13842588c917Sschwarze nch = nh->child; 13852588c917Sschwarze } 138698b8f00aSschwarze return; 138798b8f00aSschwarze } 1388395185ccSschwarze 138920fa2881Sschwarze /* 1390f5174743Sschwarze * Append old-style lists, where the column width specifiers 139120fa2881Sschwarze * trail as macro parameters, to the new-style ("normal-form") 139220fa2881Sschwarze * lists where they're argument values following -column. 139320fa2881Sschwarze */ 139420fa2881Sschwarze 13952588c917Sschwarze if (nh->child == NULL) 139698b8f00aSschwarze return; 139720fa2881Sschwarze 13982588c917Sschwarze nbl = nh->parent; 13992588c917Sschwarze for (j = 0; j < (int)nbl->args->argc; j++) 14002588c917Sschwarze if (nbl->args->argv[j].arg == MDOC_Column) 140120fa2881Sschwarze break; 140220fa2881Sschwarze 14032588c917Sschwarze assert(j < (int)nbl->args->argc); 140420fa2881Sschwarze 140520fa2881Sschwarze /* 1406a5e11edeSschwarze * Accommodate for new-style groff column syntax. Shuffle the 140720fa2881Sschwarze * child nodes, all of which must be TEXT, as arguments for the 140820fa2881Sschwarze * column field. Then, delete the head children. 140920fa2881Sschwarze */ 141020fa2881Sschwarze 14112588c917Sschwarze argv = nbl->args->argv + j; 1412f5174743Sschwarze i = argv->sz; 14132588c917Sschwarze argv->sz += nh->nchild; 1414f5174743Sschwarze argv->value = mandoc_reallocarray(argv->value, 1415f5174743Sschwarze argv->sz, sizeof(char *)); 141620fa2881Sschwarze 14172588c917Sschwarze nh->norm->Bl.ncols = argv->sz; 14182588c917Sschwarze nh->norm->Bl.cols = (void *)argv->value; 141920fa2881Sschwarze 14202588c917Sschwarze for (nch = nh->child; nch != NULL; nch = nnext) { 14212588c917Sschwarze argv->value[i++] = nch->string; 14222588c917Sschwarze nch->string = NULL; 14232588c917Sschwarze nnext = nch->next; 14242588c917Sschwarze mdoc_node_delete(NULL, nch); 1425395185ccSschwarze } 14262588c917Sschwarze nh->nchild = 0; 14272588c917Sschwarze nh->child = NULL; 1428b16e7ddfSschwarze } 1429b16e7ddfSschwarze 143098b8f00aSschwarze static void 1431f73abda9Skristaps post_bl(POST_ARGS) 1432f73abda9Skristaps { 14332a427d60Sschwarze struct mdoc_node *nparent, *nprev; /* of the Bl block */ 14342a427d60Sschwarze struct mdoc_node *nblock, *nbody; /* of the Bl */ 14352a427d60Sschwarze struct mdoc_node *nchild, *nnext; /* of the Bl body */ 1436f73abda9Skristaps 14372a427d60Sschwarze nbody = mdoc->last; 14382a427d60Sschwarze switch (nbody->type) { 143949aff9f8Sschwarze case MDOC_BLOCK: 144098b8f00aSschwarze post_bl_block(mdoc); 144198b8f00aSschwarze return; 144249aff9f8Sschwarze case MDOC_HEAD: 144398b8f00aSschwarze post_bl_head(mdoc); 144498b8f00aSschwarze return; 144549aff9f8Sschwarze case MDOC_BODY: 1446f6127a73Sschwarze break; 14472a427d60Sschwarze default: 144898b8f00aSschwarze return; 1449f6127a73Sschwarze } 1450f6127a73Sschwarze 14512a427d60Sschwarze nchild = nbody->child; 1452b7530f2fSschwarze if (nchild == NULL) { 1453*1d0823adSschwarze mandoc_msg(MANDOCERR_BLK_EMPTY, mdoc->parse, 1454b7530f2fSschwarze nbody->line, nbody->pos, "Bl"); 1455b7530f2fSschwarze return; 1456b7530f2fSschwarze } 1457b7530f2fSschwarze while (nchild != NULL) { 1458204684a7Sschwarze if (nchild->tok == MDOC_It || 1459204684a7Sschwarze (nchild->tok == MDOC_Sm && 1460204684a7Sschwarze nchild->next != NULL && 1461204684a7Sschwarze nchild->next->tok == MDOC_It)) { 14622a427d60Sschwarze nchild = nchild->next; 14632a427d60Sschwarze continue; 14642a427d60Sschwarze } 14652a427d60Sschwarze 1466dd25b57cSschwarze mandoc_msg(MANDOCERR_BL_MOVE, mdoc->parse, 1467dd25b57cSschwarze nchild->line, nchild->pos, 1468dd25b57cSschwarze mdoc_macronames[nchild->tok]); 14692a427d60Sschwarze 14702a427d60Sschwarze /* 14712a427d60Sschwarze * Move the node out of the Bl block. 14722a427d60Sschwarze * First, collect all required node pointers. 14732a427d60Sschwarze */ 14742a427d60Sschwarze 14752a427d60Sschwarze nblock = nbody->parent; 14762a427d60Sschwarze nprev = nblock->prev; 14772a427d60Sschwarze nparent = nblock->parent; 14782a427d60Sschwarze nnext = nchild->next; 14792a427d60Sschwarze 14802a427d60Sschwarze /* 14812a427d60Sschwarze * Unlink this child. 14822a427d60Sschwarze */ 14832a427d60Sschwarze 14842a427d60Sschwarze assert(NULL == nchild->prev); 14852a427d60Sschwarze if (0 == --nbody->nchild) { 14862a427d60Sschwarze nbody->child = NULL; 14872a427d60Sschwarze nbody->last = NULL; 14882a427d60Sschwarze assert(NULL == nnext); 14892a427d60Sschwarze } else { 14902a427d60Sschwarze nbody->child = nnext; 14912a427d60Sschwarze nnext->prev = NULL; 14922a427d60Sschwarze } 14932a427d60Sschwarze 14942a427d60Sschwarze /* 14952a427d60Sschwarze * Relink this child. 14962a427d60Sschwarze */ 14972a427d60Sschwarze 14982a427d60Sschwarze nchild->parent = nparent; 14992a427d60Sschwarze nchild->prev = nprev; 15002a427d60Sschwarze nchild->next = nblock; 15012a427d60Sschwarze 15022a427d60Sschwarze nblock->prev = nchild; 15032a427d60Sschwarze nparent->nchild++; 15042a427d60Sschwarze if (NULL == nprev) 15052a427d60Sschwarze nparent->child = nchild; 15062a427d60Sschwarze else 15072a427d60Sschwarze nprev->next = nchild; 15082a427d60Sschwarze 15092a427d60Sschwarze nchild = nnext; 1510f73abda9Skristaps } 1511f73abda9Skristaps } 1512f73abda9Skristaps 151398b8f00aSschwarze static void 1514753701eeSschwarze post_bk(POST_ARGS) 1515753701eeSschwarze { 15162588c917Sschwarze struct mdoc_node *n; 1517753701eeSschwarze 15182588c917Sschwarze n = mdoc->last; 15192588c917Sschwarze 15202588c917Sschwarze if (n->type == MDOC_BLOCK && n->body->child == NULL) { 1521*1d0823adSschwarze mandoc_msg(MANDOCERR_BLK_EMPTY, 15222588c917Sschwarze mdoc->parse, n->line, n->pos, "Bk"); 15232588c917Sschwarze mdoc_node_delete(mdoc, n); 15242588c917Sschwarze } 1525753701eeSschwarze } 1526753701eeSschwarze 152798b8f00aSschwarze static void 152878bbbab4Sschwarze post_sm(struct mdoc *mdoc) 1529f73abda9Skristaps { 1530dc0d8bb2Sschwarze struct mdoc_node *nch; 1531f73abda9Skristaps 1532dc0d8bb2Sschwarze nch = mdoc->last->child; 1533dc0d8bb2Sschwarze 153478bbbab4Sschwarze if (nch == NULL) { 1535f9e7bf99Sschwarze mdoc->flags ^= MDOC_SMOFF; 153698b8f00aSschwarze return; 1537bb648afaSschwarze } 1538f9e7bf99Sschwarze 153978bbbab4Sschwarze assert(nch->type == MDOC_TEXT); 154020fa2881Sschwarze 154178bbbab4Sschwarze if ( ! strcmp(nch->string, "on")) { 1542ec2beb53Sschwarze mdoc->flags &= ~MDOC_SMOFF; 154398b8f00aSschwarze return; 1544ec2beb53Sschwarze } 154578bbbab4Sschwarze if ( ! strcmp(nch->string, "off")) { 1546ec2beb53Sschwarze mdoc->flags |= MDOC_SMOFF; 154798b8f00aSschwarze return; 1548ec2beb53Sschwarze } 154920fa2881Sschwarze 1550dc0d8bb2Sschwarze mandoc_vmsg(MANDOCERR_SM_BAD, 1551dc0d8bb2Sschwarze mdoc->parse, nch->line, nch->pos, 155278bbbab4Sschwarze "%s %s", mdoc_macronames[mdoc->last->tok], nch->string); 155398b8f00aSschwarze mdoc_node_relink(mdoc, nch); 155498b8f00aSschwarze return; 155520fa2881Sschwarze } 1556f73abda9Skristaps 155798b8f00aSschwarze static void 1558f73abda9Skristaps post_root(POST_ARGS) 1559f73abda9Skristaps { 156020fa2881Sschwarze struct mdoc_node *n; 1561f73abda9Skristaps 1562ac1f49d0Sschwarze /* Add missing prologue data. */ 156320fa2881Sschwarze 1564ac1f49d0Sschwarze if (mdoc->meta.date == NULL) 1565ac1f49d0Sschwarze mdoc->meta.date = mdoc->quick ? 1566ac1f49d0Sschwarze mandoc_strdup("") : 1567ac1f49d0Sschwarze mandoc_normdate(mdoc->parse, NULL, 0, 0); 15683fdead0cSschwarze 15693fdead0cSschwarze if (mdoc->meta.title == NULL) { 15703fdead0cSschwarze mandoc_msg(MANDOCERR_DT_NOTITLE, 15713fdead0cSschwarze mdoc->parse, 0, 0, "EOF"); 15723fdead0cSschwarze mdoc->meta.title = mandoc_strdup("UNTITLED"); 15733fdead0cSschwarze } 15743fdead0cSschwarze 1575ac1f49d0Sschwarze if (mdoc->meta.vol == NULL) 1576ac1f49d0Sschwarze mdoc->meta.vol = mandoc_strdup("LOCAL"); 15773fdead0cSschwarze 15783fdead0cSschwarze if (mdoc->meta.os == NULL) { 15793fdead0cSschwarze mandoc_msg(MANDOCERR_OS_MISSING, 15803fdead0cSschwarze mdoc->parse, 0, 0, NULL); 15813fdead0cSschwarze mdoc->meta.os = mandoc_strdup(""); 1582f73abda9Skristaps } 1583f73abda9Skristaps 158420fa2881Sschwarze /* Check that we begin with a proper `Sh'. */ 158520fa2881Sschwarze 1586e20417bdSschwarze n = mdoc->first->child; 1587e20417bdSschwarze while (n != NULL && mdoc_macros[n->tok].flags & MDOC_PROLOGUE) 1588e20417bdSschwarze n = n->next; 1589e20417bdSschwarze 1590e20417bdSschwarze if (n == NULL) 1591e20417bdSschwarze mandoc_msg(MANDOCERR_DOC_EMPTY, mdoc->parse, 0, 0, NULL); 1592e20417bdSschwarze else if (n->tok != MDOC_Sh) 159351fcab2fSschwarze mandoc_msg(MANDOCERR_SEC_BEFORE, mdoc->parse, 1594e20417bdSschwarze n->line, n->pos, mdoc_macronames[n->tok]); 159520fa2881Sschwarze } 1596f73abda9Skristaps 159798b8f00aSschwarze static void 1598f73abda9Skristaps post_st(POST_ARGS) 1599f73abda9Skristaps { 1600dc0d8bb2Sschwarze struct mdoc_node *n, *nch; 160120fa2881Sschwarze const char *p; 1602f73abda9Skristaps 1603dc0d8bb2Sschwarze n = mdoc->last; 1604dc0d8bb2Sschwarze nch = n->child; 1605dc0d8bb2Sschwarze 1606dc0d8bb2Sschwarze assert(MDOC_TEXT == nch->type); 160720fa2881Sschwarze 1608dc0d8bb2Sschwarze if (NULL == (p = mdoc_a2st(nch->string))) { 1609bd594191Sschwarze mandoc_vmsg(MANDOCERR_ST_BAD, mdoc->parse, 1610bd594191Sschwarze nch->line, nch->pos, "St %s", nch->string); 1611dc0d8bb2Sschwarze mdoc_node_delete(mdoc, n); 161220fa2881Sschwarze } else { 1613dc0d8bb2Sschwarze free(nch->string); 1614dc0d8bb2Sschwarze nch->string = mandoc_strdup(p); 1615f73abda9Skristaps } 161620fa2881Sschwarze } 1617f73abda9Skristaps 161898b8f00aSschwarze static void 1619011fe33bSschwarze post_rs(POST_ARGS) 1620011fe33bSschwarze { 16216e96429aSschwarze struct mdoc_node *np, *nch, *next, *prev; 162220fa2881Sschwarze int i, j; 1623011fe33bSschwarze 16246e96429aSschwarze np = mdoc->last; 16256e96429aSschwarze 16266e96429aSschwarze if (np->type != MDOC_BODY) 162798b8f00aSschwarze return; 16286e96429aSschwarze 16296e96429aSschwarze if (np->child == NULL) { 16306e96429aSschwarze mandoc_msg(MANDOCERR_RS_EMPTY, mdoc->parse, 16316e96429aSschwarze np->line, np->pos, "Rs"); 163298b8f00aSschwarze return; 1633bb648afaSschwarze } 1634011fe33bSschwarze 163520fa2881Sschwarze /* 163620fa2881Sschwarze * The full `Rs' block needs special handling to order the 163720fa2881Sschwarze * sub-elements according to `rsord'. Pick through each element 1638b538baa5Sschwarze * and correctly order it. This is an insertion sort. 163920fa2881Sschwarze */ 164020fa2881Sschwarze 164120fa2881Sschwarze next = NULL; 16426e96429aSschwarze for (nch = np->child->next; nch != NULL; nch = next) { 16436e96429aSschwarze /* Determine order number of this child. */ 164420fa2881Sschwarze for (i = 0; i < RSORD_MAX; i++) 16456e96429aSschwarze if (rsord[i] == nch->tok) 164620fa2881Sschwarze break; 164720fa2881Sschwarze 1648b538baa5Sschwarze if (i == RSORD_MAX) { 1649b538baa5Sschwarze mandoc_msg(MANDOCERR_RS_BAD, 16506e96429aSschwarze mdoc->parse, nch->line, nch->pos, 16516e96429aSschwarze mdoc_macronames[nch->tok]); 1652b538baa5Sschwarze i = -1; 16536e96429aSschwarze } else if (nch->tok == MDOC__J || nch->tok == MDOC__B) 16546e96429aSschwarze np->norm->Rs.quote_T++; 1655b538baa5Sschwarze 165620fa2881Sschwarze /* 16576e96429aSschwarze * Remove this child from the chain. This somewhat 165820fa2881Sschwarze * repeats mdoc_node_unlink(), but since we're 165920fa2881Sschwarze * just re-ordering, there's no need for the 166020fa2881Sschwarze * full unlink process. 166120fa2881Sschwarze */ 166220fa2881Sschwarze 16636e96429aSschwarze if ((next = nch->next) != NULL) 16646e96429aSschwarze next->prev = nch->prev; 166520fa2881Sschwarze 16666e96429aSschwarze if ((prev = nch->prev) != NULL) 16676e96429aSschwarze prev->next = nch->next; 166820fa2881Sschwarze 16696e96429aSschwarze nch->prev = nch->next = NULL; 167020fa2881Sschwarze 167120fa2881Sschwarze /* 167220fa2881Sschwarze * Scan back until we reach a node that's 16736e96429aSschwarze * to be ordered before this child. 167420fa2881Sschwarze */ 167520fa2881Sschwarze 167620fa2881Sschwarze for ( ; prev ; prev = prev->prev) { 167720fa2881Sschwarze /* Determine order of `prev'. */ 167820fa2881Sschwarze for (j = 0; j < RSORD_MAX; j++) 167920fa2881Sschwarze if (rsord[j] == prev->tok) 168020fa2881Sschwarze break; 1681b538baa5Sschwarze if (j == RSORD_MAX) 1682b538baa5Sschwarze j = -1; 168320fa2881Sschwarze 168420fa2881Sschwarze if (j <= i) 168520fa2881Sschwarze break; 168620fa2881Sschwarze } 168720fa2881Sschwarze 168820fa2881Sschwarze /* 16896e96429aSschwarze * Set this child back into its correct place 16906e96429aSschwarze * in front of the `prev' node. 169120fa2881Sschwarze */ 169220fa2881Sschwarze 16936e96429aSschwarze nch->prev = prev; 169420fa2881Sschwarze 16956e96429aSschwarze if (prev == NULL) { 16966e96429aSschwarze np->child->prev = nch; 16976e96429aSschwarze nch->next = np->child; 16986e96429aSschwarze np->child = nch; 169920fa2881Sschwarze } else { 17006e96429aSschwarze if (prev->next) 17016e96429aSschwarze prev->next->prev = nch; 17026e96429aSschwarze nch->next = prev->next; 17036e96429aSschwarze prev->next = nch; 170420fa2881Sschwarze } 1705011fe33bSschwarze } 1706011fe33bSschwarze } 1707011fe33bSschwarze 17084039b21cSschwarze /* 17094039b21cSschwarze * For some arguments of some macros, 17104039b21cSschwarze * convert all breakable hyphens into ASCII_HYPH. 17114039b21cSschwarze */ 171298b8f00aSschwarze static void 17134039b21cSschwarze post_hyph(POST_ARGS) 17144039b21cSschwarze { 1715b7530f2fSschwarze struct mdoc_node *nch; 17164039b21cSschwarze char *cp; 17174039b21cSschwarze 1718b7530f2fSschwarze for (nch = mdoc->last->child; nch != NULL; nch = nch->next) { 1719b7530f2fSschwarze if (nch->type != MDOC_TEXT) 17204039b21cSschwarze continue; 17214039b21cSschwarze cp = nch->string; 1722b7530f2fSschwarze if (*cp == '\0') 17234039b21cSschwarze continue; 1724b7530f2fSschwarze while (*(++cp) != '\0') 1725b7530f2fSschwarze if (*cp == '-' && 17264039b21cSschwarze isalpha((unsigned char)cp[-1]) && 17274039b21cSschwarze isalpha((unsigned char)cp[1])) 17284039b21cSschwarze *cp = ASCII_HYPH; 17294039b21cSschwarze } 17304039b21cSschwarze } 17314039b21cSschwarze 173298b8f00aSschwarze static void 1733af216717Sschwarze post_ns(POST_ARGS) 1734af216717Sschwarze { 1735af216717Sschwarze 1736af216717Sschwarze if (MDOC_LINE & mdoc->last->flags) 173728153913Sschwarze mandoc_msg(MANDOCERR_NS_SKIP, mdoc->parse, 173828153913Sschwarze mdoc->last->line, mdoc->last->pos, NULL); 1739af216717Sschwarze } 1740af216717Sschwarze 174198b8f00aSschwarze static void 1742f73abda9Skristaps post_sh(POST_ARGS) 1743f73abda9Skristaps { 1744f73abda9Skristaps 1745753701eeSschwarze post_ignpar(mdoc); 1746753701eeSschwarze 1747cd6c268fSschwarze switch (mdoc->last->type) { 1748cd6c268fSschwarze case MDOC_HEAD: 174998b8f00aSschwarze post_sh_head(mdoc); 175098b8f00aSschwarze break; 1751cd6c268fSschwarze case MDOC_BODY: 1752cd6c268fSschwarze switch (mdoc->lastsec) { 1753cd6c268fSschwarze case SEC_NAME: 175498b8f00aSschwarze post_sh_name(mdoc); 175598b8f00aSschwarze break; 17567c384856Sschwarze case SEC_SEE_ALSO: 175798b8f00aSschwarze post_sh_see_also(mdoc); 175898b8f00aSschwarze break; 1759cd6c268fSschwarze case SEC_AUTHORS: 176098b8f00aSschwarze post_sh_authors(mdoc); 176198b8f00aSschwarze break; 1762cd6c268fSschwarze default: 1763cd6c268fSschwarze break; 1764cd6c268fSschwarze } 1765cd6c268fSschwarze break; 1766cd6c268fSschwarze default: 1767cd6c268fSschwarze break; 1768cd6c268fSschwarze } 1769f73abda9Skristaps } 1770f73abda9Skristaps 177198b8f00aSschwarze static void 1772cd6c268fSschwarze post_sh_name(POST_ARGS) 1773f73abda9Skristaps { 1774f73abda9Skristaps struct mdoc_node *n; 1775f73abda9Skristaps 1776f73abda9Skristaps /* 1777f73abda9Skristaps * Warn if the NAME section doesn't contain the `Nm' and `Nd' 1778f73abda9Skristaps * macros (can have multiple `Nm' and one `Nd'). Note that the 1779f73abda9Skristaps * children of the BODY declaration can also be "text". 1780f73abda9Skristaps */ 1781f73abda9Skristaps 178220fa2881Sschwarze if (NULL == (n = mdoc->last->child)) { 178351fcab2fSschwarze mandoc_msg(MANDOCERR_NAMESEC_BAD, mdoc->parse, 178451fcab2fSschwarze mdoc->last->line, mdoc->last->pos, "empty"); 178598b8f00aSschwarze return; 178620fa2881Sschwarze } 1787f73abda9Skristaps 1788f73abda9Skristaps for ( ; n && n->next; n = n->next) { 1789f73abda9Skristaps if (MDOC_ELEM == n->type && MDOC_Nm == n->tok) 1790f73abda9Skristaps continue; 1791f73abda9Skristaps if (MDOC_TEXT == n->type) 1792f73abda9Skristaps continue; 179351fcab2fSschwarze mandoc_msg(MANDOCERR_NAMESEC_BAD, mdoc->parse, 179451fcab2fSschwarze n->line, n->pos, mdoc_macronames[n->tok]); 1795f73abda9Skristaps } 1796f73abda9Skristaps 179749d529b5Sschwarze assert(n); 17984602e85cSschwarze if (MDOC_BLOCK == n->type && MDOC_Nd == n->tok) 179998b8f00aSschwarze return; 1800f73abda9Skristaps 180151fcab2fSschwarze mandoc_msg(MANDOCERR_NAMESEC_BAD, mdoc->parse, 180251fcab2fSschwarze n->line, n->pos, mdoc_macronames[n->tok]); 180320fa2881Sschwarze } 1804f73abda9Skristaps 180598b8f00aSschwarze static void 18067c384856Sschwarze post_sh_see_also(POST_ARGS) 18077c384856Sschwarze { 18087c384856Sschwarze const struct mdoc_node *n; 18097c384856Sschwarze const char *name, *sec; 18107c384856Sschwarze const char *lastname, *lastsec, *lastpunct; 18117c384856Sschwarze int cmp; 18127c384856Sschwarze 18137c384856Sschwarze n = mdoc->last->child; 18147c384856Sschwarze lastname = lastsec = lastpunct = NULL; 18157c384856Sschwarze while (n != NULL) { 18167c384856Sschwarze if (n->tok != MDOC_Xr || n->nchild < 2) 18177c384856Sschwarze break; 18187c384856Sschwarze 18197c384856Sschwarze /* Process one .Xr node. */ 18207c384856Sschwarze 18217c384856Sschwarze name = n->child->string; 18227c384856Sschwarze sec = n->child->next->string; 18237c384856Sschwarze if (lastsec != NULL) { 18247c384856Sschwarze if (lastpunct[0] != ',' || lastpunct[1] != '\0') 18257c384856Sschwarze mandoc_vmsg(MANDOCERR_XR_PUNCT, 18267c384856Sschwarze mdoc->parse, n->line, n->pos, 18277c384856Sschwarze "%s before %s(%s)", lastpunct, 18287c384856Sschwarze name, sec); 18297c384856Sschwarze cmp = strcmp(lastsec, sec); 18307c384856Sschwarze if (cmp > 0) 18317c384856Sschwarze mandoc_vmsg(MANDOCERR_XR_ORDER, 18327c384856Sschwarze mdoc->parse, n->line, n->pos, 18337c384856Sschwarze "%s(%s) after %s(%s)", name, 18347c384856Sschwarze sec, lastname, lastsec); 18357c384856Sschwarze else if (cmp == 0 && 18367c384856Sschwarze strcasecmp(lastname, name) > 0) 18377c384856Sschwarze mandoc_vmsg(MANDOCERR_XR_ORDER, 18387c384856Sschwarze mdoc->parse, n->line, n->pos, 18397c384856Sschwarze "%s after %s", name, lastname); 18407c384856Sschwarze } 18417c384856Sschwarze lastname = name; 18427c384856Sschwarze lastsec = sec; 18437c384856Sschwarze 18447c384856Sschwarze /* Process the following node. */ 18457c384856Sschwarze 18467c384856Sschwarze n = n->next; 18477c384856Sschwarze if (n == NULL) 18487c384856Sschwarze break; 18497c384856Sschwarze if (n->tok == MDOC_Xr) { 18507c384856Sschwarze lastpunct = "none"; 18517c384856Sschwarze continue; 18527c384856Sschwarze } 18537c384856Sschwarze if (n->type != MDOC_TEXT) 18547c384856Sschwarze break; 18557c384856Sschwarze for (name = n->string; *name != '\0'; name++) 18567c384856Sschwarze if (isalpha((const unsigned char)*name)) 185798b8f00aSschwarze return; 18587c384856Sschwarze lastpunct = n->string; 18597c384856Sschwarze if (n->next == NULL) 18607c384856Sschwarze mandoc_vmsg(MANDOCERR_XR_PUNCT, mdoc->parse, 18617c384856Sschwarze n->line, n->pos, "%s after %s(%s)", 18627c384856Sschwarze lastpunct, lastname, lastsec); 18637c384856Sschwarze n = n->next; 18647c384856Sschwarze } 18657c384856Sschwarze } 18667c384856Sschwarze 18677c384856Sschwarze static int 1868cd6c268fSschwarze child_an(const struct mdoc_node *n) 1869cd6c268fSschwarze { 1870cd6c268fSschwarze 1871cd6c268fSschwarze for (n = n->child; n != NULL; n = n->next) 1872cd6c268fSschwarze if ((n->tok == MDOC_An && n->nchild) || child_an(n)) 1873cd6c268fSschwarze return(1); 1874cd6c268fSschwarze return(0); 1875cd6c268fSschwarze } 1876cd6c268fSschwarze 187798b8f00aSschwarze static void 1878cd6c268fSschwarze post_sh_authors(POST_ARGS) 1879cd6c268fSschwarze { 1880cd6c268fSschwarze 1881cd6c268fSschwarze if ( ! child_an(mdoc->last)) 1882cd6c268fSschwarze mandoc_msg(MANDOCERR_AN_MISSING, mdoc->parse, 1883cd6c268fSschwarze mdoc->last->line, mdoc->last->pos, NULL); 1884cd6c268fSschwarze } 1885cd6c268fSschwarze 188698b8f00aSschwarze static void 1887f73abda9Skristaps post_sh_head(POST_ARGS) 1888f73abda9Skristaps { 1889a2cff342Sschwarze struct mdoc_node *n; 189051fcab2fSschwarze const char *goodsec; 189146133849Sschwarze char *secname; 1892f73abda9Skristaps enum mdoc_sec sec; 1893f73abda9Skristaps 1894f73abda9Skristaps /* 1895f73abda9Skristaps * Process a new section. Sections are either "named" or 189620fa2881Sschwarze * "custom". Custom sections are user-defined, while named ones 189720fa2881Sschwarze * follow a conventional order and may only appear in certain 189820fa2881Sschwarze * manual sections. 1899f73abda9Skristaps */ 1900f73abda9Skristaps 190183af2bccSschwarze secname = NULL; 190204e980cbSschwarze sec = SEC_CUSTOM; 190346133849Sschwarze mdoc_deroff(&secname, mdoc->last); 190446133849Sschwarze sec = NULL == secname ? SEC_CUSTOM : a2sec(secname); 1905f73abda9Skristaps 190620fa2881Sschwarze /* The NAME should be first. */ 1907f73abda9Skristaps 1908fccfce9dSschwarze if (SEC_NAME != sec && SEC_NONE == mdoc->lastnamed) 1909bd594191Sschwarze mandoc_vmsg(MANDOCERR_NAMESEC_FIRST, mdoc->parse, 1910bd594191Sschwarze mdoc->last->line, mdoc->last->pos, 1911bd594191Sschwarze "Sh %s", secname); 191220fa2881Sschwarze 191320fa2881Sschwarze /* The SYNOPSIS gets special attention in other areas. */ 191420fa2881Sschwarze 191522881299Sschwarze if (SEC_SYNOPSIS == sec) { 191675088a49Sschwarze roff_setreg(mdoc->roff, "nS", 1, '='); 191720fa2881Sschwarze mdoc->flags |= MDOC_SYNOPSIS; 191822881299Sschwarze } else { 191975088a49Sschwarze roff_setreg(mdoc->roff, "nS", 0, '='); 192020fa2881Sschwarze mdoc->flags &= ~MDOC_SYNOPSIS; 192122881299Sschwarze } 192220fa2881Sschwarze 192320fa2881Sschwarze /* Mark our last section. */ 192420fa2881Sschwarze 192520fa2881Sschwarze mdoc->lastsec = sec; 19261eccdf28Sschwarze 19271eccdf28Sschwarze /* 19281eccdf28Sschwarze * Set the section attribute for the current HEAD, for its 19291eccdf28Sschwarze * parent BLOCK, and for the HEAD children; the latter can 19301eccdf28Sschwarze * only be TEXT nodes, so no recursion is needed. 19311eccdf28Sschwarze * For other blocks and elements, including .Sh BODY, this is 19321eccdf28Sschwarze * done when allocating the node data structures, but for .Sh 19331eccdf28Sschwarze * BLOCK and HEAD, the section is still unknown at that time. 19341eccdf28Sschwarze */ 19351eccdf28Sschwarze 1936a2cff342Sschwarze mdoc->last->parent->sec = sec; 1937a2cff342Sschwarze mdoc->last->sec = sec; 1938a2cff342Sschwarze for (n = mdoc->last->child; n; n = n->next) 1939a2cff342Sschwarze n->sec = sec; 194020fa2881Sschwarze 194120fa2881Sschwarze /* We don't care about custom sections after this. */ 1942fccfce9dSschwarze 194346133849Sschwarze if (SEC_CUSTOM == sec) { 194446133849Sschwarze free(secname); 194598b8f00aSschwarze return; 194646133849Sschwarze } 1947fccfce9dSschwarze 19486be99f77Sschwarze /* 194920fa2881Sschwarze * Check whether our non-custom section is being repeated or is 195020fa2881Sschwarze * out of order. 19516be99f77Sschwarze */ 1952f73abda9Skristaps 195320fa2881Sschwarze if (sec == mdoc->lastnamed) 1954bd594191Sschwarze mandoc_vmsg(MANDOCERR_SEC_REP, mdoc->parse, 1955bd594191Sschwarze mdoc->last->line, mdoc->last->pos, 1956bd594191Sschwarze "Sh %s", secname); 195720fa2881Sschwarze 195820fa2881Sschwarze if (sec < mdoc->lastnamed) 1959bd594191Sschwarze mandoc_vmsg(MANDOCERR_SEC_ORDER, mdoc->parse, 1960bd594191Sschwarze mdoc->last->line, mdoc->last->pos, 1961bd594191Sschwarze "Sh %s", secname); 196220fa2881Sschwarze 196320fa2881Sschwarze /* Mark the last named section. */ 196420fa2881Sschwarze 196520fa2881Sschwarze mdoc->lastnamed = sec; 196620fa2881Sschwarze 196720fa2881Sschwarze /* Check particular section/manual conventions. */ 196820fa2881Sschwarze 19693fdead0cSschwarze if (mdoc->meta.msec == NULL) { 19703fdead0cSschwarze free(secname); 197198b8f00aSschwarze return; 19723fdead0cSschwarze } 197320fa2881Sschwarze 197451fcab2fSschwarze goodsec = NULL; 197520fa2881Sschwarze switch (sec) { 197649aff9f8Sschwarze case SEC_ERRORS: 1977be89e780Sschwarze if (*mdoc->meta.msec == '4') 1978be89e780Sschwarze break; 197951fcab2fSschwarze goodsec = "2, 3, 4, 9"; 1980be89e780Sschwarze /* FALLTHROUGH */ 198149aff9f8Sschwarze case SEC_RETURN_VALUES: 198220fa2881Sschwarze /* FALLTHROUGH */ 198349aff9f8Sschwarze case SEC_LIBRARY: 198492c0ca7fSschwarze if (*mdoc->meta.msec == '2') 1985f73abda9Skristaps break; 198692c0ca7fSschwarze if (*mdoc->meta.msec == '3') 198792c0ca7fSschwarze break; 198851fcab2fSschwarze if (NULL == goodsec) 198951fcab2fSschwarze goodsec = "2, 3, 9"; 199003ab2f23Sdlg /* FALLTHROUGH */ 199149aff9f8Sschwarze case SEC_CONTEXT: 199292c0ca7fSschwarze if (*mdoc->meta.msec == '9') 199392c0ca7fSschwarze break; 199451fcab2fSschwarze if (NULL == goodsec) 199551fcab2fSschwarze goodsec = "9"; 199651fcab2fSschwarze mandoc_vmsg(MANDOCERR_SEC_MSEC, mdoc->parse, 199751fcab2fSschwarze mdoc->last->line, mdoc->last->pos, 1998bd594191Sschwarze "Sh %s for %s only", secname, goodsec); 199920fa2881Sschwarze break; 2000f73abda9Skristaps default: 2001f73abda9Skristaps break; 2002f73abda9Skristaps } 200346133849Sschwarze free(secname); 2004f73abda9Skristaps } 2005d39b9a9cSschwarze 200698b8f00aSschwarze static void 2007f6127a73Sschwarze post_ignpar(POST_ARGS) 2008f6127a73Sschwarze { 2009f6127a73Sschwarze struct mdoc_node *np; 2010f6127a73Sschwarze 2011b7530f2fSschwarze switch (mdoc->last->type) { 2012b7530f2fSschwarze case MDOC_HEAD: 2013753701eeSschwarze post_hyph(mdoc); 201498b8f00aSschwarze return; 2015b7530f2fSschwarze case MDOC_BODY: 2016b7530f2fSschwarze break; 2017b7530f2fSschwarze default: 2018b7530f2fSschwarze return; 2019b7530f2fSschwarze } 2020f6127a73Sschwarze 2021f6127a73Sschwarze if (NULL != (np = mdoc->last->child)) 2022f6127a73Sschwarze if (MDOC_Pp == np->tok || MDOC_Lp == np->tok) { 202320369664Sschwarze mandoc_vmsg(MANDOCERR_PAR_SKIP, 202420369664Sschwarze mdoc->parse, np->line, np->pos, 202520369664Sschwarze "%s after %s", mdoc_macronames[np->tok], 202620369664Sschwarze mdoc_macronames[mdoc->last->tok]); 2027f6127a73Sschwarze mdoc_node_delete(mdoc, np); 2028f6127a73Sschwarze } 2029f6127a73Sschwarze 2030f6127a73Sschwarze if (NULL != (np = mdoc->last->last)) 2031f6127a73Sschwarze if (MDOC_Pp == np->tok || MDOC_Lp == np->tok) { 203220369664Sschwarze mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse, 203320369664Sschwarze np->line, np->pos, "%s at the end of %s", 203420369664Sschwarze mdoc_macronames[np->tok], 203520369664Sschwarze mdoc_macronames[mdoc->last->tok]); 2036f6127a73Sschwarze mdoc_node_delete(mdoc, np); 2037f6127a73Sschwarze } 2038f6127a73Sschwarze } 2039f6127a73Sschwarze 204098b8f00aSschwarze static void 204120fa2881Sschwarze pre_par(PRE_ARGS) 2042d39b9a9cSschwarze { 2043d39b9a9cSschwarze 2044d39b9a9cSschwarze if (NULL == mdoc->last) 204598b8f00aSschwarze return; 2046f6127a73Sschwarze if (MDOC_ELEM != n->type && MDOC_BLOCK != n->type) 204798b8f00aSschwarze return; 2048d39b9a9cSschwarze 204920fa2881Sschwarze /* 205020fa2881Sschwarze * Don't allow prior `Lp' or `Pp' prior to a paragraph-type 205120fa2881Sschwarze * block: `Lp', `Pp', or non-compact `Bd' or `Bl'. 205220fa2881Sschwarze */ 2053d39b9a9cSschwarze 2054e0dd4c9cSschwarze if (MDOC_Pp != mdoc->last->tok && 2055e0dd4c9cSschwarze MDOC_Lp != mdoc->last->tok && 2056e0dd4c9cSschwarze MDOC_br != mdoc->last->tok) 205798b8f00aSschwarze return; 20588c62fbf5Sschwarze if (MDOC_Bl == n->tok && n->norm->Bl.comp) 205998b8f00aSschwarze return; 20608c62fbf5Sschwarze if (MDOC_Bd == n->tok && n->norm->Bd.comp) 206198b8f00aSschwarze return; 20628c62fbf5Sschwarze if (MDOC_It == n->tok && n->parent->norm->Bl.comp) 206398b8f00aSschwarze return; 2064d39b9a9cSschwarze 206520369664Sschwarze mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse, 206620369664Sschwarze mdoc->last->line, mdoc->last->pos, 206720369664Sschwarze "%s before %s", mdoc_macronames[mdoc->last->tok], 206820369664Sschwarze mdoc_macronames[n->tok]); 2069d39b9a9cSschwarze mdoc_node_delete(mdoc, mdoc->last); 2070d39b9a9cSschwarze } 207120fa2881Sschwarze 207298b8f00aSschwarze static void 2073e0dd4c9cSschwarze post_par(POST_ARGS) 2074e0dd4c9cSschwarze { 207520369664Sschwarze struct mdoc_node *np; 2076e0dd4c9cSschwarze 20773798fb25Sschwarze np = mdoc->last; 2078753701eeSschwarze 20793798fb25Sschwarze if (np->tok == MDOC_sp) { 20803798fb25Sschwarze if (np->nchild > 1) 20813798fb25Sschwarze mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse, 20823798fb25Sschwarze np->child->next->line, np->child->next->pos, 20833798fb25Sschwarze "sp ... %s", np->child->next->string); 20843798fb25Sschwarze } else if (np->child != NULL) 20853798fb25Sschwarze mandoc_vmsg(MANDOCERR_ARG_SKIP, 20863798fb25Sschwarze mdoc->parse, np->line, np->pos, "%s %s", 20873798fb25Sschwarze mdoc_macronames[np->tok], np->child->string); 2088e0dd4c9cSschwarze 208920369664Sschwarze if (NULL == (np = mdoc->last->prev)) { 209020369664Sschwarze np = mdoc->last->parent; 209120369664Sschwarze if (MDOC_Sh != np->tok && MDOC_Ss != np->tok) 209298b8f00aSschwarze return; 209398b8f00aSschwarze } else if (MDOC_Pp != np->tok && MDOC_Lp != np->tok && 2094e0dd4c9cSschwarze (MDOC_br != mdoc->last->tok || 209520369664Sschwarze (MDOC_sp != np->tok && MDOC_br != np->tok))) 209698b8f00aSschwarze return; 2097e0dd4c9cSschwarze 209820369664Sschwarze mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse, 209920369664Sschwarze mdoc->last->line, mdoc->last->pos, 210020369664Sschwarze "%s after %s", mdoc_macronames[mdoc->last->tok], 210120369664Sschwarze mdoc_macronames[np->tok]); 2102e0dd4c9cSschwarze mdoc_node_delete(mdoc, mdoc->last); 2103e0dd4c9cSschwarze } 2104e0dd4c9cSschwarze 210598b8f00aSschwarze static void 210620fa2881Sschwarze pre_literal(PRE_ARGS) 210720fa2881Sschwarze { 210820fa2881Sschwarze 2109d52d1586Sschwarze pre_display(mdoc, n); 2110d52d1586Sschwarze 211120fa2881Sschwarze if (MDOC_BODY != n->type) 211298b8f00aSschwarze return; 211320fa2881Sschwarze 211420fa2881Sschwarze /* 211520fa2881Sschwarze * The `Dl' (note "el" not "one") and `Bd -literal' and `Bd 211620fa2881Sschwarze * -unfilled' macros set MDOC_LITERAL on entrance to the body. 211720fa2881Sschwarze */ 211820fa2881Sschwarze 211920fa2881Sschwarze switch (n->tok) { 212049aff9f8Sschwarze case MDOC_Dl: 212120fa2881Sschwarze mdoc->flags |= MDOC_LITERAL; 212220fa2881Sschwarze break; 212349aff9f8Sschwarze case MDOC_Bd: 21248c62fbf5Sschwarze if (DISP_literal == n->norm->Bd.type) 212520fa2881Sschwarze mdoc->flags |= MDOC_LITERAL; 21268c62fbf5Sschwarze if (DISP_unfilled == n->norm->Bd.type) 212720fa2881Sschwarze mdoc->flags |= MDOC_LITERAL; 212820fa2881Sschwarze break; 212920fa2881Sschwarze default: 213020fa2881Sschwarze abort(); 213120fa2881Sschwarze /* NOTREACHED */ 213220fa2881Sschwarze } 213320fa2881Sschwarze } 213420fa2881Sschwarze 213598b8f00aSschwarze static void 213620fa2881Sschwarze post_dd(POST_ARGS) 213720fa2881Sschwarze { 213820fa2881Sschwarze struct mdoc_node *n; 213983af2bccSschwarze char *datestr; 214020fa2881Sschwarze 2141b058e777Sschwarze if (mdoc->meta.date) 2142b058e777Sschwarze free(mdoc->meta.date); 214320fa2881Sschwarze 2144b058e777Sschwarze n = mdoc->last; 2145b058e777Sschwarze if (NULL == n->child || '\0' == n->child->string[0]) { 2146231c7061Sschwarze mdoc->meta.date = mdoc->quick ? mandoc_strdup("") : 2147231c7061Sschwarze mandoc_normdate(mdoc->parse, NULL, n->line, n->pos); 21483fdead0cSschwarze goto out; 214920fa2881Sschwarze } 215020fa2881Sschwarze 215183af2bccSschwarze datestr = NULL; 215283af2bccSschwarze mdoc_deroff(&datestr, n); 215383af2bccSschwarze if (mdoc->quick) 215483af2bccSschwarze mdoc->meta.date = datestr; 215583af2bccSschwarze else { 215683af2bccSschwarze mdoc->meta.date = mandoc_normdate(mdoc->parse, 215783af2bccSschwarze datestr, n->line, n->pos); 215883af2bccSschwarze free(datestr); 215904e980cbSschwarze } 21603fdead0cSschwarze out: 21613fdead0cSschwarze mdoc_node_delete(mdoc, n); 216220fa2881Sschwarze } 216320fa2881Sschwarze 216498b8f00aSschwarze static void 216520fa2881Sschwarze post_dt(POST_ARGS) 216620fa2881Sschwarze { 216720fa2881Sschwarze struct mdoc_node *nn, *n; 216820fa2881Sschwarze const char *cp; 216920fa2881Sschwarze char *p; 217020fa2881Sschwarze 217120fa2881Sschwarze n = mdoc->last; 217220fa2881Sschwarze 217320fa2881Sschwarze free(mdoc->meta.title); 21743fdead0cSschwarze free(mdoc->meta.msec); 217520fa2881Sschwarze free(mdoc->meta.vol); 217620fa2881Sschwarze free(mdoc->meta.arch); 217720fa2881Sschwarze 21783fdead0cSschwarze mdoc->meta.title = NULL; 21793fdead0cSschwarze mdoc->meta.msec = NULL; 21803fdead0cSschwarze mdoc->meta.vol = NULL; 21813fdead0cSschwarze mdoc->meta.arch = NULL; 218220fa2881Sschwarze 218351fcab2fSschwarze /* First check that all characters are uppercase. */ 218420fa2881Sschwarze 218520fa2881Sschwarze if (NULL != (nn = n->child)) 218620fa2881Sschwarze for (p = nn->string; *p; p++) { 218704e980cbSschwarze if (toupper((unsigned char)*p) == *p) 218820fa2881Sschwarze continue; 2189bd594191Sschwarze mandoc_vmsg(MANDOCERR_TITLE_CASE, 219051fcab2fSschwarze mdoc->parse, nn->line, 219151fcab2fSschwarze nn->pos + (p - nn->string), 2192bd594191Sschwarze "Dt %s", nn->string); 219320fa2881Sschwarze break; 219420fa2881Sschwarze } 219520fa2881Sschwarze 21963fdead0cSschwarze /* No argument: msec and arch remain NULL. */ 219720fa2881Sschwarze 219820fa2881Sschwarze if (NULL == (nn = n->child)) { 21993fdead0cSschwarze mandoc_msg(MANDOCERR_DT_NOTITLE, 22003fdead0cSschwarze mdoc->parse, n->line, n->pos, "Dt"); 22013fdead0cSschwarze mdoc->meta.title = mandoc_strdup("UNTITLED"); 220220fa2881Sschwarze mdoc->meta.vol = mandoc_strdup("LOCAL"); 22033fdead0cSschwarze goto out; 220420fa2881Sschwarze } 220520fa2881Sschwarze 22063fdead0cSschwarze /* One argument: msec and arch remain NULL. */ 220720fa2881Sschwarze 220849aff9f8Sschwarze mdoc->meta.title = mandoc_strdup( 22093fdead0cSschwarze '\0' == nn->string[0] ? "UNTITLED" : nn->string); 221020fa2881Sschwarze 221120fa2881Sschwarze if (NULL == (nn = nn->next)) { 22123fdead0cSschwarze mandoc_vmsg(MANDOCERR_MSEC_MISSING, 22133fdead0cSschwarze mdoc->parse, n->line, n->pos, 22143fdead0cSschwarze "Dt %s", mdoc->meta.title); 221520fa2881Sschwarze mdoc->meta.vol = mandoc_strdup("LOCAL"); 22163fdead0cSschwarze goto out; 221720fa2881Sschwarze } 221820fa2881Sschwarze 221920fa2881Sschwarze /* Handles: `.Dt TITLE SEC' 222049aff9f8Sschwarze * title = TITLE, 222149aff9f8Sschwarze * volume = SEC is msec ? format(msec) : SEC, 222220fa2881Sschwarze * msec = SEC is msec ? atoi(msec) : 0, 222320fa2881Sschwarze * arch = NULL 222420fa2881Sschwarze */ 222520fa2881Sschwarze 222688ec69e3Sschwarze cp = mandoc_a2msec(nn->string); 222720fa2881Sschwarze if (cp) { 222820fa2881Sschwarze mdoc->meta.vol = mandoc_strdup(cp); 222920fa2881Sschwarze mdoc->meta.msec = mandoc_strdup(nn->string); 223020fa2881Sschwarze } else { 2231bd594191Sschwarze mandoc_vmsg(MANDOCERR_MSEC_BAD, mdoc->parse, 2232bd594191Sschwarze nn->line, nn->pos, "Dt ... %s", nn->string); 223320fa2881Sschwarze mdoc->meta.vol = mandoc_strdup(nn->string); 223420fa2881Sschwarze mdoc->meta.msec = mandoc_strdup(nn->string); 223520fa2881Sschwarze } 223620fa2881Sschwarze 2237a47bc3bcSschwarze /* Handle an optional architecture */ 223820fa2881Sschwarze 2239a47bc3bcSschwarze if ((nn = nn->next) != NULL) { 2240b94f27c5Sschwarze for (p = nn->string; *p; p++) 2241b94f27c5Sschwarze *p = tolower((unsigned char)*p); 2242b94f27c5Sschwarze mdoc->meta.arch = mandoc_strdup(nn->string); 224320fa2881Sschwarze } 224420fa2881Sschwarze 224520fa2881Sschwarze /* Ignore any subsequent parameters... */ 224620fa2881Sschwarze /* FIXME: warn about subsequent parameters. */ 22473fdead0cSschwarze out: 22483fdead0cSschwarze mdoc_node_delete(mdoc, n); 224920fa2881Sschwarze } 225020fa2881Sschwarze 225198b8f00aSschwarze static void 2252992063deSschwarze post_bx(POST_ARGS) 2253992063deSschwarze { 2254992063deSschwarze struct mdoc_node *n; 2255992063deSschwarze 2256992063deSschwarze /* 2257992063deSschwarze * Make `Bx's second argument always start with an uppercase 2258992063deSschwarze * letter. Groff checks if it's an "accepted" term, but we just 2259992063deSschwarze * uppercase blindly. 2260992063deSschwarze */ 2261992063deSschwarze 2262992063deSschwarze n = mdoc->last->child; 2263992063deSschwarze if (n && NULL != (n = n->next)) 226449aff9f8Sschwarze *n->string = (char)toupper((unsigned char)*n->string); 2265992063deSschwarze } 2266992063deSschwarze 226798b8f00aSschwarze static void 226820fa2881Sschwarze post_os(POST_ARGS) 226920fa2881Sschwarze { 227020fa2881Sschwarze #ifndef OSNAME 227120fa2881Sschwarze struct utsname utsname; 22724c468128Sschwarze static char *defbuf; 227320fa2881Sschwarze #endif 22744c468128Sschwarze struct mdoc_node *n; 227520fa2881Sschwarze 227620fa2881Sschwarze n = mdoc->last; 227720fa2881Sschwarze 227820fa2881Sschwarze /* 2279353fa9ecSschwarze * Set the operating system by way of the `Os' macro. 2280353fa9ecSschwarze * The order of precedence is: 2281353fa9ecSschwarze * 1. the argument of the `Os' macro, unless empty 2282353fa9ecSschwarze * 2. the -Ios=foo command line argument, if provided 2283353fa9ecSschwarze * 3. -DOSNAME="\"foo\"", if provided during compilation 2284353fa9ecSschwarze * 4. "sysname release" from uname(3) 228520fa2881Sschwarze */ 228620fa2881Sschwarze 228720fa2881Sschwarze free(mdoc->meta.os); 228883af2bccSschwarze mdoc->meta.os = NULL; 228983af2bccSschwarze mdoc_deroff(&mdoc->meta.os, n); 229083af2bccSschwarze if (mdoc->meta.os) 22913fdead0cSschwarze goto out; 22924c468128Sschwarze 2293353fa9ecSschwarze if (mdoc->defos) { 2294353fa9ecSschwarze mdoc->meta.os = mandoc_strdup(mdoc->defos); 22953fdead0cSschwarze goto out; 2296353fa9ecSschwarze } 22974c468128Sschwarze 229820fa2881Sschwarze #ifdef OSNAME 22994c468128Sschwarze mdoc->meta.os = mandoc_strdup(OSNAME); 230020fa2881Sschwarze #else /*!OSNAME */ 23014c468128Sschwarze if (NULL == defbuf) { 2302a35fc07aSschwarze if (-1 == uname(&utsname)) { 2303f79e7afeSschwarze mandoc_msg(MANDOCERR_OS_UNAME, mdoc->parse, 2304f79e7afeSschwarze n->line, n->pos, "Os"); 23054c468128Sschwarze defbuf = mandoc_strdup("UNKNOWN"); 2306a450f7c4Sschwarze } else 2307a450f7c4Sschwarze mandoc_asprintf(&defbuf, "%s %s", 2308a450f7c4Sschwarze utsname.sysname, utsname.release); 230920fa2881Sschwarze } 23104c468128Sschwarze mdoc->meta.os = mandoc_strdup(defbuf); 231120fa2881Sschwarze #endif /*!OSNAME*/ 23123fdead0cSschwarze 23133fdead0cSschwarze out: 23143fdead0cSschwarze mdoc_node_delete(mdoc, n); 231520fa2881Sschwarze } 231620fa2881Sschwarze 2317e214f641Sschwarze /* 2318e214f641Sschwarze * If no argument is provided, 2319e214f641Sschwarze * fill in the name of the current manual page. 2320e214f641Sschwarze */ 232198b8f00aSschwarze static void 2322e214f641Sschwarze post_ex(POST_ARGS) 232320fa2881Sschwarze { 2324e214f641Sschwarze struct mdoc_node *n; 232520fa2881Sschwarze 232620fa2881Sschwarze n = mdoc->last; 232720fa2881Sschwarze 232820fa2881Sschwarze if (n->child) 232998b8f00aSschwarze return; 233020fa2881Sschwarze 2331e214f641Sschwarze if (mdoc->meta.name == NULL) { 2332bd594191Sschwarze mandoc_msg(MANDOCERR_EX_NONAME, mdoc->parse, 2333bd594191Sschwarze n->line, n->pos, "Ex"); 233498b8f00aSschwarze return; 2335e214f641Sschwarze } 233620fa2881Sschwarze 233720fa2881Sschwarze mdoc->next = MDOC_NEXT_CHILD; 233898b8f00aSschwarze mdoc_word_alloc(mdoc, n->line, n->pos, mdoc->meta.name); 2339e214f641Sschwarze mdoc->last = n; 234020fa2881Sschwarze } 234120fa2881Sschwarze 234219a69263Sschwarze static enum mdoc_sec 234319a69263Sschwarze a2sec(const char *p) 234419a69263Sschwarze { 234519a69263Sschwarze int i; 234619a69263Sschwarze 234719a69263Sschwarze for (i = 0; i < (int)SEC__MAX; i++) 234819a69263Sschwarze if (secnames[i] && 0 == strcmp(p, secnames[i])) 234919a69263Sschwarze return((enum mdoc_sec)i); 235019a69263Sschwarze 235119a69263Sschwarze return(SEC_CUSTOM); 235219a69263Sschwarze } 235319a69263Sschwarze 235419a69263Sschwarze static size_t 235519a69263Sschwarze macro2len(enum mdoct macro) 235619a69263Sschwarze { 235719a69263Sschwarze 235819a69263Sschwarze switch (macro) { 235949aff9f8Sschwarze case MDOC_Ad: 236019a69263Sschwarze return(12); 236149aff9f8Sschwarze case MDOC_Ao: 236219a69263Sschwarze return(12); 236349aff9f8Sschwarze case MDOC_An: 236419a69263Sschwarze return(12); 236549aff9f8Sschwarze case MDOC_Aq: 236619a69263Sschwarze return(12); 236749aff9f8Sschwarze case MDOC_Ar: 236819a69263Sschwarze return(12); 236949aff9f8Sschwarze case MDOC_Bo: 237019a69263Sschwarze return(12); 237149aff9f8Sschwarze case MDOC_Bq: 237219a69263Sschwarze return(12); 237349aff9f8Sschwarze case MDOC_Cd: 237419a69263Sschwarze return(12); 237549aff9f8Sschwarze case MDOC_Cm: 237619a69263Sschwarze return(10); 237749aff9f8Sschwarze case MDOC_Do: 237819a69263Sschwarze return(10); 237949aff9f8Sschwarze case MDOC_Dq: 238019a69263Sschwarze return(12); 238149aff9f8Sschwarze case MDOC_Dv: 238219a69263Sschwarze return(12); 238349aff9f8Sschwarze case MDOC_Eo: 238419a69263Sschwarze return(12); 238549aff9f8Sschwarze case MDOC_Em: 238619a69263Sschwarze return(10); 238749aff9f8Sschwarze case MDOC_Er: 238819a69263Sschwarze return(17); 238949aff9f8Sschwarze case MDOC_Ev: 239019a69263Sschwarze return(15); 239149aff9f8Sschwarze case MDOC_Fa: 239219a69263Sschwarze return(12); 239349aff9f8Sschwarze case MDOC_Fl: 239419a69263Sschwarze return(10); 239549aff9f8Sschwarze case MDOC_Fo: 239619a69263Sschwarze return(16); 239749aff9f8Sschwarze case MDOC_Fn: 239819a69263Sschwarze return(16); 239949aff9f8Sschwarze case MDOC_Ic: 240019a69263Sschwarze return(10); 240149aff9f8Sschwarze case MDOC_Li: 240219a69263Sschwarze return(16); 240349aff9f8Sschwarze case MDOC_Ms: 240419a69263Sschwarze return(6); 240549aff9f8Sschwarze case MDOC_Nm: 240619a69263Sschwarze return(10); 240749aff9f8Sschwarze case MDOC_No: 240819a69263Sschwarze return(12); 240949aff9f8Sschwarze case MDOC_Oo: 241019a69263Sschwarze return(10); 241149aff9f8Sschwarze case MDOC_Op: 241219a69263Sschwarze return(14); 241349aff9f8Sschwarze case MDOC_Pa: 241419a69263Sschwarze return(32); 241549aff9f8Sschwarze case MDOC_Pf: 241619a69263Sschwarze return(12); 241749aff9f8Sschwarze case MDOC_Po: 241819a69263Sschwarze return(12); 241949aff9f8Sschwarze case MDOC_Pq: 242019a69263Sschwarze return(12); 242149aff9f8Sschwarze case MDOC_Ql: 242219a69263Sschwarze return(16); 242349aff9f8Sschwarze case MDOC_Qo: 242419a69263Sschwarze return(12); 242549aff9f8Sschwarze case MDOC_So: 242619a69263Sschwarze return(12); 242749aff9f8Sschwarze case MDOC_Sq: 242819a69263Sschwarze return(12); 242949aff9f8Sschwarze case MDOC_Sy: 243019a69263Sschwarze return(6); 243149aff9f8Sschwarze case MDOC_Sx: 243219a69263Sschwarze return(16); 243349aff9f8Sschwarze case MDOC_Tn: 243419a69263Sschwarze return(10); 243549aff9f8Sschwarze case MDOC_Va: 243619a69263Sschwarze return(12); 243749aff9f8Sschwarze case MDOC_Vt: 243819a69263Sschwarze return(12); 243949aff9f8Sschwarze case MDOC_Xr: 244019a69263Sschwarze return(10); 244119a69263Sschwarze default: 244219a69263Sschwarze break; 244319a69263Sschwarze }; 244419a69263Sschwarze return(0); 244519a69263Sschwarze } 2446