1*371584c2SYuri Pankov /* $Id: mdoc_validate.c,v 1.301 2016/01/08 17:48:09 schwarze Exp $ */ 295c635efSGarrett D'Amore /* 3698f87a4SGarrett D'Amore * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv> 4*371584c2SYuri Pankov * Copyright (c) 2010-2016 Ingo Schwarze <schwarze@openbsd.org> 5260e9a87SYuri Pankov * Copyright (c) 2010 Joerg Sonnenberger <joerg@netbsd.org> 695c635efSGarrett D'Amore * 795c635efSGarrett D'Amore * Permission to use, copy, modify, and distribute this software for any 895c635efSGarrett D'Amore * purpose with or without fee is hereby granted, provided that the above 995c635efSGarrett D'Amore * copyright notice and this permission notice appear in all copies. 1095c635efSGarrett D'Amore * 11*371584c2SYuri Pankov * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES 1295c635efSGarrett D'Amore * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13*371584c2SYuri Pankov * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR 1495c635efSGarrett D'Amore * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1595c635efSGarrett D'Amore * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1695c635efSGarrett D'Amore * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1795c635efSGarrett D'Amore * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1895c635efSGarrett D'Amore */ 1995c635efSGarrett D'Amore #include "config.h" 2095c635efSGarrett D'Amore 21260e9a87SYuri Pankov #include <sys/types.h> 22698f87a4SGarrett D'Amore #ifndef OSNAME 2395c635efSGarrett D'Amore #include <sys/utsname.h> 2495c635efSGarrett D'Amore #endif 2595c635efSGarrett D'Amore 2695c635efSGarrett D'Amore #include <assert.h> 2795c635efSGarrett D'Amore #include <ctype.h> 2895c635efSGarrett D'Amore #include <limits.h> 2995c635efSGarrett D'Amore #include <stdio.h> 3095c635efSGarrett D'Amore #include <stdlib.h> 3195c635efSGarrett D'Amore #include <string.h> 3295c635efSGarrett D'Amore #include <time.h> 3395c635efSGarrett D'Amore 34260e9a87SYuri Pankov #include "mandoc_aux.h" 35*371584c2SYuri Pankov #include "mandoc.h" 36*371584c2SYuri Pankov #include "roff.h" 37*371584c2SYuri Pankov #include "mdoc.h" 3895c635efSGarrett D'Amore #include "libmandoc.h" 39*371584c2SYuri Pankov #include "roff_int.h" 40*371584c2SYuri Pankov #include "libmdoc.h" 4195c635efSGarrett D'Amore 4295c635efSGarrett D'Amore /* FIXME: .Bl -diag can't have non-text children in HEAD. */ 4395c635efSGarrett D'Amore 44*371584c2SYuri Pankov #define POST_ARGS struct roff_man *mdoc 4595c635efSGarrett D'Amore 4695c635efSGarrett D'Amore enum check_ineq { 4795c635efSGarrett D'Amore CHECK_LT, 4895c635efSGarrett D'Amore CHECK_GT, 4995c635efSGarrett D'Amore CHECK_EQ 5095c635efSGarrett D'Amore }; 5195c635efSGarrett D'Amore 52260e9a87SYuri Pankov typedef void (*v_post)(POST_ARGS); 5395c635efSGarrett D'Amore 54*371584c2SYuri Pankov static void check_text(struct roff_man *, int, int, char *); 55*371584c2SYuri Pankov static void check_argv(struct roff_man *, 56*371584c2SYuri Pankov struct roff_node *, struct mdoc_argv *); 57*371584c2SYuri Pankov static void check_args(struct roff_man *, struct roff_node *); 58*371584c2SYuri Pankov static int child_an(const struct roff_node *); 59*371584c2SYuri Pankov static size_t macro2len(int); 60260e9a87SYuri Pankov static void rewrite_macro2len(char **); 61260e9a87SYuri Pankov 62260e9a87SYuri Pankov static void post_an(POST_ARGS); 63*371584c2SYuri Pankov static void post_an_norm(POST_ARGS); 64260e9a87SYuri Pankov static void post_at(POST_ARGS); 65*371584c2SYuri Pankov static void post_bd(POST_ARGS); 66260e9a87SYuri Pankov static void post_bf(POST_ARGS); 67260e9a87SYuri Pankov static void post_bk(POST_ARGS); 68260e9a87SYuri Pankov static void post_bl(POST_ARGS); 69260e9a87SYuri Pankov static void post_bl_block(POST_ARGS); 70260e9a87SYuri Pankov static void post_bl_block_tag(POST_ARGS); 71260e9a87SYuri Pankov static void post_bl_head(POST_ARGS); 72*371584c2SYuri Pankov static void post_bl_norm(POST_ARGS); 73260e9a87SYuri Pankov static void post_bx(POST_ARGS); 74260e9a87SYuri Pankov static void post_defaults(POST_ARGS); 75*371584c2SYuri Pankov static void post_display(POST_ARGS); 76260e9a87SYuri Pankov static void post_dd(POST_ARGS); 77260e9a87SYuri Pankov static void post_dt(POST_ARGS); 78260e9a87SYuri Pankov static void post_en(POST_ARGS); 79260e9a87SYuri Pankov static void post_es(POST_ARGS); 80260e9a87SYuri Pankov static void post_eoln(POST_ARGS); 81260e9a87SYuri Pankov static void post_ex(POST_ARGS); 82260e9a87SYuri Pankov static void post_fa(POST_ARGS); 83260e9a87SYuri Pankov static void post_fn(POST_ARGS); 84260e9a87SYuri Pankov static void post_fname(POST_ARGS); 85260e9a87SYuri Pankov static void post_fo(POST_ARGS); 86260e9a87SYuri Pankov static void post_hyph(POST_ARGS); 87260e9a87SYuri Pankov static void post_ignpar(POST_ARGS); 88260e9a87SYuri Pankov static void post_it(POST_ARGS); 89260e9a87SYuri Pankov static void post_lb(POST_ARGS); 90260e9a87SYuri Pankov static void post_nd(POST_ARGS); 91260e9a87SYuri Pankov static void post_nm(POST_ARGS); 92260e9a87SYuri Pankov static void post_ns(POST_ARGS); 93*371584c2SYuri Pankov static void post_obsolete(POST_ARGS); 94260e9a87SYuri Pankov static void post_os(POST_ARGS); 95260e9a87SYuri Pankov static void post_par(POST_ARGS); 96*371584c2SYuri Pankov static void post_prevpar(POST_ARGS); 97260e9a87SYuri Pankov static void post_root(POST_ARGS); 98260e9a87SYuri Pankov static void post_rs(POST_ARGS); 99260e9a87SYuri Pankov static void post_sh(POST_ARGS); 100260e9a87SYuri Pankov static void post_sh_head(POST_ARGS); 101260e9a87SYuri Pankov static void post_sh_name(POST_ARGS); 102260e9a87SYuri Pankov static void post_sh_see_also(POST_ARGS); 103260e9a87SYuri Pankov static void post_sh_authors(POST_ARGS); 104260e9a87SYuri Pankov static void post_sm(POST_ARGS); 105260e9a87SYuri Pankov static void post_st(POST_ARGS); 106*371584c2SYuri Pankov static void post_std(POST_ARGS); 107*371584c2SYuri Pankov 108*371584c2SYuri Pankov static v_post mdoc_valids[MDOC_MAX] = { 109*371584c2SYuri Pankov NULL, /* Ap */ 110*371584c2SYuri Pankov post_dd, /* Dd */ 111*371584c2SYuri Pankov post_dt, /* Dt */ 112*371584c2SYuri Pankov post_os, /* Os */ 113*371584c2SYuri Pankov post_sh, /* Sh */ 114*371584c2SYuri Pankov post_ignpar, /* Ss */ 115*371584c2SYuri Pankov post_par, /* Pp */ 116*371584c2SYuri Pankov post_display, /* D1 */ 117*371584c2SYuri Pankov post_display, /* Dl */ 118*371584c2SYuri Pankov post_display, /* Bd */ 119*371584c2SYuri Pankov NULL, /* Ed */ 120*371584c2SYuri Pankov post_bl, /* Bl */ 121*371584c2SYuri Pankov NULL, /* El */ 122*371584c2SYuri Pankov post_it, /* It */ 123*371584c2SYuri Pankov NULL, /* Ad */ 124*371584c2SYuri Pankov post_an, /* An */ 125*371584c2SYuri Pankov post_defaults, /* Ar */ 126*371584c2SYuri Pankov NULL, /* Cd */ 127*371584c2SYuri Pankov NULL, /* Cm */ 128*371584c2SYuri Pankov NULL, /* Dv */ 129*371584c2SYuri Pankov NULL, /* Er */ 130*371584c2SYuri Pankov NULL, /* Ev */ 131*371584c2SYuri Pankov post_ex, /* Ex */ 132*371584c2SYuri Pankov post_fa, /* Fa */ 133*371584c2SYuri Pankov NULL, /* Fd */ 134*371584c2SYuri Pankov NULL, /* Fl */ 135*371584c2SYuri Pankov post_fn, /* Fn */ 136*371584c2SYuri Pankov NULL, /* Ft */ 137*371584c2SYuri Pankov NULL, /* Ic */ 138*371584c2SYuri Pankov NULL, /* In */ 139*371584c2SYuri Pankov post_defaults, /* Li */ 140*371584c2SYuri Pankov post_nd, /* Nd */ 141*371584c2SYuri Pankov post_nm, /* Nm */ 142*371584c2SYuri Pankov NULL, /* Op */ 143*371584c2SYuri Pankov post_obsolete, /* Ot */ 144*371584c2SYuri Pankov post_defaults, /* Pa */ 145*371584c2SYuri Pankov post_std, /* Rv */ 146*371584c2SYuri Pankov post_st, /* St */ 147*371584c2SYuri Pankov NULL, /* Va */ 148*371584c2SYuri Pankov NULL, /* Vt */ 149*371584c2SYuri Pankov NULL, /* Xr */ 150*371584c2SYuri Pankov NULL, /* %A */ 151*371584c2SYuri Pankov post_hyph, /* %B */ /* FIXME: can be used outside Rs/Re. */ 152*371584c2SYuri Pankov NULL, /* %D */ 153*371584c2SYuri Pankov NULL, /* %I */ 154*371584c2SYuri Pankov NULL, /* %J */ 155*371584c2SYuri Pankov post_hyph, /* %N */ 156*371584c2SYuri Pankov post_hyph, /* %O */ 157*371584c2SYuri Pankov NULL, /* %P */ 158*371584c2SYuri Pankov post_hyph, /* %R */ 159*371584c2SYuri Pankov post_hyph, /* %T */ /* FIXME: can be used outside Rs/Re. */ 160*371584c2SYuri Pankov NULL, /* %V */ 161*371584c2SYuri Pankov NULL, /* Ac */ 162*371584c2SYuri Pankov NULL, /* Ao */ 163*371584c2SYuri Pankov NULL, /* Aq */ 164*371584c2SYuri Pankov post_at, /* At */ 165*371584c2SYuri Pankov NULL, /* Bc */ 166*371584c2SYuri Pankov post_bf, /* Bf */ 167*371584c2SYuri Pankov NULL, /* Bo */ 168*371584c2SYuri Pankov NULL, /* Bq */ 169*371584c2SYuri Pankov NULL, /* Bsx */ 170*371584c2SYuri Pankov post_bx, /* Bx */ 171*371584c2SYuri Pankov post_obsolete, /* Db */ 172*371584c2SYuri Pankov NULL, /* Dc */ 173*371584c2SYuri Pankov NULL, /* Do */ 174*371584c2SYuri Pankov NULL, /* Dq */ 175*371584c2SYuri Pankov NULL, /* Ec */ 176*371584c2SYuri Pankov NULL, /* Ef */ 177*371584c2SYuri Pankov NULL, /* Em */ 178*371584c2SYuri Pankov NULL, /* Eo */ 179*371584c2SYuri Pankov NULL, /* Fx */ 180*371584c2SYuri Pankov NULL, /* Ms */ 181*371584c2SYuri Pankov NULL, /* No */ 182*371584c2SYuri Pankov post_ns, /* Ns */ 183*371584c2SYuri Pankov NULL, /* Nx */ 184*371584c2SYuri Pankov NULL, /* Ox */ 185*371584c2SYuri Pankov NULL, /* Pc */ 186*371584c2SYuri Pankov NULL, /* Pf */ 187*371584c2SYuri Pankov NULL, /* Po */ 188*371584c2SYuri Pankov NULL, /* Pq */ 189*371584c2SYuri Pankov NULL, /* Qc */ 190*371584c2SYuri Pankov NULL, /* Ql */ 191*371584c2SYuri Pankov NULL, /* Qo */ 192*371584c2SYuri Pankov NULL, /* Qq */ 193*371584c2SYuri Pankov NULL, /* Re */ 194*371584c2SYuri Pankov post_rs, /* Rs */ 195*371584c2SYuri Pankov NULL, /* Sc */ 196*371584c2SYuri Pankov NULL, /* So */ 197*371584c2SYuri Pankov NULL, /* Sq */ 198*371584c2SYuri Pankov post_sm, /* Sm */ 199*371584c2SYuri Pankov post_hyph, /* Sx */ 200*371584c2SYuri Pankov NULL, /* Sy */ 201*371584c2SYuri Pankov NULL, /* Tn */ 202*371584c2SYuri Pankov NULL, /* Ux */ 203*371584c2SYuri Pankov NULL, /* Xc */ 204*371584c2SYuri Pankov NULL, /* Xo */ 205*371584c2SYuri Pankov post_fo, /* Fo */ 206*371584c2SYuri Pankov NULL, /* Fc */ 207*371584c2SYuri Pankov NULL, /* Oo */ 208*371584c2SYuri Pankov NULL, /* Oc */ 209*371584c2SYuri Pankov post_bk, /* Bk */ 210*371584c2SYuri Pankov NULL, /* Ek */ 211*371584c2SYuri Pankov post_eoln, /* Bt */ 212*371584c2SYuri Pankov NULL, /* Hf */ 213*371584c2SYuri Pankov post_obsolete, /* Fr */ 214*371584c2SYuri Pankov post_eoln, /* Ud */ 215*371584c2SYuri Pankov post_lb, /* Lb */ 216*371584c2SYuri Pankov post_par, /* Lp */ 217*371584c2SYuri Pankov NULL, /* Lk */ 218*371584c2SYuri Pankov post_defaults, /* Mt */ 219*371584c2SYuri Pankov NULL, /* Brq */ 220*371584c2SYuri Pankov NULL, /* Bro */ 221*371584c2SYuri Pankov NULL, /* Brc */ 222*371584c2SYuri Pankov NULL, /* %C */ 223*371584c2SYuri Pankov post_es, /* Es */ 224*371584c2SYuri Pankov post_en, /* En */ 225*371584c2SYuri Pankov NULL, /* Dx */ 226*371584c2SYuri Pankov NULL, /* %Q */ 227*371584c2SYuri Pankov post_par, /* br */ 228*371584c2SYuri Pankov post_par, /* sp */ 229*371584c2SYuri Pankov NULL, /* %U */ 230*371584c2SYuri Pankov NULL, /* Ta */ 231*371584c2SYuri Pankov NULL, /* ll */ 23295c635efSGarrett D'Amore }; 23395c635efSGarrett D'Amore 23495c635efSGarrett D'Amore #define RSORD_MAX 14 /* Number of `Rs' blocks. */ 23595c635efSGarrett D'Amore 236*371584c2SYuri Pankov static const int rsord[RSORD_MAX] = { 23795c635efSGarrett D'Amore MDOC__A, 23895c635efSGarrett D'Amore MDOC__T, 23995c635efSGarrett D'Amore MDOC__B, 24095c635efSGarrett D'Amore MDOC__I, 24195c635efSGarrett D'Amore MDOC__J, 24295c635efSGarrett D'Amore MDOC__R, 24395c635efSGarrett D'Amore MDOC__N, 24495c635efSGarrett D'Amore MDOC__V, 245698f87a4SGarrett D'Amore MDOC__U, 24695c635efSGarrett D'Amore MDOC__P, 24795c635efSGarrett D'Amore MDOC__Q, 24895c635efSGarrett D'Amore MDOC__C, 249698f87a4SGarrett D'Amore MDOC__D, 250698f87a4SGarrett D'Amore MDOC__O 25195c635efSGarrett D'Amore }; 25295c635efSGarrett D'Amore 25395c635efSGarrett D'Amore static const char * const secnames[SEC__MAX] = { 25495c635efSGarrett D'Amore NULL, 25595c635efSGarrett D'Amore "NAME", 25695c635efSGarrett D'Amore "LIBRARY", 25795c635efSGarrett D'Amore "SYNOPSIS", 25895c635efSGarrett D'Amore "DESCRIPTION", 259260e9a87SYuri Pankov "CONTEXT", 26095c635efSGarrett D'Amore "IMPLEMENTATION NOTES", 26195c635efSGarrett D'Amore "RETURN VALUES", 26295c635efSGarrett D'Amore "ENVIRONMENT", 26395c635efSGarrett D'Amore "FILES", 26495c635efSGarrett D'Amore "EXIT STATUS", 26595c635efSGarrett D'Amore "EXAMPLES", 26695c635efSGarrett D'Amore "DIAGNOSTICS", 26795c635efSGarrett D'Amore "COMPATIBILITY", 26895c635efSGarrett D'Amore "ERRORS", 26995c635efSGarrett D'Amore "SEE ALSO", 27095c635efSGarrett D'Amore "STANDARDS", 27195c635efSGarrett D'Amore "HISTORY", 27295c635efSGarrett D'Amore "AUTHORS", 27395c635efSGarrett D'Amore "CAVEATS", 27495c635efSGarrett D'Amore "BUGS", 27595c635efSGarrett D'Amore "SECURITY CONSIDERATIONS", 27695c635efSGarrett D'Amore NULL 27795c635efSGarrett D'Amore }; 27895c635efSGarrett D'Amore 279260e9a87SYuri Pankov 280260e9a87SYuri Pankov void 281*371584c2SYuri Pankov mdoc_node_validate(struct roff_man *mdoc) 28295c635efSGarrett D'Amore { 283*371584c2SYuri Pankov struct roff_node *n; 284*371584c2SYuri Pankov v_post *p; 28595c635efSGarrett D'Amore 286*371584c2SYuri Pankov n = mdoc->last; 287*371584c2SYuri Pankov mdoc->last = mdoc->last->child; 288*371584c2SYuri Pankov while (mdoc->last != NULL) { 289*371584c2SYuri Pankov mdoc_node_validate(mdoc); 290*371584c2SYuri Pankov if (mdoc->last == n) 291*371584c2SYuri Pankov mdoc->last = mdoc->last->child; 292*371584c2SYuri Pankov else 293*371584c2SYuri Pankov mdoc->last = mdoc->last->next; 294*371584c2SYuri Pankov } 295*371584c2SYuri Pankov 296*371584c2SYuri Pankov mdoc->last = n; 297*371584c2SYuri Pankov mdoc->next = ROFF_NEXT_SIBLING; 29895c635efSGarrett D'Amore switch (n->type) { 299*371584c2SYuri Pankov case ROFFT_TEXT: 300260e9a87SYuri Pankov if (n->sec != SEC_SYNOPSIS || n->parent->tok != MDOC_Fd) 301260e9a87SYuri Pankov check_text(mdoc, n->line, n->pos, n->string); 30295c635efSGarrett D'Amore break; 303*371584c2SYuri Pankov case ROFFT_EQN: 304*371584c2SYuri Pankov case ROFFT_TBL: 30595c635efSGarrett D'Amore break; 306*371584c2SYuri Pankov case ROFFT_ROOT: 307260e9a87SYuri Pankov post_root(mdoc); 30895c635efSGarrett D'Amore break; 30995c635efSGarrett D'Amore default: 310*371584c2SYuri Pankov check_args(mdoc, mdoc->last); 31195c635efSGarrett D'Amore 312260e9a87SYuri Pankov /* 313260e9a87SYuri Pankov * Closing delimiters are not special at the 314260e9a87SYuri Pankov * beginning of a block, opening delimiters 315260e9a87SYuri Pankov * are not special at the end. 316260e9a87SYuri Pankov */ 31795c635efSGarrett D'Amore 318260e9a87SYuri Pankov if (n->child != NULL) 319260e9a87SYuri Pankov n->child->flags &= ~MDOC_DELIMC; 320260e9a87SYuri Pankov if (n->last != NULL) 321260e9a87SYuri Pankov n->last->flags &= ~MDOC_DELIMO; 32295c635efSGarrett D'Amore 323260e9a87SYuri Pankov /* Call the macro's postprocessor. */ 32495c635efSGarrett D'Amore 325*371584c2SYuri Pankov p = mdoc_valids + n->tok; 326260e9a87SYuri Pankov if (*p) 327260e9a87SYuri Pankov (*p)(mdoc); 328*371584c2SYuri Pankov if (mdoc->last == n) 329*371584c2SYuri Pankov mdoc_state(mdoc, n); 330260e9a87SYuri Pankov break; 331260e9a87SYuri Pankov } 33295c635efSGarrett D'Amore } 33395c635efSGarrett D'Amore 33495c635efSGarrett D'Amore static void 335*371584c2SYuri Pankov check_args(struct roff_man *mdoc, struct roff_node *n) 33695c635efSGarrett D'Amore { 33795c635efSGarrett D'Amore int i; 33895c635efSGarrett D'Amore 33995c635efSGarrett D'Amore if (NULL == n->args) 34095c635efSGarrett D'Amore return; 34195c635efSGarrett D'Amore 34295c635efSGarrett D'Amore assert(n->args->argc); 34395c635efSGarrett D'Amore for (i = 0; i < (int)n->args->argc; i++) 344698f87a4SGarrett D'Amore check_argv(mdoc, n, &n->args->argv[i]); 34595c635efSGarrett D'Amore } 34695c635efSGarrett D'Amore 34795c635efSGarrett D'Amore static void 348*371584c2SYuri Pankov check_argv(struct roff_man *mdoc, struct roff_node *n, struct mdoc_argv *v) 34995c635efSGarrett D'Amore { 35095c635efSGarrett D'Amore int i; 35195c635efSGarrett D'Amore 35295c635efSGarrett D'Amore for (i = 0; i < (int)v->sz; i++) 353698f87a4SGarrett D'Amore check_text(mdoc, v->line, v->pos, v->value[i]); 35495c635efSGarrett D'Amore } 35595c635efSGarrett D'Amore 35695c635efSGarrett D'Amore static void 357*371584c2SYuri Pankov check_text(struct roff_man *mdoc, int ln, int pos, char *p) 35895c635efSGarrett D'Amore { 35995c635efSGarrett D'Amore char *cp; 36095c635efSGarrett D'Amore 361698f87a4SGarrett D'Amore if (MDOC_LITERAL & mdoc->flags) 36295c635efSGarrett D'Amore return; 36395c635efSGarrett D'Amore 36495c635efSGarrett D'Amore for (cp = p; NULL != (p = strchr(p, '\t')); p++) 365260e9a87SYuri Pankov mandoc_msg(MANDOCERR_FI_TAB, mdoc->parse, 366260e9a87SYuri Pankov ln, pos + (int)(p - cp), NULL); 36795c635efSGarrett D'Amore } 36895c635efSGarrett D'Amore 369260e9a87SYuri Pankov static void 370*371584c2SYuri Pankov post_bl_norm(POST_ARGS) 37195c635efSGarrett D'Amore { 372*371584c2SYuri Pankov struct roff_node *n; 373260e9a87SYuri Pankov struct mdoc_argv *argv, *wa; 374260e9a87SYuri Pankov int i; 375260e9a87SYuri Pankov enum mdocargt mdoclt; 37695c635efSGarrett D'Amore enum mdoc_list lt; 37795c635efSGarrett D'Amore 378*371584c2SYuri Pankov n = mdoc->last->parent; 379*371584c2SYuri Pankov n->norm->Bl.type = LIST__NONE; 38095c635efSGarrett D'Amore 381260e9a87SYuri Pankov /* 38295c635efSGarrett D'Amore * First figure out which kind of list to use: bind ourselves to 38395c635efSGarrett D'Amore * the first mentioned list type and warn about any remaining 38495c635efSGarrett D'Amore * ones. If we find no list type, we default to LIST_item. 38595c635efSGarrett D'Amore */ 38695c635efSGarrett D'Amore 387260e9a87SYuri Pankov wa = (n->args == NULL) ? NULL : n->args->argv; 388260e9a87SYuri Pankov mdoclt = MDOC_ARG_MAX; 38995c635efSGarrett D'Amore for (i = 0; n->args && i < (int)n->args->argc; i++) { 390260e9a87SYuri Pankov argv = n->args->argv + i; 39195c635efSGarrett D'Amore lt = LIST__NONE; 392260e9a87SYuri Pankov switch (argv->arg) { 39395c635efSGarrett D'Amore /* Set list types. */ 394260e9a87SYuri Pankov case MDOC_Bullet: 39595c635efSGarrett D'Amore lt = LIST_bullet; 39695c635efSGarrett D'Amore break; 397260e9a87SYuri Pankov case MDOC_Dash: 39895c635efSGarrett D'Amore lt = LIST_dash; 39995c635efSGarrett D'Amore break; 400260e9a87SYuri Pankov case MDOC_Enum: 40195c635efSGarrett D'Amore lt = LIST_enum; 40295c635efSGarrett D'Amore break; 403260e9a87SYuri Pankov case MDOC_Hyphen: 40495c635efSGarrett D'Amore lt = LIST_hyphen; 40595c635efSGarrett D'Amore break; 406260e9a87SYuri Pankov case MDOC_Item: 40795c635efSGarrett D'Amore lt = LIST_item; 40895c635efSGarrett D'Amore break; 409260e9a87SYuri Pankov case MDOC_Tag: 41095c635efSGarrett D'Amore lt = LIST_tag; 41195c635efSGarrett D'Amore break; 412260e9a87SYuri Pankov case MDOC_Diag: 41395c635efSGarrett D'Amore lt = LIST_diag; 41495c635efSGarrett D'Amore break; 415260e9a87SYuri Pankov case MDOC_Hang: 41695c635efSGarrett D'Amore lt = LIST_hang; 41795c635efSGarrett D'Amore break; 418260e9a87SYuri Pankov case MDOC_Ohang: 41995c635efSGarrett D'Amore lt = LIST_ohang; 42095c635efSGarrett D'Amore break; 421260e9a87SYuri Pankov case MDOC_Inset: 42295c635efSGarrett D'Amore lt = LIST_inset; 42395c635efSGarrett D'Amore break; 424260e9a87SYuri Pankov case MDOC_Column: 42595c635efSGarrett D'Amore lt = LIST_column; 42695c635efSGarrett D'Amore break; 42795c635efSGarrett D'Amore /* Set list arguments. */ 428260e9a87SYuri Pankov case MDOC_Compact: 429260e9a87SYuri Pankov if (n->norm->Bl.comp) 430260e9a87SYuri Pankov mandoc_msg(MANDOCERR_ARG_REP, 431260e9a87SYuri Pankov mdoc->parse, argv->line, 432260e9a87SYuri Pankov argv->pos, "Bl -compact"); 433260e9a87SYuri Pankov n->norm->Bl.comp = 1; 43495c635efSGarrett D'Amore break; 435260e9a87SYuri Pankov case MDOC_Width: 436260e9a87SYuri Pankov wa = argv; 437260e9a87SYuri Pankov if (0 == argv->sz) { 438260e9a87SYuri Pankov mandoc_msg(MANDOCERR_ARG_EMPTY, 439260e9a87SYuri Pankov mdoc->parse, argv->line, 440260e9a87SYuri Pankov argv->pos, "Bl -width"); 441260e9a87SYuri Pankov n->norm->Bl.width = "0n"; 44295c635efSGarrett D'Amore break; 44395c635efSGarrett D'Amore } 444260e9a87SYuri Pankov if (NULL != n->norm->Bl.width) 445260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_ARG_REP, 446260e9a87SYuri Pankov mdoc->parse, argv->line, 447260e9a87SYuri Pankov argv->pos, "Bl -width %s", 448260e9a87SYuri Pankov argv->value[0]); 449260e9a87SYuri Pankov rewrite_macro2len(argv->value); 450260e9a87SYuri Pankov n->norm->Bl.width = argv->value[0]; 45195c635efSGarrett D'Amore break; 452260e9a87SYuri Pankov case MDOC_Offset: 453260e9a87SYuri Pankov if (0 == argv->sz) { 454260e9a87SYuri Pankov mandoc_msg(MANDOCERR_ARG_EMPTY, 455260e9a87SYuri Pankov mdoc->parse, argv->line, 456260e9a87SYuri Pankov argv->pos, "Bl -offset"); 45795c635efSGarrett D'Amore break; 45895c635efSGarrett D'Amore } 459260e9a87SYuri Pankov if (NULL != n->norm->Bl.offs) 460260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_ARG_REP, 461260e9a87SYuri Pankov mdoc->parse, argv->line, 462260e9a87SYuri Pankov argv->pos, "Bl -offset %s", 463260e9a87SYuri Pankov argv->value[0]); 464260e9a87SYuri Pankov rewrite_macro2len(argv->value); 465260e9a87SYuri Pankov n->norm->Bl.offs = argv->value[0]; 46695c635efSGarrett D'Amore break; 46795c635efSGarrett D'Amore default: 46895c635efSGarrett D'Amore continue; 46995c635efSGarrett D'Amore } 470260e9a87SYuri Pankov if (LIST__NONE == lt) 471260e9a87SYuri Pankov continue; 472260e9a87SYuri Pankov mdoclt = argv->arg; 47395c635efSGarrett D'Amore 47495c635efSGarrett D'Amore /* Check: multiple list types. */ 47595c635efSGarrett D'Amore 476260e9a87SYuri Pankov if (LIST__NONE != n->norm->Bl.type) { 477260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_BL_REP, 478260e9a87SYuri Pankov mdoc->parse, n->line, n->pos, 479260e9a87SYuri Pankov "Bl -%s", mdoc_argnames[argv->arg]); 480260e9a87SYuri Pankov continue; 48195c635efSGarrett D'Amore } 48295c635efSGarrett D'Amore 48395c635efSGarrett D'Amore /* The list type should come first. */ 48495c635efSGarrett D'Amore 485260e9a87SYuri Pankov if (n->norm->Bl.width || 486260e9a87SYuri Pankov n->norm->Bl.offs || 487260e9a87SYuri Pankov n->norm->Bl.comp) 488260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_BL_LATETYPE, 489260e9a87SYuri Pankov mdoc->parse, n->line, n->pos, "Bl -%s", 490260e9a87SYuri Pankov mdoc_argnames[n->args->argv[0].arg]); 491260e9a87SYuri Pankov 492260e9a87SYuri Pankov n->norm->Bl.type = lt; 493260e9a87SYuri Pankov if (LIST_column == lt) { 494260e9a87SYuri Pankov n->norm->Bl.ncols = argv->sz; 495260e9a87SYuri Pankov n->norm->Bl.cols = (void *)argv->value; 496260e9a87SYuri Pankov } 49795c635efSGarrett D'Amore } 49895c635efSGarrett D'Amore 49995c635efSGarrett D'Amore /* Allow lists to default to LIST_item. */ 50095c635efSGarrett D'Amore 50195c635efSGarrett D'Amore if (LIST__NONE == n->norm->Bl.type) { 502260e9a87SYuri Pankov mandoc_msg(MANDOCERR_BL_NOTYPE, mdoc->parse, 503260e9a87SYuri Pankov n->line, n->pos, "Bl"); 50495c635efSGarrett D'Amore n->norm->Bl.type = LIST_item; 50595c635efSGarrett D'Amore } 50695c635efSGarrett D'Amore 507260e9a87SYuri Pankov /* 50895c635efSGarrett D'Amore * Validate the width field. Some list types don't need width 50995c635efSGarrett D'Amore * types and should be warned about them. Others should have it 510698f87a4SGarrett D'Amore * and must also be warned. Yet others have a default and need 511698f87a4SGarrett D'Amore * no warning. 51295c635efSGarrett D'Amore */ 51395c635efSGarrett D'Amore 51495c635efSGarrett D'Amore switch (n->norm->Bl.type) { 515260e9a87SYuri Pankov case LIST_tag: 516698f87a4SGarrett D'Amore if (NULL == n->norm->Bl.width) 517260e9a87SYuri Pankov mandoc_msg(MANDOCERR_BL_NOWIDTH, mdoc->parse, 518260e9a87SYuri Pankov n->line, n->pos, "Bl -tag"); 51995c635efSGarrett D'Amore break; 520260e9a87SYuri Pankov case LIST_column: 521260e9a87SYuri Pankov case LIST_diag: 522260e9a87SYuri Pankov case LIST_ohang: 523260e9a87SYuri Pankov case LIST_inset: 524260e9a87SYuri Pankov case LIST_item: 52595c635efSGarrett D'Amore if (n->norm->Bl.width) 526260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_BL_SKIPW, mdoc->parse, 527260e9a87SYuri Pankov wa->line, wa->pos, "Bl -%s", 528260e9a87SYuri Pankov mdoc_argnames[mdoclt]); 52995c635efSGarrett D'Amore break; 530260e9a87SYuri Pankov case LIST_bullet: 531260e9a87SYuri Pankov case LIST_dash: 532260e9a87SYuri Pankov case LIST_hyphen: 533698f87a4SGarrett D'Amore if (NULL == n->norm->Bl.width) 534698f87a4SGarrett D'Amore n->norm->Bl.width = "2n"; 535698f87a4SGarrett D'Amore break; 536260e9a87SYuri Pankov case LIST_enum: 537698f87a4SGarrett D'Amore if (NULL == n->norm->Bl.width) 538698f87a4SGarrett D'Amore n->norm->Bl.width = "3n"; 539698f87a4SGarrett D'Amore break; 54095c635efSGarrett D'Amore default: 54195c635efSGarrett D'Amore break; 54295c635efSGarrett D'Amore } 54395c635efSGarrett D'Amore } 54495c635efSGarrett D'Amore 545260e9a87SYuri Pankov static void 546*371584c2SYuri Pankov post_bd(POST_ARGS) 54795c635efSGarrett D'Amore { 548*371584c2SYuri Pankov struct roff_node *n; 549260e9a87SYuri Pankov struct mdoc_argv *argv; 550260e9a87SYuri Pankov int i; 551260e9a87SYuri Pankov enum mdoc_disp dt; 55295c635efSGarrett D'Amore 553*371584c2SYuri Pankov n = mdoc->last; 55495c635efSGarrett D'Amore for (i = 0; n->args && i < (int)n->args->argc; i++) { 555260e9a87SYuri Pankov argv = n->args->argv + i; 55695c635efSGarrett D'Amore dt = DISP__NONE; 55795c635efSGarrett D'Amore 558260e9a87SYuri Pankov switch (argv->arg) { 559260e9a87SYuri Pankov case MDOC_Centred: 560260e9a87SYuri Pankov dt = DISP_centered; 56195c635efSGarrett D'Amore break; 562260e9a87SYuri Pankov case MDOC_Ragged: 56395c635efSGarrett D'Amore dt = DISP_ragged; 56495c635efSGarrett D'Amore break; 565260e9a87SYuri Pankov case MDOC_Unfilled: 56695c635efSGarrett D'Amore dt = DISP_unfilled; 56795c635efSGarrett D'Amore break; 568260e9a87SYuri Pankov case MDOC_Filled: 56995c635efSGarrett D'Amore dt = DISP_filled; 57095c635efSGarrett D'Amore break; 571260e9a87SYuri Pankov case MDOC_Literal: 57295c635efSGarrett D'Amore dt = DISP_literal; 57395c635efSGarrett D'Amore break; 574260e9a87SYuri Pankov case MDOC_File: 575260e9a87SYuri Pankov mandoc_msg(MANDOCERR_BD_FILE, mdoc->parse, 576260e9a87SYuri Pankov n->line, n->pos, NULL); 577260e9a87SYuri Pankov break; 578260e9a87SYuri Pankov case MDOC_Offset: 579260e9a87SYuri Pankov if (0 == argv->sz) { 580260e9a87SYuri Pankov mandoc_msg(MANDOCERR_ARG_EMPTY, 581260e9a87SYuri Pankov mdoc->parse, argv->line, 582260e9a87SYuri Pankov argv->pos, "Bd -offset"); 58395c635efSGarrett D'Amore break; 58495c635efSGarrett D'Amore } 585260e9a87SYuri Pankov if (NULL != n->norm->Bd.offs) 586260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_ARG_REP, 587260e9a87SYuri Pankov mdoc->parse, argv->line, 588260e9a87SYuri Pankov argv->pos, "Bd -offset %s", 589260e9a87SYuri Pankov argv->value[0]); 590260e9a87SYuri Pankov rewrite_macro2len(argv->value); 591260e9a87SYuri Pankov n->norm->Bd.offs = argv->value[0]; 59295c635efSGarrett D'Amore break; 593260e9a87SYuri Pankov case MDOC_Compact: 594260e9a87SYuri Pankov if (n->norm->Bd.comp) 595260e9a87SYuri Pankov mandoc_msg(MANDOCERR_ARG_REP, 596260e9a87SYuri Pankov mdoc->parse, argv->line, 597260e9a87SYuri Pankov argv->pos, "Bd -compact"); 598260e9a87SYuri Pankov n->norm->Bd.comp = 1; 59995c635efSGarrett D'Amore break; 60095c635efSGarrett D'Amore default: 60195c635efSGarrett D'Amore abort(); 60295c635efSGarrett D'Amore } 603260e9a87SYuri Pankov if (DISP__NONE == dt) 604260e9a87SYuri Pankov continue; 60595c635efSGarrett D'Amore 606260e9a87SYuri Pankov if (DISP__NONE == n->norm->Bd.type) 60795c635efSGarrett D'Amore n->norm->Bd.type = dt; 608260e9a87SYuri Pankov else 609260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_BD_REP, 610260e9a87SYuri Pankov mdoc->parse, n->line, n->pos, 611260e9a87SYuri Pankov "Bd -%s", mdoc_argnames[argv->arg]); 61295c635efSGarrett D'Amore } 61395c635efSGarrett D'Amore 61495c635efSGarrett D'Amore if (DISP__NONE == n->norm->Bd.type) { 615260e9a87SYuri Pankov mandoc_msg(MANDOCERR_BD_NOTYPE, mdoc->parse, 616260e9a87SYuri Pankov n->line, n->pos, "Bd"); 61795c635efSGarrett D'Amore n->norm->Bd.type = DISP_ragged; 61895c635efSGarrett D'Amore } 61995c635efSGarrett D'Amore } 62095c635efSGarrett D'Amore 621260e9a87SYuri Pankov static void 622*371584c2SYuri Pankov post_an_norm(POST_ARGS) 62395c635efSGarrett D'Amore { 624*371584c2SYuri Pankov struct roff_node *n; 625260e9a87SYuri Pankov struct mdoc_argv *argv; 626260e9a87SYuri Pankov size_t i; 62795c635efSGarrett D'Amore 628*371584c2SYuri Pankov n = mdoc->last; 629260e9a87SYuri Pankov if (n->args == NULL) 630260e9a87SYuri Pankov return; 63195c635efSGarrett D'Amore 632260e9a87SYuri Pankov for (i = 1; i < n->args->argc; i++) { 633260e9a87SYuri Pankov argv = n->args->argv + i; 634260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_AN_REP, 635260e9a87SYuri Pankov mdoc->parse, argv->line, argv->pos, 636260e9a87SYuri Pankov "An -%s", mdoc_argnames[argv->arg]); 637260e9a87SYuri Pankov } 638260e9a87SYuri Pankov 639260e9a87SYuri Pankov argv = n->args->argv; 640260e9a87SYuri Pankov if (argv->arg == MDOC_Split) 64195c635efSGarrett D'Amore n->norm->An.auth = AUTH_split; 642260e9a87SYuri Pankov else if (argv->arg == MDOC_Nosplit) 64395c635efSGarrett D'Amore n->norm->An.auth = AUTH_nosplit; 64495c635efSGarrett D'Amore else 64595c635efSGarrett D'Amore abort(); 64695c635efSGarrett D'Amore } 64795c635efSGarrett D'Amore 648260e9a87SYuri Pankov static void 649*371584c2SYuri Pankov post_std(POST_ARGS) 65095c635efSGarrett D'Amore { 651*371584c2SYuri Pankov struct roff_node *n; 65295c635efSGarrett D'Amore 653*371584c2SYuri Pankov n = mdoc->last; 654*371584c2SYuri Pankov if (n->args && n->args->argc == 1) 655*371584c2SYuri Pankov if (n->args->argv[0].arg == MDOC_Std) 656260e9a87SYuri Pankov return; 65795c635efSGarrett D'Amore 658260e9a87SYuri Pankov mandoc_msg(MANDOCERR_ARG_STD, mdoc->parse, 659260e9a87SYuri Pankov n->line, n->pos, mdoc_macronames[n->tok]); 66095c635efSGarrett D'Amore } 66195c635efSGarrett D'Amore 662260e9a87SYuri Pankov static void 663*371584c2SYuri Pankov post_obsolete(POST_ARGS) 66495c635efSGarrett D'Amore { 665*371584c2SYuri Pankov struct roff_node *n; 66695c635efSGarrett D'Amore 667*371584c2SYuri Pankov n = mdoc->last; 668*371584c2SYuri Pankov if (n->type == ROFFT_ELEM || n->type == ROFFT_BLOCK) 669260e9a87SYuri Pankov mandoc_msg(MANDOCERR_MACRO_OBS, mdoc->parse, 670260e9a87SYuri Pankov n->line, n->pos, mdoc_macronames[n->tok]); 671260e9a87SYuri Pankov } 67295c635efSGarrett D'Amore 673260e9a87SYuri Pankov static void 67495c635efSGarrett D'Amore post_bf(POST_ARGS) 67595c635efSGarrett D'Amore { 676*371584c2SYuri Pankov struct roff_node *np, *nch; 67795c635efSGarrett D'Amore 67895c635efSGarrett D'Amore /* 67995c635efSGarrett D'Amore * Unlike other data pointers, these are "housed" by the HEAD 68095c635efSGarrett D'Amore * element, which contains the goods. 68195c635efSGarrett D'Amore */ 68295c635efSGarrett D'Amore 68395c635efSGarrett D'Amore np = mdoc->last; 684*371584c2SYuri Pankov if (np->type != ROFFT_HEAD) 685260e9a87SYuri Pankov return; 686260e9a87SYuri Pankov 687*371584c2SYuri Pankov assert(np->parent->type == ROFFT_BLOCK); 688*371584c2SYuri Pankov assert(np->parent->tok == MDOC_Bf); 68995c635efSGarrett D'Amore 690260e9a87SYuri Pankov /* Check the number of arguments. */ 69195c635efSGarrett D'Amore 692260e9a87SYuri Pankov nch = np->child; 693*371584c2SYuri Pankov if (np->parent->args == NULL) { 694*371584c2SYuri Pankov if (nch == NULL) { 695260e9a87SYuri Pankov mandoc_msg(MANDOCERR_BF_NOFONT, mdoc->parse, 696260e9a87SYuri Pankov np->line, np->pos, "Bf"); 697260e9a87SYuri Pankov return; 698260e9a87SYuri Pankov } 699260e9a87SYuri Pankov nch = nch->next; 70095c635efSGarrett D'Amore } 701*371584c2SYuri Pankov if (nch != NULL) 702260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse, 703260e9a87SYuri Pankov nch->line, nch->pos, "Bf ... %s", nch->string); 70495c635efSGarrett D'Amore 70595c635efSGarrett D'Amore /* Extract argument into data. */ 706260e9a87SYuri Pankov 707*371584c2SYuri Pankov if (np->parent->args != NULL) { 708*371584c2SYuri Pankov switch (np->parent->args->argv[0].arg) { 709*371584c2SYuri Pankov case MDOC_Emphasis: 71095c635efSGarrett D'Amore np->norm->Bf.font = FONT_Em; 711*371584c2SYuri Pankov break; 712*371584c2SYuri Pankov case MDOC_Literal: 71395c635efSGarrett D'Amore np->norm->Bf.font = FONT_Li; 714*371584c2SYuri Pankov break; 715*371584c2SYuri Pankov case MDOC_Symbolic: 71695c635efSGarrett D'Amore np->norm->Bf.font = FONT_Sy; 717*371584c2SYuri Pankov break; 718*371584c2SYuri Pankov default: 71995c635efSGarrett D'Amore abort(); 720*371584c2SYuri Pankov } 721260e9a87SYuri Pankov return; 72295c635efSGarrett D'Amore } 72395c635efSGarrett D'Amore 72495c635efSGarrett D'Amore /* Extract parameter into data. */ 72595c635efSGarrett D'Amore 726*371584c2SYuri Pankov if ( ! strcmp(np->child->string, "Em")) 72795c635efSGarrett D'Amore np->norm->Bf.font = FONT_Em; 728*371584c2SYuri Pankov else if ( ! strcmp(np->child->string, "Li")) 72995c635efSGarrett D'Amore np->norm->Bf.font = FONT_Li; 730*371584c2SYuri Pankov else if ( ! strcmp(np->child->string, "Sy")) 73195c635efSGarrett D'Amore np->norm->Bf.font = FONT_Sy; 732260e9a87SYuri Pankov else 733260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_BF_BADFONT, mdoc->parse, 734260e9a87SYuri Pankov np->child->line, np->child->pos, 735260e9a87SYuri Pankov "Bf %s", np->child->string); 73695c635efSGarrett D'Amore } 73795c635efSGarrett D'Amore 738260e9a87SYuri Pankov static void 73995c635efSGarrett D'Amore post_lb(POST_ARGS) 74095c635efSGarrett D'Amore { 741*371584c2SYuri Pankov struct roff_node *n; 742260e9a87SYuri Pankov const char *stdlibname; 743260e9a87SYuri Pankov char *libname; 74495c635efSGarrett D'Amore 745260e9a87SYuri Pankov n = mdoc->last->child; 746*371584c2SYuri Pankov assert(n->type == ROFFT_TEXT); 74795c635efSGarrett D'Amore 748260e9a87SYuri Pankov if (NULL == (stdlibname = mdoc_a2lib(n->string))) 749260e9a87SYuri Pankov mandoc_asprintf(&libname, 750260e9a87SYuri Pankov "library \\(Lq%s\\(Rq", n->string); 751260e9a87SYuri Pankov else 752260e9a87SYuri Pankov libname = mandoc_strdup(stdlibname); 75395c635efSGarrett D'Amore 754260e9a87SYuri Pankov free(n->string); 755260e9a87SYuri Pankov n->string = libname; 756260e9a87SYuri Pankov } 75795c635efSGarrett D'Amore 758260e9a87SYuri Pankov static void 759260e9a87SYuri Pankov post_eoln(POST_ARGS) 760260e9a87SYuri Pankov { 761*371584c2SYuri Pankov const struct roff_node *n; 76295c635efSGarrett D'Amore 763260e9a87SYuri Pankov n = mdoc->last; 764*371584c2SYuri Pankov if (n->child != NULL) 765260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_ARG_SKIP, 766260e9a87SYuri Pankov mdoc->parse, n->line, n->pos, 767260e9a87SYuri Pankov "%s %s", mdoc_macronames[n->tok], 768260e9a87SYuri Pankov n->child->string); 769260e9a87SYuri Pankov } 77095c635efSGarrett D'Amore 771260e9a87SYuri Pankov static void 772260e9a87SYuri Pankov post_fname(POST_ARGS) 773260e9a87SYuri Pankov { 774*371584c2SYuri Pankov const struct roff_node *n; 775260e9a87SYuri Pankov const char *cp; 776260e9a87SYuri Pankov size_t pos; 77795c635efSGarrett D'Amore 778260e9a87SYuri Pankov n = mdoc->last->child; 779260e9a87SYuri Pankov pos = strcspn(n->string, "()"); 780260e9a87SYuri Pankov cp = n->string + pos; 781260e9a87SYuri Pankov if ( ! (cp[0] == '\0' || (cp[0] == '(' && cp[1] == '*'))) 782260e9a87SYuri Pankov mandoc_msg(MANDOCERR_FN_PAREN, mdoc->parse, 783260e9a87SYuri Pankov n->line, n->pos + pos, n->string); 78495c635efSGarrett D'Amore } 78595c635efSGarrett D'Amore 786260e9a87SYuri Pankov static void 787260e9a87SYuri Pankov post_fn(POST_ARGS) 78895c635efSGarrett D'Amore { 78995c635efSGarrett D'Amore 790260e9a87SYuri Pankov post_fname(mdoc); 791260e9a87SYuri Pankov post_fa(mdoc); 79295c635efSGarrett D'Amore } 79395c635efSGarrett D'Amore 794260e9a87SYuri Pankov static void 795260e9a87SYuri Pankov post_fo(POST_ARGS) 796260e9a87SYuri Pankov { 797*371584c2SYuri Pankov const struct roff_node *n; 79895c635efSGarrett D'Amore 799260e9a87SYuri Pankov n = mdoc->last; 800260e9a87SYuri Pankov 801*371584c2SYuri Pankov if (n->type != ROFFT_HEAD) 802260e9a87SYuri Pankov return; 803260e9a87SYuri Pankov 804260e9a87SYuri Pankov if (n->child == NULL) { 805260e9a87SYuri Pankov mandoc_msg(MANDOCERR_FO_NOHEAD, mdoc->parse, 806260e9a87SYuri Pankov n->line, n->pos, "Fo"); 807260e9a87SYuri Pankov return; 808260e9a87SYuri Pankov } 809260e9a87SYuri Pankov if (n->child != n->last) { 810260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse, 811260e9a87SYuri Pankov n->child->next->line, n->child->next->pos, 812260e9a87SYuri Pankov "Fo ... %s", n->child->next->string); 813260e9a87SYuri Pankov while (n->child != n->last) 814*371584c2SYuri Pankov roff_node_delete(mdoc, n->last); 815260e9a87SYuri Pankov } 816260e9a87SYuri Pankov 817260e9a87SYuri Pankov post_fname(mdoc); 818260e9a87SYuri Pankov } 819260e9a87SYuri Pankov 820260e9a87SYuri Pankov static void 821260e9a87SYuri Pankov post_fa(POST_ARGS) 822260e9a87SYuri Pankov { 823*371584c2SYuri Pankov const struct roff_node *n; 824260e9a87SYuri Pankov const char *cp; 825260e9a87SYuri Pankov 826260e9a87SYuri Pankov for (n = mdoc->last->child; n != NULL; n = n->next) { 827260e9a87SYuri Pankov for (cp = n->string; *cp != '\0'; cp++) { 828260e9a87SYuri Pankov /* Ignore callbacks and alterations. */ 829260e9a87SYuri Pankov if (*cp == '(' || *cp == '{') 830260e9a87SYuri Pankov break; 831260e9a87SYuri Pankov if (*cp != ',') 832260e9a87SYuri Pankov continue; 833260e9a87SYuri Pankov mandoc_msg(MANDOCERR_FA_COMMA, mdoc->parse, 834260e9a87SYuri Pankov n->line, n->pos + (cp - n->string), 835260e9a87SYuri Pankov n->string); 836260e9a87SYuri Pankov break; 837260e9a87SYuri Pankov } 838260e9a87SYuri Pankov } 839260e9a87SYuri Pankov } 840260e9a87SYuri Pankov 841260e9a87SYuri Pankov static void 84295c635efSGarrett D'Amore post_nm(POST_ARGS) 84395c635efSGarrett D'Amore { 844*371584c2SYuri Pankov struct roff_node *n; 845260e9a87SYuri Pankov 846260e9a87SYuri Pankov n = mdoc->last; 847260e9a87SYuri Pankov 848260e9a87SYuri Pankov if (n->last != NULL && 849260e9a87SYuri Pankov (n->last->tok == MDOC_Pp || 850260e9a87SYuri Pankov n->last->tok == MDOC_Lp)) 851260e9a87SYuri Pankov mdoc_node_relink(mdoc, n->last); 85295c635efSGarrett D'Amore 853*371584c2SYuri Pankov if (mdoc->meta.name != NULL) 854260e9a87SYuri Pankov return; 85595c635efSGarrett D'Amore 856*371584c2SYuri Pankov deroff(&mdoc->meta.name, n); 85795c635efSGarrett D'Amore 858*371584c2SYuri Pankov if (mdoc->meta.name == NULL) 859260e9a87SYuri Pankov mandoc_msg(MANDOCERR_NM_NONAME, mdoc->parse, 860260e9a87SYuri Pankov n->line, n->pos, "Nm"); 86195c635efSGarrett D'Amore } 86295c635efSGarrett D'Amore 863260e9a87SYuri Pankov static void 864260e9a87SYuri Pankov post_nd(POST_ARGS) 865260e9a87SYuri Pankov { 866*371584c2SYuri Pankov struct roff_node *n; 867260e9a87SYuri Pankov 868260e9a87SYuri Pankov n = mdoc->last; 869260e9a87SYuri Pankov 870*371584c2SYuri Pankov if (n->type != ROFFT_BODY) 871260e9a87SYuri Pankov return; 872260e9a87SYuri Pankov 873260e9a87SYuri Pankov if (n->child == NULL) 874260e9a87SYuri Pankov mandoc_msg(MANDOCERR_ND_EMPTY, mdoc->parse, 875260e9a87SYuri Pankov n->line, n->pos, "Nd"); 876260e9a87SYuri Pankov 877260e9a87SYuri Pankov post_hyph(mdoc); 878260e9a87SYuri Pankov } 879260e9a87SYuri Pankov 880260e9a87SYuri Pankov static void 881*371584c2SYuri Pankov post_display(POST_ARGS) 882260e9a87SYuri Pankov { 883*371584c2SYuri Pankov struct roff_node *n, *np; 884260e9a87SYuri Pankov 885260e9a87SYuri Pankov n = mdoc->last; 886*371584c2SYuri Pankov switch (n->type) { 887*371584c2SYuri Pankov case ROFFT_BODY: 888*371584c2SYuri Pankov if (n->end != ENDBODY_NOT) 889*371584c2SYuri Pankov break; 890*371584c2SYuri Pankov if (n->child == NULL) 891*371584c2SYuri Pankov mandoc_msg(MANDOCERR_BLK_EMPTY, mdoc->parse, 892*371584c2SYuri Pankov n->line, n->pos, mdoc_macronames[n->tok]); 893*371584c2SYuri Pankov else if (n->tok == MDOC_D1) 894*371584c2SYuri Pankov post_hyph(mdoc); 895*371584c2SYuri Pankov break; 896*371584c2SYuri Pankov case ROFFT_BLOCK: 897*371584c2SYuri Pankov if (n->tok == MDOC_Bd) { 898*371584c2SYuri Pankov if (n->args == NULL) { 899*371584c2SYuri Pankov mandoc_msg(MANDOCERR_BD_NOARG, 900*371584c2SYuri Pankov mdoc->parse, n->line, n->pos, "Bd"); 901*371584c2SYuri Pankov mdoc->next = ROFF_NEXT_SIBLING; 902*371584c2SYuri Pankov while (n->body->child != NULL) 903*371584c2SYuri Pankov mdoc_node_relink(mdoc, 904*371584c2SYuri Pankov n->body->child); 905*371584c2SYuri Pankov roff_node_delete(mdoc, n); 906*371584c2SYuri Pankov break; 907*371584c2SYuri Pankov } 908*371584c2SYuri Pankov post_bd(mdoc); 909*371584c2SYuri Pankov post_prevpar(mdoc); 910*371584c2SYuri Pankov } 911*371584c2SYuri Pankov for (np = n->parent; np != NULL; np = np->parent) { 912*371584c2SYuri Pankov if (np->type == ROFFT_BLOCK && np->tok == MDOC_Bd) { 913*371584c2SYuri Pankov mandoc_vmsg(MANDOCERR_BD_NEST, 914*371584c2SYuri Pankov mdoc->parse, n->line, n->pos, 915*371584c2SYuri Pankov "%s in Bd", mdoc_macronames[n->tok]); 916*371584c2SYuri Pankov break; 917*371584c2SYuri Pankov } 918*371584c2SYuri Pankov } 919*371584c2SYuri Pankov break; 920*371584c2SYuri Pankov default: 921*371584c2SYuri Pankov break; 922*371584c2SYuri Pankov } 92395c635efSGarrett D'Amore } 92495c635efSGarrett D'Amore 925260e9a87SYuri Pankov static void 92695c635efSGarrett D'Amore post_defaults(POST_ARGS) 92795c635efSGarrett D'Amore { 928*371584c2SYuri Pankov struct roff_node *nn; 92995c635efSGarrett D'Amore 93095c635efSGarrett D'Amore /* 93195c635efSGarrett D'Amore * The `Ar' defaults to "file ..." if no value is provided as an 93295c635efSGarrett D'Amore * argument; the `Mt' and `Pa' macros use "~"; the `Li' just 93395c635efSGarrett D'Amore * gets an empty string. 93495c635efSGarrett D'Amore */ 93595c635efSGarrett D'Amore 936*371584c2SYuri Pankov if (mdoc->last->child != NULL) 937260e9a87SYuri Pankov return; 938260e9a87SYuri Pankov 93995c635efSGarrett D'Amore nn = mdoc->last; 94095c635efSGarrett D'Amore 94195c635efSGarrett D'Amore switch (nn->tok) { 942260e9a87SYuri Pankov case MDOC_Ar: 943*371584c2SYuri Pankov mdoc->next = ROFF_NEXT_CHILD; 944*371584c2SYuri Pankov roff_word_alloc(mdoc, nn->line, nn->pos, "file"); 945*371584c2SYuri Pankov roff_word_alloc(mdoc, nn->line, nn->pos, "..."); 94695c635efSGarrett D'Amore break; 947260e9a87SYuri Pankov case MDOC_Pa: 948260e9a87SYuri Pankov case MDOC_Mt: 949*371584c2SYuri Pankov mdoc->next = ROFF_NEXT_CHILD; 950*371584c2SYuri Pankov roff_word_alloc(mdoc, nn->line, nn->pos, "~"); 95195c635efSGarrett D'Amore break; 95295c635efSGarrett D'Amore default: 95395c635efSGarrett D'Amore abort(); 954260e9a87SYuri Pankov } 95595c635efSGarrett D'Amore mdoc->last = nn; 95695c635efSGarrett D'Amore } 95795c635efSGarrett D'Amore 958260e9a87SYuri Pankov static void 95995c635efSGarrett D'Amore post_at(POST_ARGS) 96095c635efSGarrett D'Amore { 961*371584c2SYuri Pankov struct roff_node *n; 962260e9a87SYuri Pankov const char *std_att; 963260e9a87SYuri Pankov char *att; 964260e9a87SYuri Pankov 965260e9a87SYuri Pankov n = mdoc->last; 966260e9a87SYuri Pankov if (n->child == NULL) { 967*371584c2SYuri Pankov mdoc->next = ROFF_NEXT_CHILD; 968*371584c2SYuri Pankov roff_word_alloc(mdoc, n->line, n->pos, "AT&T UNIX"); 969260e9a87SYuri Pankov mdoc->last = n; 970260e9a87SYuri Pankov return; 971260e9a87SYuri Pankov } 97295c635efSGarrett D'Amore 97395c635efSGarrett D'Amore /* 97495c635efSGarrett D'Amore * If we have a child, look it up in the standard keys. If a 97595c635efSGarrett D'Amore * key exist, use that instead of the child; if it doesn't, 97695c635efSGarrett D'Amore * prefix "AT&T UNIX " to the existing data. 97795c635efSGarrett D'Amore */ 97895c635efSGarrett D'Amore 979260e9a87SYuri Pankov n = n->child; 980*371584c2SYuri Pankov assert(n->type == ROFFT_TEXT); 981*371584c2SYuri Pankov if ((std_att = mdoc_a2att(n->string)) == NULL) { 982260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_AT_BAD, mdoc->parse, 983260e9a87SYuri Pankov n->line, n->pos, "At %s", n->string); 984260e9a87SYuri Pankov mandoc_asprintf(&att, "AT&T UNIX %s", n->string); 985260e9a87SYuri Pankov } else 986260e9a87SYuri Pankov att = mandoc_strdup(std_att); 98795c635efSGarrett D'Amore 988260e9a87SYuri Pankov free(n->string); 989260e9a87SYuri Pankov n->string = att; 99095c635efSGarrett D'Amore } 99195c635efSGarrett D'Amore 992260e9a87SYuri Pankov static void 99395c635efSGarrett D'Amore post_an(POST_ARGS) 99495c635efSGarrett D'Amore { 995*371584c2SYuri Pankov struct roff_node *np, *nch; 996*371584c2SYuri Pankov 997*371584c2SYuri Pankov post_an_norm(mdoc); 99895c635efSGarrett D'Amore 99995c635efSGarrett D'Amore np = mdoc->last; 1000260e9a87SYuri Pankov nch = np->child; 1001260e9a87SYuri Pankov if (np->norm->An.auth == AUTH__NONE) { 1002260e9a87SYuri Pankov if (nch == NULL) 1003260e9a87SYuri Pankov mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse, 1004260e9a87SYuri Pankov np->line, np->pos, "An"); 1005260e9a87SYuri Pankov } else if (nch != NULL) 1006260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse, 1007260e9a87SYuri Pankov nch->line, nch->pos, "An ... %s", nch->string); 1008260e9a87SYuri Pankov } 1009260e9a87SYuri Pankov 1010260e9a87SYuri Pankov static void 1011260e9a87SYuri Pankov post_en(POST_ARGS) 1012260e9a87SYuri Pankov { 101395c635efSGarrett D'Amore 1014*371584c2SYuri Pankov post_obsolete(mdoc); 1015*371584c2SYuri Pankov if (mdoc->last->type == ROFFT_BLOCK) 1016260e9a87SYuri Pankov mdoc->last->norm->Es = mdoc->last_es; 101795c635efSGarrett D'Amore } 101895c635efSGarrett D'Amore 1019260e9a87SYuri Pankov static void 1020260e9a87SYuri Pankov post_es(POST_ARGS) 1021260e9a87SYuri Pankov { 102295c635efSGarrett D'Amore 1023*371584c2SYuri Pankov post_obsolete(mdoc); 1024260e9a87SYuri Pankov mdoc->last_es = mdoc->last; 1025260e9a87SYuri Pankov } 1026260e9a87SYuri Pankov 1027260e9a87SYuri Pankov static void 102895c635efSGarrett D'Amore post_it(POST_ARGS) 102995c635efSGarrett D'Amore { 1030*371584c2SYuri Pankov struct roff_node *nbl, *nit, *nch; 103195c635efSGarrett D'Amore int i, cols; 103295c635efSGarrett D'Amore enum mdoc_list lt; 1033*371584c2SYuri Pankov 1034*371584c2SYuri Pankov post_prevpar(mdoc); 103595c635efSGarrett D'Amore 1036260e9a87SYuri Pankov nit = mdoc->last; 1037*371584c2SYuri Pankov if (nit->type != ROFFT_BLOCK) 1038260e9a87SYuri Pankov return; 103995c635efSGarrett D'Amore 1040260e9a87SYuri Pankov nbl = nit->parent->parent; 1041260e9a87SYuri Pankov lt = nbl->norm->Bl.type; 104295c635efSGarrett D'Amore 104395c635efSGarrett D'Amore switch (lt) { 1044260e9a87SYuri Pankov case LIST_tag: 1045260e9a87SYuri Pankov case LIST_hang: 1046260e9a87SYuri Pankov case LIST_ohang: 1047260e9a87SYuri Pankov case LIST_inset: 1048260e9a87SYuri Pankov case LIST_diag: 1049260e9a87SYuri Pankov if (nit->head->child == NULL) 1050260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_IT_NOHEAD, 1051260e9a87SYuri Pankov mdoc->parse, nit->line, nit->pos, 1052260e9a87SYuri Pankov "Bl -%s It", 1053260e9a87SYuri Pankov mdoc_argnames[nbl->args->argv[0].arg]); 105495c635efSGarrett D'Amore break; 1055260e9a87SYuri Pankov case LIST_bullet: 1056260e9a87SYuri Pankov case LIST_dash: 1057260e9a87SYuri Pankov case LIST_enum: 1058260e9a87SYuri Pankov case LIST_hyphen: 1059260e9a87SYuri Pankov if (nit->body == NULL || nit->body->child == NULL) 1060260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_IT_NOBODY, 1061260e9a87SYuri Pankov mdoc->parse, nit->line, nit->pos, 1062260e9a87SYuri Pankov "Bl -%s It", 1063260e9a87SYuri Pankov mdoc_argnames[nbl->args->argv[0].arg]); 106495c635efSGarrett D'Amore /* FALLTHROUGH */ 1065260e9a87SYuri Pankov case LIST_item: 1066260e9a87SYuri Pankov if (nit->head->child != NULL) 1067260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_ARG_SKIP, 1068260e9a87SYuri Pankov mdoc->parse, nit->line, nit->pos, 1069260e9a87SYuri Pankov "It %s", nit->head->child->string); 107095c635efSGarrett D'Amore break; 1071260e9a87SYuri Pankov case LIST_column: 1072260e9a87SYuri Pankov cols = (int)nbl->norm->Bl.ncols; 107395c635efSGarrett D'Amore 1074260e9a87SYuri Pankov assert(nit->head->child == NULL); 107595c635efSGarrett D'Amore 1076*371584c2SYuri Pankov i = 0; 1077*371584c2SYuri Pankov for (nch = nit->child; nch != NULL; nch = nch->next) 1078*371584c2SYuri Pankov if (nch->type == ROFFT_BODY) 107995c635efSGarrett D'Amore i++; 108095c635efSGarrett D'Amore 1081260e9a87SYuri Pankov if (i < cols || i > cols + 1) 1082260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_BL_COL, 1083260e9a87SYuri Pankov mdoc->parse, nit->line, nit->pos, 1084260e9a87SYuri Pankov "%d columns, %d cells", cols, i); 108595c635efSGarrett D'Amore break; 1086260e9a87SYuri Pankov default: 1087260e9a87SYuri Pankov abort(); 108895c635efSGarrett D'Amore } 108995c635efSGarrett D'Amore } 109095c635efSGarrett D'Amore 1091260e9a87SYuri Pankov static void 1092260e9a87SYuri Pankov post_bl_block(POST_ARGS) 109395c635efSGarrett D'Amore { 1094*371584c2SYuri Pankov struct roff_node *n, *ni, *nc; 1095*371584c2SYuri Pankov 1096*371584c2SYuri Pankov post_prevpar(mdoc); 109795c635efSGarrett D'Amore 109895c635efSGarrett D'Amore /* 109995c635efSGarrett D'Amore * These are fairly complicated, so we've broken them into two 110095c635efSGarrett D'Amore * functions. post_bl_block_tag() is called when a -tag is 110195c635efSGarrett D'Amore * specified, but no -width (it must be guessed). The second 110295c635efSGarrett D'Amore * when a -width is specified (macro indicators must be 110395c635efSGarrett D'Amore * rewritten into real lengths). 110495c635efSGarrett D'Amore */ 110595c635efSGarrett D'Amore 110695c635efSGarrett D'Amore n = mdoc->last; 110795c635efSGarrett D'Amore 1108*371584c2SYuri Pankov if (n->norm->Bl.type == LIST_tag && 1109*371584c2SYuri Pankov n->norm->Bl.width == NULL) { 1110260e9a87SYuri Pankov post_bl_block_tag(mdoc); 1111*371584c2SYuri Pankov assert(n->norm->Bl.width != NULL); 1112698f87a4SGarrett D'Amore } 111395c635efSGarrett D'Amore 1114*371584c2SYuri Pankov for (ni = n->body->child; ni != NULL; ni = ni->next) { 1115*371584c2SYuri Pankov if (ni->body == NULL) 1116698f87a4SGarrett D'Amore continue; 1117698f87a4SGarrett D'Amore nc = ni->body->last; 1118*371584c2SYuri Pankov while (nc != NULL) { 1119698f87a4SGarrett D'Amore switch (nc->tok) { 1120260e9a87SYuri Pankov case MDOC_Pp: 1121260e9a87SYuri Pankov case MDOC_Lp: 1122260e9a87SYuri Pankov case MDOC_br: 1123698f87a4SGarrett D'Amore break; 1124698f87a4SGarrett D'Amore default: 1125698f87a4SGarrett D'Amore nc = NULL; 1126698f87a4SGarrett D'Amore continue; 1127698f87a4SGarrett D'Amore } 1128*371584c2SYuri Pankov if (ni->next == NULL) { 1129260e9a87SYuri Pankov mandoc_msg(MANDOCERR_PAR_MOVE, 1130260e9a87SYuri Pankov mdoc->parse, nc->line, nc->pos, 1131260e9a87SYuri Pankov mdoc_macronames[nc->tok]); 1132260e9a87SYuri Pankov mdoc_node_relink(mdoc, nc); 1133*371584c2SYuri Pankov } else if (n->norm->Bl.comp == 0 && 1134*371584c2SYuri Pankov n->norm->Bl.type != LIST_column) { 1135260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_PAR_SKIP, 1136260e9a87SYuri Pankov mdoc->parse, nc->line, nc->pos, 1137260e9a87SYuri Pankov "%s before It", 1138260e9a87SYuri Pankov mdoc_macronames[nc->tok]); 1139*371584c2SYuri Pankov roff_node_delete(mdoc, nc); 1140698f87a4SGarrett D'Amore } else 1141698f87a4SGarrett D'Amore break; 1142698f87a4SGarrett D'Amore nc = ni->body->last; 1143698f87a4SGarrett D'Amore } 1144698f87a4SGarrett D'Amore } 114595c635efSGarrett D'Amore } 114695c635efSGarrett D'Amore 1147260e9a87SYuri Pankov /* 1148260e9a87SYuri Pankov * If the argument of -offset or -width is a macro, 1149260e9a87SYuri Pankov * replace it with the associated default width. 1150260e9a87SYuri Pankov */ 1151260e9a87SYuri Pankov void 1152260e9a87SYuri Pankov rewrite_macro2len(char **arg) 115395c635efSGarrett D'Amore { 115495c635efSGarrett D'Amore size_t width; 1155*371584c2SYuri Pankov int tok; 115695c635efSGarrett D'Amore 1157260e9a87SYuri Pankov if (*arg == NULL) 1158260e9a87SYuri Pankov return; 1159260e9a87SYuri Pankov else if ( ! strcmp(*arg, "Ds")) 116095c635efSGarrett D'Amore width = 6; 1161*371584c2SYuri Pankov else if ((tok = mdoc_hash_find(*arg)) == TOKEN_NONE) 1162260e9a87SYuri Pankov return; 1163260e9a87SYuri Pankov else 1164260e9a87SYuri Pankov width = macro2len(tok); 116595c635efSGarrett D'Amore 1166260e9a87SYuri Pankov free(*arg); 1167260e9a87SYuri Pankov mandoc_asprintf(arg, "%zun", width); 116895c635efSGarrett D'Amore } 116995c635efSGarrett D'Amore 1170260e9a87SYuri Pankov static void 117195c635efSGarrett D'Amore post_bl_block_tag(POST_ARGS) 117295c635efSGarrett D'Amore { 1173*371584c2SYuri Pankov struct roff_node *n, *nn; 117495c635efSGarrett D'Amore size_t sz, ssz; 117595c635efSGarrett D'Amore int i; 1176260e9a87SYuri Pankov char buf[24]; 117795c635efSGarrett D'Amore 117895c635efSGarrett D'Amore /* 117995c635efSGarrett D'Amore * Calculate the -width for a `Bl -tag' list if it hasn't been 118095c635efSGarrett D'Amore * provided. Uses the first head macro. NOTE AGAIN: this is 118195c635efSGarrett D'Amore * ONLY if the -width argument has NOT been provided. See 1182260e9a87SYuri Pankov * rewrite_macro2len() for converting the -width string. 118395c635efSGarrett D'Amore */ 118495c635efSGarrett D'Amore 118595c635efSGarrett D'Amore sz = 10; 118695c635efSGarrett D'Amore n = mdoc->last; 118795c635efSGarrett D'Amore 1188*371584c2SYuri Pankov for (nn = n->body->child; nn != NULL; nn = nn->next) { 1189*371584c2SYuri Pankov if (nn->tok != MDOC_It) 119095c635efSGarrett D'Amore continue; 119195c635efSGarrett D'Amore 1192*371584c2SYuri Pankov assert(nn->type == ROFFT_BLOCK); 119395c635efSGarrett D'Amore nn = nn->head->child; 119495c635efSGarrett D'Amore 119595c635efSGarrett D'Amore if (nn == NULL) 119695c635efSGarrett D'Amore break; 119795c635efSGarrett D'Amore 1198*371584c2SYuri Pankov if (nn->type == ROFFT_TEXT) { 119995c635efSGarrett D'Amore sz = strlen(nn->string) + 1; 120095c635efSGarrett D'Amore break; 120195c635efSGarrett D'Amore } 120295c635efSGarrett D'Amore 120395c635efSGarrett D'Amore if (0 != (ssz = macro2len(nn->tok))) 120495c635efSGarrett D'Amore sz = ssz; 120595c635efSGarrett D'Amore 120695c635efSGarrett D'Amore break; 1207260e9a87SYuri Pankov } 120895c635efSGarrett D'Amore 120995c635efSGarrett D'Amore /* Defaults to ten ens. */ 121095c635efSGarrett D'Amore 1211260e9a87SYuri Pankov (void)snprintf(buf, sizeof(buf), "%un", (unsigned int)sz); 121295c635efSGarrett D'Amore 121395c635efSGarrett D'Amore /* 121495c635efSGarrett D'Amore * We have to dynamically add this to the macro's argument list. 121595c635efSGarrett D'Amore * We're guaranteed that a MDOC_Width doesn't already exist. 121695c635efSGarrett D'Amore */ 121795c635efSGarrett D'Amore 1218*371584c2SYuri Pankov assert(n->args != NULL); 121995c635efSGarrett D'Amore i = (int)(n->args->argc)++; 122095c635efSGarrett D'Amore 1221260e9a87SYuri Pankov n->args->argv = mandoc_reallocarray(n->args->argv, 1222260e9a87SYuri Pankov n->args->argc, sizeof(struct mdoc_argv)); 122395c635efSGarrett D'Amore 122495c635efSGarrett D'Amore n->args->argv[i].arg = MDOC_Width; 122595c635efSGarrett D'Amore n->args->argv[i].line = n->line; 122695c635efSGarrett D'Amore n->args->argv[i].pos = n->pos; 122795c635efSGarrett D'Amore n->args->argv[i].sz = 1; 122895c635efSGarrett D'Amore n->args->argv[i].value = mandoc_malloc(sizeof(char *)); 122995c635efSGarrett D'Amore n->args->argv[i].value[0] = mandoc_strdup(buf); 123095c635efSGarrett D'Amore 123195c635efSGarrett D'Amore /* Set our width! */ 123295c635efSGarrett D'Amore n->norm->Bl.width = n->args->argv[i].value[0]; 123395c635efSGarrett D'Amore } 123495c635efSGarrett D'Amore 1235260e9a87SYuri Pankov static void 1236260e9a87SYuri Pankov post_bl_head(POST_ARGS) 123795c635efSGarrett D'Amore { 1238*371584c2SYuri Pankov struct roff_node *nbl, *nh, *nch, *nnext; 1239260e9a87SYuri Pankov struct mdoc_argv *argv; 124095c635efSGarrett D'Amore int i, j; 124195c635efSGarrett D'Amore 1242*371584c2SYuri Pankov post_bl_norm(mdoc); 1243260e9a87SYuri Pankov 1244*371584c2SYuri Pankov nh = mdoc->last; 1245260e9a87SYuri Pankov if (nh->norm->Bl.type != LIST_column) { 1246260e9a87SYuri Pankov if ((nch = nh->child) == NULL) 1247260e9a87SYuri Pankov return; 1248260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse, 1249260e9a87SYuri Pankov nch->line, nch->pos, "Bl ... %s", nch->string); 1250260e9a87SYuri Pankov while (nch != NULL) { 1251*371584c2SYuri Pankov roff_node_delete(mdoc, nch); 1252260e9a87SYuri Pankov nch = nh->child; 1253260e9a87SYuri Pankov } 1254260e9a87SYuri Pankov return; 1255260e9a87SYuri Pankov } 125695c635efSGarrett D'Amore 125795c635efSGarrett D'Amore /* 1258260e9a87SYuri Pankov * Append old-style lists, where the column width specifiers 125995c635efSGarrett D'Amore * trail as macro parameters, to the new-style ("normal-form") 126095c635efSGarrett D'Amore * lists where they're argument values following -column. 126195c635efSGarrett D'Amore */ 126295c635efSGarrett D'Amore 1263260e9a87SYuri Pankov if (nh->child == NULL) 1264260e9a87SYuri Pankov return; 126595c635efSGarrett D'Amore 1266260e9a87SYuri Pankov nbl = nh->parent; 1267260e9a87SYuri Pankov for (j = 0; j < (int)nbl->args->argc; j++) 1268260e9a87SYuri Pankov if (nbl->args->argv[j].arg == MDOC_Column) 126995c635efSGarrett D'Amore break; 127095c635efSGarrett D'Amore 1271260e9a87SYuri Pankov assert(j < (int)nbl->args->argc); 127295c635efSGarrett D'Amore 127395c635efSGarrett D'Amore /* 127495c635efSGarrett D'Amore * Accommodate for new-style groff column syntax. Shuffle the 127595c635efSGarrett D'Amore * child nodes, all of which must be TEXT, as arguments for the 127695c635efSGarrett D'Amore * column field. Then, delete the head children. 127795c635efSGarrett D'Amore */ 127895c635efSGarrett D'Amore 1279260e9a87SYuri Pankov argv = nbl->args->argv + j; 1280260e9a87SYuri Pankov i = argv->sz; 1281*371584c2SYuri Pankov for (nch = nh->child; nch != NULL; nch = nch->next) 1282*371584c2SYuri Pankov argv->sz++; 1283260e9a87SYuri Pankov argv->value = mandoc_reallocarray(argv->value, 1284260e9a87SYuri Pankov argv->sz, sizeof(char *)); 128595c635efSGarrett D'Amore 1286260e9a87SYuri Pankov nh->norm->Bl.ncols = argv->sz; 1287260e9a87SYuri Pankov nh->norm->Bl.cols = (void *)argv->value; 128895c635efSGarrett D'Amore 1289260e9a87SYuri Pankov for (nch = nh->child; nch != NULL; nch = nnext) { 1290260e9a87SYuri Pankov argv->value[i++] = nch->string; 1291260e9a87SYuri Pankov nch->string = NULL; 1292260e9a87SYuri Pankov nnext = nch->next; 1293*371584c2SYuri Pankov roff_node_delete(NULL, nch); 129495c635efSGarrett D'Amore } 1295260e9a87SYuri Pankov nh->child = NULL; 129695c635efSGarrett D'Amore } 129795c635efSGarrett D'Amore 1298260e9a87SYuri Pankov static void 129995c635efSGarrett D'Amore post_bl(POST_ARGS) 130095c635efSGarrett D'Amore { 1301*371584c2SYuri Pankov struct roff_node *nparent, *nprev; /* of the Bl block */ 1302*371584c2SYuri Pankov struct roff_node *nblock, *nbody; /* of the Bl */ 1303*371584c2SYuri Pankov struct roff_node *nchild, *nnext; /* of the Bl body */ 130495c635efSGarrett D'Amore 1305698f87a4SGarrett D'Amore nbody = mdoc->last; 1306698f87a4SGarrett D'Amore switch (nbody->type) { 1307*371584c2SYuri Pankov case ROFFT_BLOCK: 1308260e9a87SYuri Pankov post_bl_block(mdoc); 1309260e9a87SYuri Pankov return; 1310*371584c2SYuri Pankov case ROFFT_HEAD: 1311260e9a87SYuri Pankov post_bl_head(mdoc); 1312260e9a87SYuri Pankov return; 1313*371584c2SYuri Pankov case ROFFT_BODY: 1314698f87a4SGarrett D'Amore break; 1315698f87a4SGarrett D'Amore default: 1316260e9a87SYuri Pankov return; 1317698f87a4SGarrett D'Amore } 1318*371584c2SYuri Pankov if (nbody->end != ENDBODY_NOT) 1319*371584c2SYuri Pankov return; 132095c635efSGarrett D'Amore 1321698f87a4SGarrett D'Amore nchild = nbody->child; 1322260e9a87SYuri Pankov if (nchild == NULL) { 1323260e9a87SYuri Pankov mandoc_msg(MANDOCERR_BLK_EMPTY, mdoc->parse, 1324260e9a87SYuri Pankov nbody->line, nbody->pos, "Bl"); 1325260e9a87SYuri Pankov return; 1326260e9a87SYuri Pankov } 1327260e9a87SYuri Pankov while (nchild != NULL) { 1328260e9a87SYuri Pankov if (nchild->tok == MDOC_It || 1329260e9a87SYuri Pankov (nchild->tok == MDOC_Sm && 1330260e9a87SYuri Pankov nchild->next != NULL && 1331260e9a87SYuri Pankov nchild->next->tok == MDOC_It)) { 1332698f87a4SGarrett D'Amore nchild = nchild->next; 133395c635efSGarrett D'Amore continue; 133495c635efSGarrett D'Amore } 133595c635efSGarrett D'Amore 1336260e9a87SYuri Pankov mandoc_msg(MANDOCERR_BL_MOVE, mdoc->parse, 1337260e9a87SYuri Pankov nchild->line, nchild->pos, 1338260e9a87SYuri Pankov mdoc_macronames[nchild->tok]); 1339698f87a4SGarrett D'Amore 1340698f87a4SGarrett D'Amore /* 1341698f87a4SGarrett D'Amore * Move the node out of the Bl block. 1342698f87a4SGarrett D'Amore * First, collect all required node pointers. 1343698f87a4SGarrett D'Amore */ 1344698f87a4SGarrett D'Amore 1345698f87a4SGarrett D'Amore nblock = nbody->parent; 1346698f87a4SGarrett D'Amore nprev = nblock->prev; 1347698f87a4SGarrett D'Amore nparent = nblock->parent; 1348698f87a4SGarrett D'Amore nnext = nchild->next; 1349698f87a4SGarrett D'Amore 1350698f87a4SGarrett D'Amore /* 1351698f87a4SGarrett D'Amore * Unlink this child. 1352698f87a4SGarrett D'Amore */ 1353698f87a4SGarrett D'Amore 1354*371584c2SYuri Pankov assert(nchild->prev == NULL); 1355*371584c2SYuri Pankov nbody->child = nnext; 1356*371584c2SYuri Pankov if (nnext == NULL) 1357698f87a4SGarrett D'Amore nbody->last = NULL; 1358*371584c2SYuri Pankov else 1359698f87a4SGarrett D'Amore nnext->prev = NULL; 1360698f87a4SGarrett D'Amore 1361698f87a4SGarrett D'Amore /* 1362698f87a4SGarrett D'Amore * Relink this child. 1363698f87a4SGarrett D'Amore */ 1364698f87a4SGarrett D'Amore 1365698f87a4SGarrett D'Amore nchild->parent = nparent; 1366698f87a4SGarrett D'Amore nchild->prev = nprev; 1367698f87a4SGarrett D'Amore nchild->next = nblock; 1368698f87a4SGarrett D'Amore 1369698f87a4SGarrett D'Amore nblock->prev = nchild; 1370*371584c2SYuri Pankov if (nprev == NULL) 1371698f87a4SGarrett D'Amore nparent->child = nchild; 1372698f87a4SGarrett D'Amore else 1373698f87a4SGarrett D'Amore nprev->next = nchild; 1374698f87a4SGarrett D'Amore 1375698f87a4SGarrett D'Amore nchild = nnext; 137695c635efSGarrett D'Amore } 1377260e9a87SYuri Pankov } 1378260e9a87SYuri Pankov 1379260e9a87SYuri Pankov static void 1380260e9a87SYuri Pankov post_bk(POST_ARGS) 1381260e9a87SYuri Pankov { 1382*371584c2SYuri Pankov struct roff_node *n; 1383260e9a87SYuri Pankov 1384260e9a87SYuri Pankov n = mdoc->last; 138595c635efSGarrett D'Amore 1386*371584c2SYuri Pankov if (n->type == ROFFT_BLOCK && n->body->child == NULL) { 1387260e9a87SYuri Pankov mandoc_msg(MANDOCERR_BLK_EMPTY, 1388260e9a87SYuri Pankov mdoc->parse, n->line, n->pos, "Bk"); 1389*371584c2SYuri Pankov roff_node_delete(mdoc, n); 1390260e9a87SYuri Pankov } 139195c635efSGarrett D'Amore } 139295c635efSGarrett D'Amore 1393260e9a87SYuri Pankov static void 1394*371584c2SYuri Pankov post_sm(POST_ARGS) 139595c635efSGarrett D'Amore { 1396*371584c2SYuri Pankov struct roff_node *nch; 139795c635efSGarrett D'Amore 1398260e9a87SYuri Pankov nch = mdoc->last->child; 1399260e9a87SYuri Pankov 1400260e9a87SYuri Pankov if (nch == NULL) { 1401260e9a87SYuri Pankov mdoc->flags ^= MDOC_SMOFF; 1402260e9a87SYuri Pankov return; 140395c635efSGarrett D'Amore } 140495c635efSGarrett D'Amore 1405*371584c2SYuri Pankov assert(nch->type == ROFFT_TEXT); 140695c635efSGarrett D'Amore 1407260e9a87SYuri Pankov if ( ! strcmp(nch->string, "on")) { 1408260e9a87SYuri Pankov mdoc->flags &= ~MDOC_SMOFF; 1409260e9a87SYuri Pankov return; 1410698f87a4SGarrett D'Amore } 1411260e9a87SYuri Pankov if ( ! strcmp(nch->string, "off")) { 1412260e9a87SYuri Pankov mdoc->flags |= MDOC_SMOFF; 1413260e9a87SYuri Pankov return; 1414698f87a4SGarrett D'Amore } 141595c635efSGarrett D'Amore 1416260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_SM_BAD, 1417260e9a87SYuri Pankov mdoc->parse, nch->line, nch->pos, 1418260e9a87SYuri Pankov "%s %s", mdoc_macronames[mdoc->last->tok], nch->string); 1419260e9a87SYuri Pankov mdoc_node_relink(mdoc, nch); 1420260e9a87SYuri Pankov return; 142195c635efSGarrett D'Amore } 142295c635efSGarrett D'Amore 1423260e9a87SYuri Pankov static void 142495c635efSGarrett D'Amore post_root(POST_ARGS) 142595c635efSGarrett D'Amore { 1426*371584c2SYuri Pankov struct roff_node *n; 142795c635efSGarrett D'Amore 1428260e9a87SYuri Pankov /* Add missing prologue data. */ 142995c635efSGarrett D'Amore 1430260e9a87SYuri Pankov if (mdoc->meta.date == NULL) 1431260e9a87SYuri Pankov mdoc->meta.date = mdoc->quick ? 1432260e9a87SYuri Pankov mandoc_strdup("") : 1433260e9a87SYuri Pankov mandoc_normdate(mdoc->parse, NULL, 0, 0); 143495c635efSGarrett D'Amore 1435260e9a87SYuri Pankov if (mdoc->meta.title == NULL) { 1436260e9a87SYuri Pankov mandoc_msg(MANDOCERR_DT_NOTITLE, 1437260e9a87SYuri Pankov mdoc->parse, 0, 0, "EOF"); 1438260e9a87SYuri Pankov mdoc->meta.title = mandoc_strdup("UNTITLED"); 143995c635efSGarrett D'Amore } 144095c635efSGarrett D'Amore 1441260e9a87SYuri Pankov if (mdoc->meta.vol == NULL) 1442260e9a87SYuri Pankov mdoc->meta.vol = mandoc_strdup("LOCAL"); 144395c635efSGarrett D'Amore 1444260e9a87SYuri Pankov if (mdoc->meta.os == NULL) { 1445260e9a87SYuri Pankov mandoc_msg(MANDOCERR_OS_MISSING, 1446260e9a87SYuri Pankov mdoc->parse, 0, 0, NULL); 1447260e9a87SYuri Pankov mdoc->meta.os = mandoc_strdup(""); 144895c635efSGarrett D'Amore } 144995c635efSGarrett D'Amore 1450260e9a87SYuri Pankov /* Check that we begin with a proper `Sh'. */ 1451260e9a87SYuri Pankov 1452260e9a87SYuri Pankov n = mdoc->first->child; 1453*371584c2SYuri Pankov while (n != NULL && n->tok != TOKEN_NONE && 1454*371584c2SYuri Pankov mdoc_macros[n->tok].flags & MDOC_PROLOGUE) 1455260e9a87SYuri Pankov n = n->next; 1456260e9a87SYuri Pankov 1457260e9a87SYuri Pankov if (n == NULL) 1458260e9a87SYuri Pankov mandoc_msg(MANDOCERR_DOC_EMPTY, mdoc->parse, 0, 0, NULL); 1459260e9a87SYuri Pankov else if (n->tok != MDOC_Sh) 1460260e9a87SYuri Pankov mandoc_msg(MANDOCERR_SEC_BEFORE, mdoc->parse, 1461260e9a87SYuri Pankov n->line, n->pos, mdoc_macronames[n->tok]); 146295c635efSGarrett D'Amore } 146395c635efSGarrett D'Amore 1464260e9a87SYuri Pankov static void 146595c635efSGarrett D'Amore post_st(POST_ARGS) 146695c635efSGarrett D'Amore { 1467*371584c2SYuri Pankov struct roff_node *n, *nch; 146895c635efSGarrett D'Amore const char *p; 146995c635efSGarrett D'Amore 1470260e9a87SYuri Pankov n = mdoc->last; 1471260e9a87SYuri Pankov nch = n->child; 147295c635efSGarrett D'Amore 1473*371584c2SYuri Pankov assert(nch->type == ROFFT_TEXT); 147495c635efSGarrett D'Amore 1475*371584c2SYuri Pankov if ((p = mdoc_a2st(nch->string)) == NULL) { 1476260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_ST_BAD, mdoc->parse, 1477260e9a87SYuri Pankov nch->line, nch->pos, "St %s", nch->string); 1478*371584c2SYuri Pankov roff_node_delete(mdoc, n); 147995c635efSGarrett D'Amore } else { 1480260e9a87SYuri Pankov free(nch->string); 1481260e9a87SYuri Pankov nch->string = mandoc_strdup(p); 148295c635efSGarrett D'Amore } 148395c635efSGarrett D'Amore } 148495c635efSGarrett D'Amore 1485260e9a87SYuri Pankov static void 148695c635efSGarrett D'Amore post_rs(POST_ARGS) 148795c635efSGarrett D'Amore { 1488*371584c2SYuri Pankov struct roff_node *np, *nch, *next, *prev; 148995c635efSGarrett D'Amore int i, j; 149095c635efSGarrett D'Amore 1491260e9a87SYuri Pankov np = mdoc->last; 149295c635efSGarrett D'Amore 1493*371584c2SYuri Pankov if (np->type != ROFFT_BODY) 1494260e9a87SYuri Pankov return; 149595c635efSGarrett D'Amore 1496260e9a87SYuri Pankov if (np->child == NULL) { 1497260e9a87SYuri Pankov mandoc_msg(MANDOCERR_RS_EMPTY, mdoc->parse, 1498260e9a87SYuri Pankov np->line, np->pos, "Rs"); 1499260e9a87SYuri Pankov return; 150095c635efSGarrett D'Amore } 150195c635efSGarrett D'Amore 150295c635efSGarrett D'Amore /* 150395c635efSGarrett D'Amore * The full `Rs' block needs special handling to order the 150495c635efSGarrett D'Amore * sub-elements according to `rsord'. Pick through each element 1505260e9a87SYuri Pankov * and correctly order it. This is an insertion sort. 150695c635efSGarrett D'Amore */ 150795c635efSGarrett D'Amore 150895c635efSGarrett D'Amore next = NULL; 1509260e9a87SYuri Pankov for (nch = np->child->next; nch != NULL; nch = next) { 1510260e9a87SYuri Pankov /* Determine order number of this child. */ 151195c635efSGarrett D'Amore for (i = 0; i < RSORD_MAX; i++) 1512260e9a87SYuri Pankov if (rsord[i] == nch->tok) 151395c635efSGarrett D'Amore break; 151495c635efSGarrett D'Amore 1515260e9a87SYuri Pankov if (i == RSORD_MAX) { 1516260e9a87SYuri Pankov mandoc_msg(MANDOCERR_RS_BAD, 1517260e9a87SYuri Pankov mdoc->parse, nch->line, nch->pos, 1518260e9a87SYuri Pankov mdoc_macronames[nch->tok]); 1519260e9a87SYuri Pankov i = -1; 1520260e9a87SYuri Pankov } else if (nch->tok == MDOC__J || nch->tok == MDOC__B) 1521260e9a87SYuri Pankov np->norm->Rs.quote_T++; 1522260e9a87SYuri Pankov 1523260e9a87SYuri Pankov /* 1524260e9a87SYuri Pankov * Remove this child from the chain. This somewhat 1525*371584c2SYuri Pankov * repeats roff_node_unlink(), but since we're 152695c635efSGarrett D'Amore * just re-ordering, there's no need for the 152795c635efSGarrett D'Amore * full unlink process. 152895c635efSGarrett D'Amore */ 152995c635efSGarrett D'Amore 1530260e9a87SYuri Pankov if ((next = nch->next) != NULL) 1531260e9a87SYuri Pankov next->prev = nch->prev; 153295c635efSGarrett D'Amore 1533260e9a87SYuri Pankov if ((prev = nch->prev) != NULL) 1534260e9a87SYuri Pankov prev->next = nch->next; 153595c635efSGarrett D'Amore 1536260e9a87SYuri Pankov nch->prev = nch->next = NULL; 1537260e9a87SYuri Pankov 1538260e9a87SYuri Pankov /* 153995c635efSGarrett D'Amore * Scan back until we reach a node that's 1540260e9a87SYuri Pankov * to be ordered before this child. 154195c635efSGarrett D'Amore */ 154295c635efSGarrett D'Amore 154395c635efSGarrett D'Amore for ( ; prev ; prev = prev->prev) { 154495c635efSGarrett D'Amore /* Determine order of `prev'. */ 154595c635efSGarrett D'Amore for (j = 0; j < RSORD_MAX; j++) 154695c635efSGarrett D'Amore if (rsord[j] == prev->tok) 154795c635efSGarrett D'Amore break; 1548260e9a87SYuri Pankov if (j == RSORD_MAX) 1549260e9a87SYuri Pankov j = -1; 155095c635efSGarrett D'Amore 155195c635efSGarrett D'Amore if (j <= i) 155295c635efSGarrett D'Amore break; 155395c635efSGarrett D'Amore } 155495c635efSGarrett D'Amore 155595c635efSGarrett D'Amore /* 1556260e9a87SYuri Pankov * Set this child back into its correct place 1557260e9a87SYuri Pankov * in front of the `prev' node. 155895c635efSGarrett D'Amore */ 155995c635efSGarrett D'Amore 1560260e9a87SYuri Pankov nch->prev = prev; 156195c635efSGarrett D'Amore 1562260e9a87SYuri Pankov if (prev == NULL) { 1563260e9a87SYuri Pankov np->child->prev = nch; 1564260e9a87SYuri Pankov nch->next = np->child; 1565260e9a87SYuri Pankov np->child = nch; 156695c635efSGarrett D'Amore } else { 1567260e9a87SYuri Pankov if (prev->next) 1568260e9a87SYuri Pankov prev->next->prev = nch; 1569260e9a87SYuri Pankov nch->next = prev->next; 1570260e9a87SYuri Pankov prev->next = nch; 157195c635efSGarrett D'Amore } 157295c635efSGarrett D'Amore } 157395c635efSGarrett D'Amore } 157495c635efSGarrett D'Amore 1575698f87a4SGarrett D'Amore /* 1576698f87a4SGarrett D'Amore * For some arguments of some macros, 1577698f87a4SGarrett D'Amore * convert all breakable hyphens into ASCII_HYPH. 1578698f87a4SGarrett D'Amore */ 1579260e9a87SYuri Pankov static void 1580698f87a4SGarrett D'Amore post_hyph(POST_ARGS) 1581698f87a4SGarrett D'Amore { 1582*371584c2SYuri Pankov struct roff_node *nch; 1583698f87a4SGarrett D'Amore char *cp; 1584698f87a4SGarrett D'Amore 1585260e9a87SYuri Pankov for (nch = mdoc->last->child; nch != NULL; nch = nch->next) { 1586*371584c2SYuri Pankov if (nch->type != ROFFT_TEXT) 1587698f87a4SGarrett D'Amore continue; 1588698f87a4SGarrett D'Amore cp = nch->string; 1589260e9a87SYuri Pankov if (*cp == '\0') 1590698f87a4SGarrett D'Amore continue; 1591260e9a87SYuri Pankov while (*(++cp) != '\0') 1592260e9a87SYuri Pankov if (*cp == '-' && 1593698f87a4SGarrett D'Amore isalpha((unsigned char)cp[-1]) && 1594698f87a4SGarrett D'Amore isalpha((unsigned char)cp[1])) 1595698f87a4SGarrett D'Amore *cp = ASCII_HYPH; 1596698f87a4SGarrett D'Amore } 1597698f87a4SGarrett D'Amore } 1598698f87a4SGarrett D'Amore 1599260e9a87SYuri Pankov static void 160095c635efSGarrett D'Amore post_ns(POST_ARGS) 160195c635efSGarrett D'Amore { 160295c635efSGarrett D'Amore 1603*371584c2SYuri Pankov if (mdoc->last->flags & MDOC_LINE) 1604260e9a87SYuri Pankov mandoc_msg(MANDOCERR_NS_SKIP, mdoc->parse, 1605260e9a87SYuri Pankov mdoc->last->line, mdoc->last->pos, NULL); 160695c635efSGarrett D'Amore } 160795c635efSGarrett D'Amore 1608260e9a87SYuri Pankov static void 160995c635efSGarrett D'Amore post_sh(POST_ARGS) 161095c635efSGarrett D'Amore { 161195c635efSGarrett D'Amore 1612260e9a87SYuri Pankov post_ignpar(mdoc); 161395c635efSGarrett D'Amore 1614260e9a87SYuri Pankov switch (mdoc->last->type) { 1615*371584c2SYuri Pankov case ROFFT_HEAD: 1616260e9a87SYuri Pankov post_sh_head(mdoc); 1617260e9a87SYuri Pankov break; 1618*371584c2SYuri Pankov case ROFFT_BODY: 1619260e9a87SYuri Pankov switch (mdoc->lastsec) { 1620260e9a87SYuri Pankov case SEC_NAME: 1621260e9a87SYuri Pankov post_sh_name(mdoc); 1622260e9a87SYuri Pankov break; 1623260e9a87SYuri Pankov case SEC_SEE_ALSO: 1624260e9a87SYuri Pankov post_sh_see_also(mdoc); 1625260e9a87SYuri Pankov break; 1626260e9a87SYuri Pankov case SEC_AUTHORS: 1627260e9a87SYuri Pankov post_sh_authors(mdoc); 1628260e9a87SYuri Pankov break; 1629260e9a87SYuri Pankov default: 1630260e9a87SYuri Pankov break; 1631260e9a87SYuri Pankov } 1632260e9a87SYuri Pankov break; 1633260e9a87SYuri Pankov default: 1634260e9a87SYuri Pankov break; 1635260e9a87SYuri Pankov } 163695c635efSGarrett D'Amore } 163795c635efSGarrett D'Amore 1638260e9a87SYuri Pankov static void 1639260e9a87SYuri Pankov post_sh_name(POST_ARGS) 164095c635efSGarrett D'Amore { 1641*371584c2SYuri Pankov struct roff_node *n; 1642260e9a87SYuri Pankov int hasnm, hasnd; 164395c635efSGarrett D'Amore 1644260e9a87SYuri Pankov hasnm = hasnd = 0; 164595c635efSGarrett D'Amore 1646260e9a87SYuri Pankov for (n = mdoc->last->child; n != NULL; n = n->next) { 1647260e9a87SYuri Pankov switch (n->tok) { 1648260e9a87SYuri Pankov case MDOC_Nm: 1649260e9a87SYuri Pankov hasnm = 1; 1650260e9a87SYuri Pankov break; 1651260e9a87SYuri Pankov case MDOC_Nd: 1652260e9a87SYuri Pankov hasnd = 1; 1653260e9a87SYuri Pankov if (n->next != NULL) 1654260e9a87SYuri Pankov mandoc_msg(MANDOCERR_NAMESEC_ND, 1655260e9a87SYuri Pankov mdoc->parse, n->line, n->pos, NULL); 1656260e9a87SYuri Pankov break; 1657*371584c2SYuri Pankov case TOKEN_NONE: 1658260e9a87SYuri Pankov if (hasnm) 1659260e9a87SYuri Pankov break; 1660260e9a87SYuri Pankov /* FALLTHROUGH */ 1661260e9a87SYuri Pankov default: 1662260e9a87SYuri Pankov mandoc_msg(MANDOCERR_NAMESEC_BAD, mdoc->parse, 1663260e9a87SYuri Pankov n->line, n->pos, mdoc_macronames[n->tok]); 1664260e9a87SYuri Pankov break; 1665260e9a87SYuri Pankov } 166695c635efSGarrett D'Amore } 166795c635efSGarrett D'Amore 1668260e9a87SYuri Pankov if ( ! hasnm) 1669260e9a87SYuri Pankov mandoc_msg(MANDOCERR_NAMESEC_NONM, mdoc->parse, 1670260e9a87SYuri Pankov mdoc->last->line, mdoc->last->pos, NULL); 1671260e9a87SYuri Pankov if ( ! hasnd) 1672260e9a87SYuri Pankov mandoc_msg(MANDOCERR_NAMESEC_NOND, mdoc->parse, 1673260e9a87SYuri Pankov mdoc->last->line, mdoc->last->pos, NULL); 1674260e9a87SYuri Pankov } 1675260e9a87SYuri Pankov 1676260e9a87SYuri Pankov static void 1677260e9a87SYuri Pankov post_sh_see_also(POST_ARGS) 1678260e9a87SYuri Pankov { 1679*371584c2SYuri Pankov const struct roff_node *n; 1680260e9a87SYuri Pankov const char *name, *sec; 1681260e9a87SYuri Pankov const char *lastname, *lastsec, *lastpunct; 1682260e9a87SYuri Pankov int cmp; 1683260e9a87SYuri Pankov 1684260e9a87SYuri Pankov n = mdoc->last->child; 1685260e9a87SYuri Pankov lastname = lastsec = lastpunct = NULL; 1686260e9a87SYuri Pankov while (n != NULL) { 1687*371584c2SYuri Pankov if (n->tok != MDOC_Xr || 1688*371584c2SYuri Pankov n->child == NULL || 1689*371584c2SYuri Pankov n->child->next == NULL) 1690260e9a87SYuri Pankov break; 1691260e9a87SYuri Pankov 1692260e9a87SYuri Pankov /* Process one .Xr node. */ 1693260e9a87SYuri Pankov 1694260e9a87SYuri Pankov name = n->child->string; 1695260e9a87SYuri Pankov sec = n->child->next->string; 1696260e9a87SYuri Pankov if (lastsec != NULL) { 1697260e9a87SYuri Pankov if (lastpunct[0] != ',' || lastpunct[1] != '\0') 1698260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_XR_PUNCT, 1699260e9a87SYuri Pankov mdoc->parse, n->line, n->pos, 1700260e9a87SYuri Pankov "%s before %s(%s)", lastpunct, 1701260e9a87SYuri Pankov name, sec); 1702260e9a87SYuri Pankov cmp = strcmp(lastsec, sec); 1703260e9a87SYuri Pankov if (cmp > 0) 1704260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_XR_ORDER, 1705260e9a87SYuri Pankov mdoc->parse, n->line, n->pos, 1706260e9a87SYuri Pankov "%s(%s) after %s(%s)", name, 1707260e9a87SYuri Pankov sec, lastname, lastsec); 1708260e9a87SYuri Pankov else if (cmp == 0 && 1709260e9a87SYuri Pankov strcasecmp(lastname, name) > 0) 1710260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_XR_ORDER, 1711260e9a87SYuri Pankov mdoc->parse, n->line, n->pos, 1712260e9a87SYuri Pankov "%s after %s", name, lastname); 1713260e9a87SYuri Pankov } 1714260e9a87SYuri Pankov lastname = name; 1715260e9a87SYuri Pankov lastsec = sec; 1716260e9a87SYuri Pankov 1717260e9a87SYuri Pankov /* Process the following node. */ 1718260e9a87SYuri Pankov 1719260e9a87SYuri Pankov n = n->next; 1720260e9a87SYuri Pankov if (n == NULL) 1721260e9a87SYuri Pankov break; 1722260e9a87SYuri Pankov if (n->tok == MDOC_Xr) { 1723260e9a87SYuri Pankov lastpunct = "none"; 172495c635efSGarrett D'Amore continue; 1725260e9a87SYuri Pankov } 1726*371584c2SYuri Pankov if (n->type != ROFFT_TEXT) 1727260e9a87SYuri Pankov break; 1728260e9a87SYuri Pankov for (name = n->string; *name != '\0'; name++) 1729260e9a87SYuri Pankov if (isalpha((const unsigned char)*name)) 1730260e9a87SYuri Pankov return; 1731260e9a87SYuri Pankov lastpunct = n->string; 1732260e9a87SYuri Pankov if (n->next == NULL) 1733260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_XR_PUNCT, mdoc->parse, 1734260e9a87SYuri Pankov n->line, n->pos, "%s after %s(%s)", 1735260e9a87SYuri Pankov lastpunct, lastname, lastsec); 1736260e9a87SYuri Pankov n = n->next; 173795c635efSGarrett D'Amore } 1738260e9a87SYuri Pankov } 173995c635efSGarrett D'Amore 1740260e9a87SYuri Pankov static int 1741*371584c2SYuri Pankov child_an(const struct roff_node *n) 1742260e9a87SYuri Pankov { 174395c635efSGarrett D'Amore 1744260e9a87SYuri Pankov for (n = n->child; n != NULL; n = n->next) 1745*371584c2SYuri Pankov if ((n->tok == MDOC_An && n->child != NULL) || child_an(n)) 1746*371584c2SYuri Pankov return 1; 1747*371584c2SYuri Pankov return 0; 174895c635efSGarrett D'Amore } 174995c635efSGarrett D'Amore 1750260e9a87SYuri Pankov static void 1751260e9a87SYuri Pankov post_sh_authors(POST_ARGS) 1752260e9a87SYuri Pankov { 1753260e9a87SYuri Pankov 1754260e9a87SYuri Pankov if ( ! child_an(mdoc->last)) 1755260e9a87SYuri Pankov mandoc_msg(MANDOCERR_AN_MISSING, mdoc->parse, 1756260e9a87SYuri Pankov mdoc->last->line, mdoc->last->pos, NULL); 1757260e9a87SYuri Pankov } 1758260e9a87SYuri Pankov 1759260e9a87SYuri Pankov static void 176095c635efSGarrett D'Amore post_sh_head(POST_ARGS) 176195c635efSGarrett D'Amore { 1762260e9a87SYuri Pankov const char *goodsec; 1763*371584c2SYuri Pankov enum roff_sec sec; 176495c635efSGarrett D'Amore 176595c635efSGarrett D'Amore /* 176695c635efSGarrett D'Amore * Process a new section. Sections are either "named" or 176795c635efSGarrett D'Amore * "custom". Custom sections are user-defined, while named ones 176895c635efSGarrett D'Amore * follow a conventional order and may only appear in certain 176995c635efSGarrett D'Amore * manual sections. 177095c635efSGarrett D'Amore */ 177195c635efSGarrett D'Amore 1772*371584c2SYuri Pankov sec = mdoc->last->sec; 177395c635efSGarrett D'Amore 177495c635efSGarrett D'Amore /* The NAME should be first. */ 177595c635efSGarrett D'Amore 177695c635efSGarrett D'Amore if (SEC_NAME != sec && SEC_NONE == mdoc->lastnamed) 1777260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_NAMESEC_FIRST, mdoc->parse, 1778260e9a87SYuri Pankov mdoc->last->line, mdoc->last->pos, 1779*371584c2SYuri Pankov "Sh %s", secnames[sec]); 178095c635efSGarrett D'Amore 178195c635efSGarrett D'Amore /* The SYNOPSIS gets special attention in other areas. */ 178295c635efSGarrett D'Amore 1783*371584c2SYuri Pankov if (sec == SEC_SYNOPSIS) { 1784698f87a4SGarrett D'Amore roff_setreg(mdoc->roff, "nS", 1, '='); 178595c635efSGarrett D'Amore mdoc->flags |= MDOC_SYNOPSIS; 1786698f87a4SGarrett D'Amore } else { 1787698f87a4SGarrett D'Amore roff_setreg(mdoc->roff, "nS", 0, '='); 178895c635efSGarrett D'Amore mdoc->flags &= ~MDOC_SYNOPSIS; 1789698f87a4SGarrett D'Amore } 179095c635efSGarrett D'Amore 179195c635efSGarrett D'Amore /* Mark our last section. */ 179295c635efSGarrett D'Amore 179395c635efSGarrett D'Amore mdoc->lastsec = sec; 179495c635efSGarrett D'Amore 179595c635efSGarrett D'Amore /* We don't care about custom sections after this. */ 179695c635efSGarrett D'Amore 1797*371584c2SYuri Pankov if (sec == SEC_CUSTOM) 1798260e9a87SYuri Pankov return; 179995c635efSGarrett D'Amore 180095c635efSGarrett D'Amore /* 180195c635efSGarrett D'Amore * Check whether our non-custom section is being repeated or is 180295c635efSGarrett D'Amore * out of order. 180395c635efSGarrett D'Amore */ 180495c635efSGarrett D'Amore 180595c635efSGarrett D'Amore if (sec == mdoc->lastnamed) 1806260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_SEC_REP, mdoc->parse, 1807260e9a87SYuri Pankov mdoc->last->line, mdoc->last->pos, 1808*371584c2SYuri Pankov "Sh %s", secnames[sec]); 180995c635efSGarrett D'Amore 181095c635efSGarrett D'Amore if (sec < mdoc->lastnamed) 1811260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_SEC_ORDER, mdoc->parse, 1812260e9a87SYuri Pankov mdoc->last->line, mdoc->last->pos, 1813*371584c2SYuri Pankov "Sh %s", secnames[sec]); 181495c635efSGarrett D'Amore 181595c635efSGarrett D'Amore /* Mark the last named section. */ 181695c635efSGarrett D'Amore 181795c635efSGarrett D'Amore mdoc->lastnamed = sec; 181895c635efSGarrett D'Amore 181995c635efSGarrett D'Amore /* Check particular section/manual conventions. */ 182095c635efSGarrett D'Amore 1821*371584c2SYuri Pankov if (mdoc->meta.msec == NULL) 1822260e9a87SYuri Pankov return; 182395c635efSGarrett D'Amore 1824260e9a87SYuri Pankov goodsec = NULL; 182595c635efSGarrett D'Amore switch (sec) { 1826260e9a87SYuri Pankov case SEC_ERRORS: 1827260e9a87SYuri Pankov if (*mdoc->meta.msec == '4') 1828260e9a87SYuri Pankov break; 1829260e9a87SYuri Pankov goodsec = "2, 3, 4, 9"; 183095c635efSGarrett D'Amore /* FALLTHROUGH */ 1831260e9a87SYuri Pankov case SEC_RETURN_VALUES: 1832260e9a87SYuri Pankov case SEC_LIBRARY: 183395c635efSGarrett D'Amore if (*mdoc->meta.msec == '2') 183495c635efSGarrett D'Amore break; 183595c635efSGarrett D'Amore if (*mdoc->meta.msec == '3') 183695c635efSGarrett D'Amore break; 1837260e9a87SYuri Pankov if (NULL == goodsec) 1838260e9a87SYuri Pankov goodsec = "2, 3, 9"; 1839260e9a87SYuri Pankov /* FALLTHROUGH */ 1840260e9a87SYuri Pankov case SEC_CONTEXT: 184195c635efSGarrett D'Amore if (*mdoc->meta.msec == '9') 184295c635efSGarrett D'Amore break; 1843260e9a87SYuri Pankov if (NULL == goodsec) 1844260e9a87SYuri Pankov goodsec = "9"; 1845260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_SEC_MSEC, mdoc->parse, 1846260e9a87SYuri Pankov mdoc->last->line, mdoc->last->pos, 1847*371584c2SYuri Pankov "Sh %s for %s only", secnames[sec], goodsec); 184895c635efSGarrett D'Amore break; 184995c635efSGarrett D'Amore default: 185095c635efSGarrett D'Amore break; 185195c635efSGarrett D'Amore } 185295c635efSGarrett D'Amore } 185395c635efSGarrett D'Amore 1854260e9a87SYuri Pankov static void 185595c635efSGarrett D'Amore post_ignpar(POST_ARGS) 185695c635efSGarrett D'Amore { 1857*371584c2SYuri Pankov struct roff_node *np; 185895c635efSGarrett D'Amore 1859260e9a87SYuri Pankov switch (mdoc->last->type) { 1860*371584c2SYuri Pankov case ROFFT_HEAD: 1861260e9a87SYuri Pankov post_hyph(mdoc); 1862260e9a87SYuri Pankov return; 1863*371584c2SYuri Pankov case ROFFT_BODY: 1864260e9a87SYuri Pankov break; 1865260e9a87SYuri Pankov default: 1866260e9a87SYuri Pankov return; 1867260e9a87SYuri Pankov } 186895c635efSGarrett D'Amore 1869*371584c2SYuri Pankov if ((np = mdoc->last->child) != NULL) 1870*371584c2SYuri Pankov if (np->tok == MDOC_Pp || np->tok == MDOC_Lp) { 1871260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_PAR_SKIP, 1872260e9a87SYuri Pankov mdoc->parse, np->line, np->pos, 1873260e9a87SYuri Pankov "%s after %s", mdoc_macronames[np->tok], 1874260e9a87SYuri Pankov mdoc_macronames[mdoc->last->tok]); 1875*371584c2SYuri Pankov roff_node_delete(mdoc, np); 187695c635efSGarrett D'Amore } 187795c635efSGarrett D'Amore 1878*371584c2SYuri Pankov if ((np = mdoc->last->last) != NULL) 1879*371584c2SYuri Pankov if (np->tok == MDOC_Pp || np->tok == MDOC_Lp) { 1880260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse, 1881260e9a87SYuri Pankov np->line, np->pos, "%s at the end of %s", 1882260e9a87SYuri Pankov mdoc_macronames[np->tok], 1883260e9a87SYuri Pankov mdoc_macronames[mdoc->last->tok]); 1884*371584c2SYuri Pankov roff_node_delete(mdoc, np); 188595c635efSGarrett D'Amore } 188695c635efSGarrett D'Amore } 188795c635efSGarrett D'Amore 1888260e9a87SYuri Pankov static void 1889*371584c2SYuri Pankov post_prevpar(POST_ARGS) 189095c635efSGarrett D'Amore { 1891*371584c2SYuri Pankov struct roff_node *n; 189295c635efSGarrett D'Amore 1893*371584c2SYuri Pankov n = mdoc->last; 1894*371584c2SYuri Pankov if (NULL == n->prev) 1895260e9a87SYuri Pankov return; 1896*371584c2SYuri Pankov if (n->type != ROFFT_ELEM && n->type != ROFFT_BLOCK) 1897260e9a87SYuri Pankov return; 189895c635efSGarrett D'Amore 1899260e9a87SYuri Pankov /* 190095c635efSGarrett D'Amore * Don't allow prior `Lp' or `Pp' prior to a paragraph-type 190195c635efSGarrett D'Amore * block: `Lp', `Pp', or non-compact `Bd' or `Bl'. 190295c635efSGarrett D'Amore */ 190395c635efSGarrett D'Amore 1904*371584c2SYuri Pankov if (n->prev->tok != MDOC_Pp && 1905*371584c2SYuri Pankov n->prev->tok != MDOC_Lp && 1906*371584c2SYuri Pankov n->prev->tok != MDOC_br) 1907260e9a87SYuri Pankov return; 1908*371584c2SYuri Pankov if (n->tok == MDOC_Bl && n->norm->Bl.comp) 1909260e9a87SYuri Pankov return; 1910*371584c2SYuri Pankov if (n->tok == MDOC_Bd && n->norm->Bd.comp) 1911260e9a87SYuri Pankov return; 1912*371584c2SYuri Pankov if (n->tok == MDOC_It && n->parent->norm->Bl.comp) 1913260e9a87SYuri Pankov return; 191495c635efSGarrett D'Amore 1915260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse, 1916*371584c2SYuri Pankov n->prev->line, n->prev->pos, 1917*371584c2SYuri Pankov "%s before %s", mdoc_macronames[n->prev->tok], 1918260e9a87SYuri Pankov mdoc_macronames[n->tok]); 1919*371584c2SYuri Pankov roff_node_delete(mdoc, n->prev); 192095c635efSGarrett D'Amore } 192195c635efSGarrett D'Amore 1922260e9a87SYuri Pankov static void 1923698f87a4SGarrett D'Amore post_par(POST_ARGS) 1924698f87a4SGarrett D'Amore { 1925*371584c2SYuri Pankov struct roff_node *np; 1926698f87a4SGarrett D'Amore 1927260e9a87SYuri Pankov np = mdoc->last; 1928*371584c2SYuri Pankov if (np->tok != MDOC_br && np->tok != MDOC_sp) 1929*371584c2SYuri Pankov post_prevpar(mdoc); 1930698f87a4SGarrett D'Amore 1931260e9a87SYuri Pankov if (np->tok == MDOC_sp) { 1932*371584c2SYuri Pankov if (np->child != NULL && np->child->next != NULL) 1933260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse, 1934260e9a87SYuri Pankov np->child->next->line, np->child->next->pos, 1935260e9a87SYuri Pankov "sp ... %s", np->child->next->string); 1936260e9a87SYuri Pankov } else if (np->child != NULL) 1937260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_ARG_SKIP, 1938260e9a87SYuri Pankov mdoc->parse, np->line, np->pos, "%s %s", 1939260e9a87SYuri Pankov mdoc_macronames[np->tok], np->child->string); 1940260e9a87SYuri Pankov 1941*371584c2SYuri Pankov if ((np = mdoc->last->prev) == NULL) { 1942260e9a87SYuri Pankov np = mdoc->last->parent; 1943*371584c2SYuri Pankov if (np->tok != MDOC_Sh && np->tok != MDOC_Ss) 1944260e9a87SYuri Pankov return; 1945*371584c2SYuri Pankov } else if (np->tok != MDOC_Pp && np->tok != MDOC_Lp && 1946*371584c2SYuri Pankov (mdoc->last->tok != MDOC_br || 1947*371584c2SYuri Pankov (np->tok != MDOC_sp && np->tok != MDOC_br))) 1948260e9a87SYuri Pankov return; 1949698f87a4SGarrett D'Amore 1950260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse, 1951260e9a87SYuri Pankov mdoc->last->line, mdoc->last->pos, 1952260e9a87SYuri Pankov "%s after %s", mdoc_macronames[mdoc->last->tok], 1953260e9a87SYuri Pankov mdoc_macronames[np->tok]); 1954*371584c2SYuri Pankov roff_node_delete(mdoc, mdoc->last); 195595c635efSGarrett D'Amore } 195695c635efSGarrett D'Amore 1957260e9a87SYuri Pankov static void 195895c635efSGarrett D'Amore post_dd(POST_ARGS) 195995c635efSGarrett D'Amore { 1960*371584c2SYuri Pankov struct roff_node *n; 1961260e9a87SYuri Pankov char *datestr; 196295c635efSGarrett D'Amore 1963*371584c2SYuri Pankov n = mdoc->last; 1964*371584c2SYuri Pankov if (mdoc->meta.date != NULL) { 1965*371584c2SYuri Pankov mandoc_msg(MANDOCERR_PROLOG_REP, mdoc->parse, 1966*371584c2SYuri Pankov n->line, n->pos, "Dd"); 196795c635efSGarrett D'Amore free(mdoc->meta.date); 1968*371584c2SYuri Pankov } else if (mdoc->flags & MDOC_PBODY) 1969*371584c2SYuri Pankov mandoc_msg(MANDOCERR_PROLOG_LATE, mdoc->parse, 1970*371584c2SYuri Pankov n->line, n->pos, "Dd"); 1971*371584c2SYuri Pankov else if (mdoc->meta.title != NULL) 1972*371584c2SYuri Pankov mandoc_msg(MANDOCERR_PROLOG_ORDER, mdoc->parse, 1973*371584c2SYuri Pankov n->line, n->pos, "Dd after Dt"); 1974*371584c2SYuri Pankov else if (mdoc->meta.os != NULL) 1975*371584c2SYuri Pankov mandoc_msg(MANDOCERR_PROLOG_ORDER, mdoc->parse, 1976*371584c2SYuri Pankov n->line, n->pos, "Dd after Os"); 197795c635efSGarrett D'Amore 1978*371584c2SYuri Pankov if (n->child == NULL || n->child->string[0] == '\0') { 1979260e9a87SYuri Pankov mdoc->meta.date = mdoc->quick ? mandoc_strdup("") : 1980260e9a87SYuri Pankov mandoc_normdate(mdoc->parse, NULL, n->line, n->pos); 1981260e9a87SYuri Pankov goto out; 198295c635efSGarrett D'Amore } 198395c635efSGarrett D'Amore 1984260e9a87SYuri Pankov datestr = NULL; 1985*371584c2SYuri Pankov deroff(&datestr, n); 1986260e9a87SYuri Pankov if (mdoc->quick) 1987260e9a87SYuri Pankov mdoc->meta.date = datestr; 1988260e9a87SYuri Pankov else { 1989260e9a87SYuri Pankov mdoc->meta.date = mandoc_normdate(mdoc->parse, 1990260e9a87SYuri Pankov datestr, n->line, n->pos); 1991260e9a87SYuri Pankov free(datestr); 199295c635efSGarrett D'Amore } 1993260e9a87SYuri Pankov out: 1994*371584c2SYuri Pankov roff_node_delete(mdoc, n); 199595c635efSGarrett D'Amore } 199695c635efSGarrett D'Amore 1997260e9a87SYuri Pankov static void 199895c635efSGarrett D'Amore post_dt(POST_ARGS) 199995c635efSGarrett D'Amore { 2000*371584c2SYuri Pankov struct roff_node *nn, *n; 200195c635efSGarrett D'Amore const char *cp; 200295c635efSGarrett D'Amore char *p; 200395c635efSGarrett D'Amore 200495c635efSGarrett D'Amore n = mdoc->last; 2005*371584c2SYuri Pankov if (mdoc->flags & MDOC_PBODY) { 2006*371584c2SYuri Pankov mandoc_msg(MANDOCERR_DT_LATE, mdoc->parse, 2007*371584c2SYuri Pankov n->line, n->pos, "Dt"); 2008*371584c2SYuri Pankov goto out; 2009*371584c2SYuri Pankov } 2010*371584c2SYuri Pankov 2011*371584c2SYuri Pankov if (mdoc->meta.title != NULL) 2012*371584c2SYuri Pankov mandoc_msg(MANDOCERR_PROLOG_REP, mdoc->parse, 2013*371584c2SYuri Pankov n->line, n->pos, "Dt"); 2014*371584c2SYuri Pankov else if (mdoc->meta.os != NULL) 2015*371584c2SYuri Pankov mandoc_msg(MANDOCERR_PROLOG_ORDER, mdoc->parse, 2016*371584c2SYuri Pankov n->line, n->pos, "Dt after Os"); 201795c635efSGarrett D'Amore 2018260e9a87SYuri Pankov free(mdoc->meta.title); 2019260e9a87SYuri Pankov free(mdoc->meta.msec); 2020260e9a87SYuri Pankov free(mdoc->meta.vol); 2021260e9a87SYuri Pankov free(mdoc->meta.arch); 202295c635efSGarrett D'Amore 2023260e9a87SYuri Pankov mdoc->meta.title = NULL; 2024260e9a87SYuri Pankov mdoc->meta.msec = NULL; 2025260e9a87SYuri Pankov mdoc->meta.vol = NULL; 2026260e9a87SYuri Pankov mdoc->meta.arch = NULL; 202795c635efSGarrett D'Amore 2028260e9a87SYuri Pankov /* Mandatory first argument: title. */ 202995c635efSGarrett D'Amore 2030260e9a87SYuri Pankov nn = n->child; 2031260e9a87SYuri Pankov if (nn == NULL || *nn->string == '\0') { 2032260e9a87SYuri Pankov mandoc_msg(MANDOCERR_DT_NOTITLE, 2033260e9a87SYuri Pankov mdoc->parse, n->line, n->pos, "Dt"); 2034260e9a87SYuri Pankov mdoc->meta.title = mandoc_strdup("UNTITLED"); 2035260e9a87SYuri Pankov } else { 2036260e9a87SYuri Pankov mdoc->meta.title = mandoc_strdup(nn->string); 203795c635efSGarrett D'Amore 2038260e9a87SYuri Pankov /* Check that all characters are uppercase. */ 203995c635efSGarrett D'Amore 2040260e9a87SYuri Pankov for (p = nn->string; *p != '\0'; p++) 2041260e9a87SYuri Pankov if (islower((unsigned char)*p)) { 2042260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_TITLE_CASE, 2043260e9a87SYuri Pankov mdoc->parse, nn->line, 2044260e9a87SYuri Pankov nn->pos + (p - nn->string), 2045260e9a87SYuri Pankov "Dt %s", nn->string); 2046260e9a87SYuri Pankov break; 2047260e9a87SYuri Pankov } 204895c635efSGarrett D'Amore } 204995c635efSGarrett D'Amore 2050260e9a87SYuri Pankov /* Mandatory second argument: section.�*/ 205195c635efSGarrett D'Amore 2052260e9a87SYuri Pankov if (nn != NULL) 2053260e9a87SYuri Pankov nn = nn->next; 205495c635efSGarrett D'Amore 2055260e9a87SYuri Pankov if (nn == NULL) { 2056260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_MSEC_MISSING, 2057260e9a87SYuri Pankov mdoc->parse, n->line, n->pos, 2058260e9a87SYuri Pankov "Dt %s", mdoc->meta.title); 205995c635efSGarrett D'Amore mdoc->meta.vol = mandoc_strdup("LOCAL"); 2060260e9a87SYuri Pankov goto out; /* msec and arch remain NULL. */ 206195c635efSGarrett D'Amore } 206295c635efSGarrett D'Amore 2063260e9a87SYuri Pankov mdoc->meta.msec = mandoc_strdup(nn->string); 2064260e9a87SYuri Pankov 2065260e9a87SYuri Pankov /* Infer volume title from section number. */ 206695c635efSGarrett D'Amore 206795c635efSGarrett D'Amore cp = mandoc_a2msec(nn->string); 2068260e9a87SYuri Pankov if (cp == NULL) { 2069260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_MSEC_BAD, mdoc->parse, 2070260e9a87SYuri Pankov nn->line, nn->pos, "Dt ... %s", nn->string); 207195c635efSGarrett D'Amore mdoc->meta.vol = mandoc_strdup(nn->string); 2072260e9a87SYuri Pankov } else 2073260e9a87SYuri Pankov mdoc->meta.vol = mandoc_strdup(cp); 207495c635efSGarrett D'Amore 2075260e9a87SYuri Pankov /* Optional third argument: architecture. */ 207695c635efSGarrett D'Amore 2077260e9a87SYuri Pankov if ((nn = nn->next) == NULL) 2078260e9a87SYuri Pankov goto out; 207995c635efSGarrett D'Amore 2080260e9a87SYuri Pankov for (p = nn->string; *p != '\0'; p++) 2081260e9a87SYuri Pankov *p = tolower((unsigned char)*p); 2082260e9a87SYuri Pankov mdoc->meta.arch = mandoc_strdup(nn->string); 208395c635efSGarrett D'Amore 2084260e9a87SYuri Pankov /* Ignore fourth and later arguments. */ 208595c635efSGarrett D'Amore 2086260e9a87SYuri Pankov if ((nn = nn->next) != NULL) 2087260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse, 2088260e9a87SYuri Pankov nn->line, nn->pos, "Dt ... %s", nn->string); 208995c635efSGarrett D'Amore 2090260e9a87SYuri Pankov out: 2091*371584c2SYuri Pankov roff_node_delete(mdoc, n); 209295c635efSGarrett D'Amore } 209395c635efSGarrett D'Amore 2094260e9a87SYuri Pankov static void 209595c635efSGarrett D'Amore post_bx(POST_ARGS) 209695c635efSGarrett D'Amore { 2097*371584c2SYuri Pankov struct roff_node *n; 209895c635efSGarrett D'Amore 2099260e9a87SYuri Pankov /* 210095c635efSGarrett D'Amore * Make `Bx's second argument always start with an uppercase 210195c635efSGarrett D'Amore * letter. Groff checks if it's an "accepted" term, but we just 210295c635efSGarrett D'Amore * uppercase blindly. 210395c635efSGarrett D'Amore */ 210495c635efSGarrett D'Amore 2105*371584c2SYuri Pankov if ((n = mdoc->last->child) != NULL && (n = n->next) != NULL) 2106260e9a87SYuri Pankov *n->string = (char)toupper((unsigned char)*n->string); 210795c635efSGarrett D'Amore } 210895c635efSGarrett D'Amore 2109260e9a87SYuri Pankov static void 211095c635efSGarrett D'Amore post_os(POST_ARGS) 211195c635efSGarrett D'Amore { 211295c635efSGarrett D'Amore #ifndef OSNAME 211395c635efSGarrett D'Amore struct utsname utsname; 2114260e9a87SYuri Pankov static char *defbuf; 211595c635efSGarrett D'Amore #endif 2116*371584c2SYuri Pankov struct roff_node *n; 211795c635efSGarrett D'Amore 211895c635efSGarrett D'Amore n = mdoc->last; 2119*371584c2SYuri Pankov if (mdoc->meta.os != NULL) 2120*371584c2SYuri Pankov mandoc_msg(MANDOCERR_PROLOG_REP, mdoc->parse, 2121*371584c2SYuri Pankov n->line, n->pos, "Os"); 2122*371584c2SYuri Pankov else if (mdoc->flags & MDOC_PBODY) 2123*371584c2SYuri Pankov mandoc_msg(MANDOCERR_PROLOG_LATE, mdoc->parse, 2124*371584c2SYuri Pankov n->line, n->pos, "Os"); 212595c635efSGarrett D'Amore 212695c635efSGarrett D'Amore /* 2127698f87a4SGarrett D'Amore * Set the operating system by way of the `Os' macro. 2128698f87a4SGarrett D'Amore * The order of precedence is: 2129698f87a4SGarrett D'Amore * 1. the argument of the `Os' macro, unless empty 2130698f87a4SGarrett D'Amore * 2. the -Ios=foo command line argument, if provided 2131698f87a4SGarrett D'Amore * 3. -DOSNAME="\"foo\"", if provided during compilation 2132698f87a4SGarrett D'Amore * 4. "sysname release" from uname(3) 2133260e9a87SYuri Pankov */ 213495c635efSGarrett D'Amore 2135698f87a4SGarrett D'Amore free(mdoc->meta.os); 2136260e9a87SYuri Pankov mdoc->meta.os = NULL; 2137*371584c2SYuri Pankov deroff(&mdoc->meta.os, n); 2138260e9a87SYuri Pankov if (mdoc->meta.os) 2139260e9a87SYuri Pankov goto out; 214095c635efSGarrett D'Amore 2141260e9a87SYuri Pankov if (mdoc->defos) { 2142260e9a87SYuri Pankov mdoc->meta.os = mandoc_strdup(mdoc->defos); 2143260e9a87SYuri Pankov goto out; 214495c635efSGarrett D'Amore } 214595c635efSGarrett D'Amore 214695c635efSGarrett D'Amore #ifdef OSNAME 2147260e9a87SYuri Pankov mdoc->meta.os = mandoc_strdup(OSNAME); 214895c635efSGarrett D'Amore #else /*!OSNAME */ 2149*371584c2SYuri Pankov if (defbuf == NULL) { 2150*371584c2SYuri Pankov if (uname(&utsname) == -1) { 2151260e9a87SYuri Pankov mandoc_msg(MANDOCERR_OS_UNAME, mdoc->parse, 2152260e9a87SYuri Pankov n->line, n->pos, "Os"); 2153260e9a87SYuri Pankov defbuf = mandoc_strdup("UNKNOWN"); 2154260e9a87SYuri Pankov } else 2155260e9a87SYuri Pankov mandoc_asprintf(&defbuf, "%s %s", 2156260e9a87SYuri Pankov utsname.sysname, utsname.release); 215795c635efSGarrett D'Amore } 2158260e9a87SYuri Pankov mdoc->meta.os = mandoc_strdup(defbuf); 2159260e9a87SYuri Pankov #endif /*!OSNAME*/ 216095c635efSGarrett D'Amore 2161260e9a87SYuri Pankov out: 2162*371584c2SYuri Pankov roff_node_delete(mdoc, n); 216395c635efSGarrett D'Amore } 216495c635efSGarrett D'Amore 2165260e9a87SYuri Pankov /* 2166260e9a87SYuri Pankov * If no argument is provided, 2167260e9a87SYuri Pankov * fill in the name of the current manual page. 2168260e9a87SYuri Pankov */ 2169260e9a87SYuri Pankov static void 2170260e9a87SYuri Pankov post_ex(POST_ARGS) 217195c635efSGarrett D'Amore { 2172*371584c2SYuri Pankov struct roff_node *n; 217395c635efSGarrett D'Amore 2174*371584c2SYuri Pankov post_std(mdoc); 217595c635efSGarrett D'Amore 2176*371584c2SYuri Pankov n = mdoc->last; 2177*371584c2SYuri Pankov if (n->child != NULL) 2178260e9a87SYuri Pankov return; 217995c635efSGarrett D'Amore 2180260e9a87SYuri Pankov if (mdoc->meta.name == NULL) { 2181260e9a87SYuri Pankov mandoc_msg(MANDOCERR_EX_NONAME, mdoc->parse, 2182260e9a87SYuri Pankov n->line, n->pos, "Ex"); 2183260e9a87SYuri Pankov return; 218495c635efSGarrett D'Amore } 218595c635efSGarrett D'Amore 2186*371584c2SYuri Pankov mdoc->next = ROFF_NEXT_CHILD; 2187*371584c2SYuri Pankov roff_word_alloc(mdoc, n->line, n->pos, mdoc->meta.name); 2188260e9a87SYuri Pankov mdoc->last = n; 218995c635efSGarrett D'Amore } 219095c635efSGarrett D'Amore 2191*371584c2SYuri Pankov enum roff_sec 2192*371584c2SYuri Pankov mdoc_a2sec(const char *p) 219395c635efSGarrett D'Amore { 219495c635efSGarrett D'Amore int i; 219595c635efSGarrett D'Amore 2196260e9a87SYuri Pankov for (i = 0; i < (int)SEC__MAX; i++) 219795c635efSGarrett D'Amore if (secnames[i] && 0 == strcmp(p, secnames[i])) 2198*371584c2SYuri Pankov return (enum roff_sec)i; 219995c635efSGarrett D'Amore 2200*371584c2SYuri Pankov return SEC_CUSTOM; 220195c635efSGarrett D'Amore } 220295c635efSGarrett D'Amore 220395c635efSGarrett D'Amore static size_t 2204*371584c2SYuri Pankov macro2len(int macro) 220595c635efSGarrett D'Amore { 220695c635efSGarrett D'Amore 220795c635efSGarrett D'Amore switch (macro) { 2208260e9a87SYuri Pankov case MDOC_Ad: 2209*371584c2SYuri Pankov return 12; 2210260e9a87SYuri Pankov case MDOC_Ao: 2211*371584c2SYuri Pankov return 12; 2212260e9a87SYuri Pankov case MDOC_An: 2213*371584c2SYuri Pankov return 12; 2214260e9a87SYuri Pankov case MDOC_Aq: 2215*371584c2SYuri Pankov return 12; 2216260e9a87SYuri Pankov case MDOC_Ar: 2217*371584c2SYuri Pankov return 12; 2218260e9a87SYuri Pankov case MDOC_Bo: 2219*371584c2SYuri Pankov return 12; 2220260e9a87SYuri Pankov case MDOC_Bq: 2221*371584c2SYuri Pankov return 12; 2222260e9a87SYuri Pankov case MDOC_Cd: 2223*371584c2SYuri Pankov return 12; 2224260e9a87SYuri Pankov case MDOC_Cm: 2225*371584c2SYuri Pankov return 10; 2226260e9a87SYuri Pankov case MDOC_Do: 2227*371584c2SYuri Pankov return 10; 2228260e9a87SYuri Pankov case MDOC_Dq: 2229*371584c2SYuri Pankov return 12; 2230260e9a87SYuri Pankov case MDOC_Dv: 2231*371584c2SYuri Pankov return 12; 2232260e9a87SYuri Pankov case MDOC_Eo: 2233*371584c2SYuri Pankov return 12; 2234260e9a87SYuri Pankov case MDOC_Em: 2235*371584c2SYuri Pankov return 10; 2236260e9a87SYuri Pankov case MDOC_Er: 2237*371584c2SYuri Pankov return 17; 2238260e9a87SYuri Pankov case MDOC_Ev: 2239*371584c2SYuri Pankov return 15; 2240260e9a87SYuri Pankov case MDOC_Fa: 2241*371584c2SYuri Pankov return 12; 2242260e9a87SYuri Pankov case MDOC_Fl: 2243*371584c2SYuri Pankov return 10; 2244260e9a87SYuri Pankov case MDOC_Fo: 2245*371584c2SYuri Pankov return 16; 2246260e9a87SYuri Pankov case MDOC_Fn: 2247*371584c2SYuri Pankov return 16; 2248260e9a87SYuri Pankov case MDOC_Ic: 2249*371584c2SYuri Pankov return 10; 2250260e9a87SYuri Pankov case MDOC_Li: 2251*371584c2SYuri Pankov return 16; 2252260e9a87SYuri Pankov case MDOC_Ms: 2253*371584c2SYuri Pankov return 6; 2254260e9a87SYuri Pankov case MDOC_Nm: 2255*371584c2SYuri Pankov return 10; 2256260e9a87SYuri Pankov case MDOC_No: 2257*371584c2SYuri Pankov return 12; 2258260e9a87SYuri Pankov case MDOC_Oo: 2259*371584c2SYuri Pankov return 10; 2260260e9a87SYuri Pankov case MDOC_Op: 2261*371584c2SYuri Pankov return 14; 2262260e9a87SYuri Pankov case MDOC_Pa: 2263*371584c2SYuri Pankov return 32; 2264260e9a87SYuri Pankov case MDOC_Pf: 2265*371584c2SYuri Pankov return 12; 2266260e9a87SYuri Pankov case MDOC_Po: 2267*371584c2SYuri Pankov return 12; 2268260e9a87SYuri Pankov case MDOC_Pq: 2269*371584c2SYuri Pankov return 12; 2270260e9a87SYuri Pankov case MDOC_Ql: 2271*371584c2SYuri Pankov return 16; 2272260e9a87SYuri Pankov case MDOC_Qo: 2273*371584c2SYuri Pankov return 12; 2274260e9a87SYuri Pankov case MDOC_So: 2275*371584c2SYuri Pankov return 12; 2276260e9a87SYuri Pankov case MDOC_Sq: 2277*371584c2SYuri Pankov return 12; 2278260e9a87SYuri Pankov case MDOC_Sy: 2279*371584c2SYuri Pankov return 6; 2280260e9a87SYuri Pankov case MDOC_Sx: 2281*371584c2SYuri Pankov return 16; 2282260e9a87SYuri Pankov case MDOC_Tn: 2283*371584c2SYuri Pankov return 10; 2284260e9a87SYuri Pankov case MDOC_Va: 2285*371584c2SYuri Pankov return 12; 2286260e9a87SYuri Pankov case MDOC_Vt: 2287*371584c2SYuri Pankov return 12; 2288260e9a87SYuri Pankov case MDOC_Xr: 2289*371584c2SYuri Pankov return 10; 229095c635efSGarrett D'Amore default: 229195c635efSGarrett D'Amore break; 229295c635efSGarrett D'Amore }; 2293*371584c2SYuri Pankov return 0; 229495c635efSGarrett D'Amore } 2295