1*a40ea1a7SYuri Pankov /* $Id: mdoc_validate.c,v 1.318 2017/02/06 03:44:58 schwarze Exp $ */ 295c635efSGarrett D'Amore /* 3698f87a4SGarrett D'Amore * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv> 4*a40ea1a7SYuri Pankov * Copyright (c) 2010-2017 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 * 11371584c2SYuri 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 13371584c2SYuri 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" 35371584c2SYuri Pankov #include "mandoc.h" 36371584c2SYuri Pankov #include "roff.h" 37371584c2SYuri Pankov #include "mdoc.h" 3895c635efSGarrett D'Amore #include "libmandoc.h" 39371584c2SYuri Pankov #include "roff_int.h" 40371584c2SYuri Pankov #include "libmdoc.h" 4195c635efSGarrett D'Amore 4295c635efSGarrett D'Amore /* FIXME: .Bl -diag can't have non-text children in HEAD. */ 4395c635efSGarrett D'Amore 44371584c2SYuri 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*a40ea1a7SYuri Pankov static int build_list(struct roff_man *, int); 55371584c2SYuri Pankov static void check_text(struct roff_man *, int, int, char *); 56371584c2SYuri Pankov static void check_argv(struct roff_man *, 57371584c2SYuri Pankov struct roff_node *, struct mdoc_argv *); 58371584c2SYuri Pankov static void check_args(struct roff_man *, struct roff_node *); 59371584c2SYuri Pankov static int child_an(const struct roff_node *); 60371584c2SYuri Pankov static size_t macro2len(int); 61260e9a87SYuri Pankov static void rewrite_macro2len(char **); 62260e9a87SYuri Pankov 63260e9a87SYuri Pankov static void post_an(POST_ARGS); 64371584c2SYuri Pankov static void post_an_norm(POST_ARGS); 65260e9a87SYuri Pankov static void post_at(POST_ARGS); 66371584c2SYuri Pankov static void post_bd(POST_ARGS); 67260e9a87SYuri Pankov static void post_bf(POST_ARGS); 68260e9a87SYuri Pankov static void post_bk(POST_ARGS); 69260e9a87SYuri Pankov static void post_bl(POST_ARGS); 70260e9a87SYuri Pankov static void post_bl_block(POST_ARGS); 71260e9a87SYuri Pankov static void post_bl_head(POST_ARGS); 72371584c2SYuri Pankov static void post_bl_norm(POST_ARGS); 73260e9a87SYuri Pankov static void post_bx(POST_ARGS); 74260e9a87SYuri Pankov static void post_defaults(POST_ARGS); 75371584c2SYuri 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); 93371584c2SYuri Pankov static void post_obsolete(POST_ARGS); 94260e9a87SYuri Pankov static void post_os(POST_ARGS); 95260e9a87SYuri Pankov static void post_par(POST_ARGS); 96371584c2SYuri Pankov static void post_prevpar(POST_ARGS); 97260e9a87SYuri Pankov static void post_root(POST_ARGS); 98260e9a87SYuri Pankov static void post_rs(POST_ARGS); 99*a40ea1a7SYuri Pankov static void post_rv(POST_ARGS); 100260e9a87SYuri Pankov static void post_sh(POST_ARGS); 101260e9a87SYuri Pankov static void post_sh_head(POST_ARGS); 102260e9a87SYuri Pankov static void post_sh_name(POST_ARGS); 103260e9a87SYuri Pankov static void post_sh_see_also(POST_ARGS); 104260e9a87SYuri Pankov static void post_sh_authors(POST_ARGS); 105260e9a87SYuri Pankov static void post_sm(POST_ARGS); 106260e9a87SYuri Pankov static void post_st(POST_ARGS); 107371584c2SYuri Pankov static void post_std(POST_ARGS); 108*a40ea1a7SYuri Pankov static void post_xr(POST_ARGS); 109*a40ea1a7SYuri Pankov static void post_xx(POST_ARGS); 110371584c2SYuri Pankov 111371584c2SYuri Pankov static v_post mdoc_valids[MDOC_MAX] = { 112371584c2SYuri Pankov NULL, /* Ap */ 113371584c2SYuri Pankov post_dd, /* Dd */ 114371584c2SYuri Pankov post_dt, /* Dt */ 115371584c2SYuri Pankov post_os, /* Os */ 116371584c2SYuri Pankov post_sh, /* Sh */ 117371584c2SYuri Pankov post_ignpar, /* Ss */ 118371584c2SYuri Pankov post_par, /* Pp */ 119371584c2SYuri Pankov post_display, /* D1 */ 120371584c2SYuri Pankov post_display, /* Dl */ 121371584c2SYuri Pankov post_display, /* Bd */ 122371584c2SYuri Pankov NULL, /* Ed */ 123371584c2SYuri Pankov post_bl, /* Bl */ 124371584c2SYuri Pankov NULL, /* El */ 125371584c2SYuri Pankov post_it, /* It */ 126371584c2SYuri Pankov NULL, /* Ad */ 127371584c2SYuri Pankov post_an, /* An */ 128371584c2SYuri Pankov post_defaults, /* Ar */ 129371584c2SYuri Pankov NULL, /* Cd */ 130371584c2SYuri Pankov NULL, /* Cm */ 131371584c2SYuri Pankov NULL, /* Dv */ 132371584c2SYuri Pankov NULL, /* Er */ 133371584c2SYuri Pankov NULL, /* Ev */ 134371584c2SYuri Pankov post_ex, /* Ex */ 135371584c2SYuri Pankov post_fa, /* Fa */ 136371584c2SYuri Pankov NULL, /* Fd */ 137371584c2SYuri Pankov NULL, /* Fl */ 138371584c2SYuri Pankov post_fn, /* Fn */ 139371584c2SYuri Pankov NULL, /* Ft */ 140371584c2SYuri Pankov NULL, /* Ic */ 141371584c2SYuri Pankov NULL, /* In */ 142371584c2SYuri Pankov post_defaults, /* Li */ 143371584c2SYuri Pankov post_nd, /* Nd */ 144371584c2SYuri Pankov post_nm, /* Nm */ 145371584c2SYuri Pankov NULL, /* Op */ 146371584c2SYuri Pankov post_obsolete, /* Ot */ 147371584c2SYuri Pankov post_defaults, /* Pa */ 148*a40ea1a7SYuri Pankov post_rv, /* Rv */ 149371584c2SYuri Pankov post_st, /* St */ 150371584c2SYuri Pankov NULL, /* Va */ 151371584c2SYuri Pankov NULL, /* Vt */ 152*a40ea1a7SYuri Pankov post_xr, /* Xr */ 153371584c2SYuri Pankov NULL, /* %A */ 154371584c2SYuri Pankov post_hyph, /* %B */ /* FIXME: can be used outside Rs/Re. */ 155371584c2SYuri Pankov NULL, /* %D */ 156371584c2SYuri Pankov NULL, /* %I */ 157371584c2SYuri Pankov NULL, /* %J */ 158371584c2SYuri Pankov post_hyph, /* %N */ 159371584c2SYuri Pankov post_hyph, /* %O */ 160371584c2SYuri Pankov NULL, /* %P */ 161371584c2SYuri Pankov post_hyph, /* %R */ 162371584c2SYuri Pankov post_hyph, /* %T */ /* FIXME: can be used outside Rs/Re. */ 163371584c2SYuri Pankov NULL, /* %V */ 164371584c2SYuri Pankov NULL, /* Ac */ 165371584c2SYuri Pankov NULL, /* Ao */ 166371584c2SYuri Pankov NULL, /* Aq */ 167371584c2SYuri Pankov post_at, /* At */ 168371584c2SYuri Pankov NULL, /* Bc */ 169371584c2SYuri Pankov post_bf, /* Bf */ 170371584c2SYuri Pankov NULL, /* Bo */ 171371584c2SYuri Pankov NULL, /* Bq */ 172*a40ea1a7SYuri Pankov post_xx, /* Bsx */ 173371584c2SYuri Pankov post_bx, /* Bx */ 174371584c2SYuri Pankov post_obsolete, /* Db */ 175371584c2SYuri Pankov NULL, /* Dc */ 176371584c2SYuri Pankov NULL, /* Do */ 177371584c2SYuri Pankov NULL, /* Dq */ 178371584c2SYuri Pankov NULL, /* Ec */ 179371584c2SYuri Pankov NULL, /* Ef */ 180371584c2SYuri Pankov NULL, /* Em */ 181371584c2SYuri Pankov NULL, /* Eo */ 182*a40ea1a7SYuri Pankov post_xx, /* Fx */ 183371584c2SYuri Pankov NULL, /* Ms */ 184371584c2SYuri Pankov NULL, /* No */ 185371584c2SYuri Pankov post_ns, /* Ns */ 186*a40ea1a7SYuri Pankov post_xx, /* Nx */ 187*a40ea1a7SYuri Pankov post_xx, /* Ox */ 188371584c2SYuri Pankov NULL, /* Pc */ 189371584c2SYuri Pankov NULL, /* Pf */ 190371584c2SYuri Pankov NULL, /* Po */ 191371584c2SYuri Pankov NULL, /* Pq */ 192371584c2SYuri Pankov NULL, /* Qc */ 193371584c2SYuri Pankov NULL, /* Ql */ 194371584c2SYuri Pankov NULL, /* Qo */ 195371584c2SYuri Pankov NULL, /* Qq */ 196371584c2SYuri Pankov NULL, /* Re */ 197371584c2SYuri Pankov post_rs, /* Rs */ 198371584c2SYuri Pankov NULL, /* Sc */ 199371584c2SYuri Pankov NULL, /* So */ 200371584c2SYuri Pankov NULL, /* Sq */ 201371584c2SYuri Pankov post_sm, /* Sm */ 202371584c2SYuri Pankov post_hyph, /* Sx */ 203371584c2SYuri Pankov NULL, /* Sy */ 204371584c2SYuri Pankov NULL, /* Tn */ 205*a40ea1a7SYuri Pankov post_xx, /* Ux */ 206371584c2SYuri Pankov NULL, /* Xc */ 207371584c2SYuri Pankov NULL, /* Xo */ 208371584c2SYuri Pankov post_fo, /* Fo */ 209371584c2SYuri Pankov NULL, /* Fc */ 210371584c2SYuri Pankov NULL, /* Oo */ 211371584c2SYuri Pankov NULL, /* Oc */ 212371584c2SYuri Pankov post_bk, /* Bk */ 213371584c2SYuri Pankov NULL, /* Ek */ 214371584c2SYuri Pankov post_eoln, /* Bt */ 215371584c2SYuri Pankov NULL, /* Hf */ 216371584c2SYuri Pankov post_obsolete, /* Fr */ 217371584c2SYuri Pankov post_eoln, /* Ud */ 218371584c2SYuri Pankov post_lb, /* Lb */ 219371584c2SYuri Pankov post_par, /* Lp */ 220371584c2SYuri Pankov NULL, /* Lk */ 221371584c2SYuri Pankov post_defaults, /* Mt */ 222371584c2SYuri Pankov NULL, /* Brq */ 223371584c2SYuri Pankov NULL, /* Bro */ 224371584c2SYuri Pankov NULL, /* Brc */ 225371584c2SYuri Pankov NULL, /* %C */ 226371584c2SYuri Pankov post_es, /* Es */ 227371584c2SYuri Pankov post_en, /* En */ 228*a40ea1a7SYuri Pankov post_xx, /* Dx */ 229371584c2SYuri Pankov NULL, /* %Q */ 230371584c2SYuri Pankov post_par, /* br */ 231371584c2SYuri Pankov post_par, /* sp */ 232371584c2SYuri Pankov NULL, /* %U */ 233371584c2SYuri Pankov NULL, /* Ta */ 234371584c2SYuri Pankov NULL, /* ll */ 23595c635efSGarrett D'Amore }; 23695c635efSGarrett D'Amore 23795c635efSGarrett D'Amore #define RSORD_MAX 14 /* Number of `Rs' blocks. */ 23895c635efSGarrett D'Amore 239371584c2SYuri Pankov static const int rsord[RSORD_MAX] = { 24095c635efSGarrett D'Amore MDOC__A, 24195c635efSGarrett D'Amore MDOC__T, 24295c635efSGarrett D'Amore MDOC__B, 24395c635efSGarrett D'Amore MDOC__I, 24495c635efSGarrett D'Amore MDOC__J, 24595c635efSGarrett D'Amore MDOC__R, 24695c635efSGarrett D'Amore MDOC__N, 24795c635efSGarrett D'Amore MDOC__V, 248698f87a4SGarrett D'Amore MDOC__U, 24995c635efSGarrett D'Amore MDOC__P, 25095c635efSGarrett D'Amore MDOC__Q, 25195c635efSGarrett D'Amore MDOC__C, 252698f87a4SGarrett D'Amore MDOC__D, 253698f87a4SGarrett D'Amore MDOC__O 25495c635efSGarrett D'Amore }; 25595c635efSGarrett D'Amore 25695c635efSGarrett D'Amore static const char * const secnames[SEC__MAX] = { 25795c635efSGarrett D'Amore NULL, 25895c635efSGarrett D'Amore "NAME", 25995c635efSGarrett D'Amore "LIBRARY", 26095c635efSGarrett D'Amore "SYNOPSIS", 26195c635efSGarrett D'Amore "DESCRIPTION", 262260e9a87SYuri Pankov "CONTEXT", 26395c635efSGarrett D'Amore "IMPLEMENTATION NOTES", 26495c635efSGarrett D'Amore "RETURN VALUES", 26595c635efSGarrett D'Amore "ENVIRONMENT", 26695c635efSGarrett D'Amore "FILES", 26795c635efSGarrett D'Amore "EXIT STATUS", 26895c635efSGarrett D'Amore "EXAMPLES", 26995c635efSGarrett D'Amore "DIAGNOSTICS", 27095c635efSGarrett D'Amore "COMPATIBILITY", 27195c635efSGarrett D'Amore "ERRORS", 27295c635efSGarrett D'Amore "SEE ALSO", 27395c635efSGarrett D'Amore "STANDARDS", 27495c635efSGarrett D'Amore "HISTORY", 27595c635efSGarrett D'Amore "AUTHORS", 27695c635efSGarrett D'Amore "CAVEATS", 27795c635efSGarrett D'Amore "BUGS", 27895c635efSGarrett D'Amore "SECURITY CONSIDERATIONS", 27995c635efSGarrett D'Amore NULL 28095c635efSGarrett D'Amore }; 28195c635efSGarrett D'Amore 282260e9a87SYuri Pankov 283260e9a87SYuri Pankov void 284371584c2SYuri Pankov mdoc_node_validate(struct roff_man *mdoc) 28595c635efSGarrett D'Amore { 286371584c2SYuri Pankov struct roff_node *n; 287371584c2SYuri Pankov v_post *p; 28895c635efSGarrett D'Amore 289371584c2SYuri Pankov n = mdoc->last; 290371584c2SYuri Pankov mdoc->last = mdoc->last->child; 291371584c2SYuri Pankov while (mdoc->last != NULL) { 292371584c2SYuri Pankov mdoc_node_validate(mdoc); 293371584c2SYuri Pankov if (mdoc->last == n) 294371584c2SYuri Pankov mdoc->last = mdoc->last->child; 295371584c2SYuri Pankov else 296371584c2SYuri Pankov mdoc->last = mdoc->last->next; 297371584c2SYuri Pankov } 298371584c2SYuri Pankov 299371584c2SYuri Pankov mdoc->last = n; 300371584c2SYuri Pankov mdoc->next = ROFF_NEXT_SIBLING; 30195c635efSGarrett D'Amore switch (n->type) { 302371584c2SYuri Pankov case ROFFT_TEXT: 303*a40ea1a7SYuri Pankov if (n->sec != SEC_SYNOPSIS || 304*a40ea1a7SYuri Pankov (n->parent->tok != MDOC_Cd && n->parent->tok != MDOC_Fd)) 305260e9a87SYuri Pankov check_text(mdoc, n->line, n->pos, n->string); 30695c635efSGarrett D'Amore break; 307371584c2SYuri Pankov case ROFFT_EQN: 308371584c2SYuri Pankov case ROFFT_TBL: 30995c635efSGarrett D'Amore break; 310371584c2SYuri Pankov case ROFFT_ROOT: 311260e9a87SYuri Pankov post_root(mdoc); 31295c635efSGarrett D'Amore break; 31395c635efSGarrett D'Amore default: 314371584c2SYuri Pankov check_args(mdoc, mdoc->last); 31595c635efSGarrett D'Amore 316260e9a87SYuri Pankov /* 317260e9a87SYuri Pankov * Closing delimiters are not special at the 318260e9a87SYuri Pankov * beginning of a block, opening delimiters 319260e9a87SYuri Pankov * are not special at the end. 320260e9a87SYuri Pankov */ 32195c635efSGarrett D'Amore 322260e9a87SYuri Pankov if (n->child != NULL) 323*a40ea1a7SYuri Pankov n->child->flags &= ~NODE_DELIMC; 324260e9a87SYuri Pankov if (n->last != NULL) 325*a40ea1a7SYuri Pankov n->last->flags &= ~NODE_DELIMO; 32695c635efSGarrett D'Amore 327260e9a87SYuri Pankov /* Call the macro's postprocessor. */ 32895c635efSGarrett D'Amore 329371584c2SYuri Pankov p = mdoc_valids + n->tok; 330260e9a87SYuri Pankov if (*p) 331260e9a87SYuri Pankov (*p)(mdoc); 332371584c2SYuri Pankov if (mdoc->last == n) 333371584c2SYuri Pankov mdoc_state(mdoc, n); 334260e9a87SYuri Pankov break; 335260e9a87SYuri Pankov } 33695c635efSGarrett D'Amore } 33795c635efSGarrett D'Amore 33895c635efSGarrett D'Amore static void 339371584c2SYuri Pankov check_args(struct roff_man *mdoc, struct roff_node *n) 34095c635efSGarrett D'Amore { 34195c635efSGarrett D'Amore int i; 34295c635efSGarrett D'Amore 34395c635efSGarrett D'Amore if (NULL == n->args) 34495c635efSGarrett D'Amore return; 34595c635efSGarrett D'Amore 34695c635efSGarrett D'Amore assert(n->args->argc); 34795c635efSGarrett D'Amore for (i = 0; i < (int)n->args->argc; i++) 348698f87a4SGarrett D'Amore check_argv(mdoc, n, &n->args->argv[i]); 34995c635efSGarrett D'Amore } 35095c635efSGarrett D'Amore 35195c635efSGarrett D'Amore static void 352371584c2SYuri Pankov check_argv(struct roff_man *mdoc, struct roff_node *n, struct mdoc_argv *v) 35395c635efSGarrett D'Amore { 35495c635efSGarrett D'Amore int i; 35595c635efSGarrett D'Amore 35695c635efSGarrett D'Amore for (i = 0; i < (int)v->sz; i++) 357698f87a4SGarrett D'Amore check_text(mdoc, v->line, v->pos, v->value[i]); 35895c635efSGarrett D'Amore } 35995c635efSGarrett D'Amore 36095c635efSGarrett D'Amore static void 361371584c2SYuri Pankov check_text(struct roff_man *mdoc, int ln, int pos, char *p) 36295c635efSGarrett D'Amore { 36395c635efSGarrett D'Amore char *cp; 36495c635efSGarrett D'Amore 365698f87a4SGarrett D'Amore if (MDOC_LITERAL & mdoc->flags) 36695c635efSGarrett D'Amore return; 36795c635efSGarrett D'Amore 36895c635efSGarrett D'Amore for (cp = p; NULL != (p = strchr(p, '\t')); p++) 369260e9a87SYuri Pankov mandoc_msg(MANDOCERR_FI_TAB, mdoc->parse, 370260e9a87SYuri Pankov ln, pos + (int)(p - cp), NULL); 37195c635efSGarrett D'Amore } 37295c635efSGarrett D'Amore 373260e9a87SYuri Pankov static void 374371584c2SYuri Pankov post_bl_norm(POST_ARGS) 37595c635efSGarrett D'Amore { 376371584c2SYuri Pankov struct roff_node *n; 377260e9a87SYuri Pankov struct mdoc_argv *argv, *wa; 378260e9a87SYuri Pankov int i; 379260e9a87SYuri Pankov enum mdocargt mdoclt; 38095c635efSGarrett D'Amore enum mdoc_list lt; 38195c635efSGarrett D'Amore 382371584c2SYuri Pankov n = mdoc->last->parent; 383371584c2SYuri Pankov n->norm->Bl.type = LIST__NONE; 38495c635efSGarrett D'Amore 385260e9a87SYuri Pankov /* 38695c635efSGarrett D'Amore * First figure out which kind of list to use: bind ourselves to 38795c635efSGarrett D'Amore * the first mentioned list type and warn about any remaining 38895c635efSGarrett D'Amore * ones. If we find no list type, we default to LIST_item. 38995c635efSGarrett D'Amore */ 39095c635efSGarrett D'Amore 391260e9a87SYuri Pankov wa = (n->args == NULL) ? NULL : n->args->argv; 392260e9a87SYuri Pankov mdoclt = MDOC_ARG_MAX; 39395c635efSGarrett D'Amore for (i = 0; n->args && i < (int)n->args->argc; i++) { 394260e9a87SYuri Pankov argv = n->args->argv + i; 39595c635efSGarrett D'Amore lt = LIST__NONE; 396260e9a87SYuri Pankov switch (argv->arg) { 39795c635efSGarrett D'Amore /* Set list types. */ 398260e9a87SYuri Pankov case MDOC_Bullet: 39995c635efSGarrett D'Amore lt = LIST_bullet; 40095c635efSGarrett D'Amore break; 401260e9a87SYuri Pankov case MDOC_Dash: 40295c635efSGarrett D'Amore lt = LIST_dash; 40395c635efSGarrett D'Amore break; 404260e9a87SYuri Pankov case MDOC_Enum: 40595c635efSGarrett D'Amore lt = LIST_enum; 40695c635efSGarrett D'Amore break; 407260e9a87SYuri Pankov case MDOC_Hyphen: 40895c635efSGarrett D'Amore lt = LIST_hyphen; 40995c635efSGarrett D'Amore break; 410260e9a87SYuri Pankov case MDOC_Item: 41195c635efSGarrett D'Amore lt = LIST_item; 41295c635efSGarrett D'Amore break; 413260e9a87SYuri Pankov case MDOC_Tag: 41495c635efSGarrett D'Amore lt = LIST_tag; 41595c635efSGarrett D'Amore break; 416260e9a87SYuri Pankov case MDOC_Diag: 41795c635efSGarrett D'Amore lt = LIST_diag; 41895c635efSGarrett D'Amore break; 419260e9a87SYuri Pankov case MDOC_Hang: 42095c635efSGarrett D'Amore lt = LIST_hang; 42195c635efSGarrett D'Amore break; 422260e9a87SYuri Pankov case MDOC_Ohang: 42395c635efSGarrett D'Amore lt = LIST_ohang; 42495c635efSGarrett D'Amore break; 425260e9a87SYuri Pankov case MDOC_Inset: 42695c635efSGarrett D'Amore lt = LIST_inset; 42795c635efSGarrett D'Amore break; 428260e9a87SYuri Pankov case MDOC_Column: 42995c635efSGarrett D'Amore lt = LIST_column; 43095c635efSGarrett D'Amore break; 43195c635efSGarrett D'Amore /* Set list arguments. */ 432260e9a87SYuri Pankov case MDOC_Compact: 433260e9a87SYuri Pankov if (n->norm->Bl.comp) 434260e9a87SYuri Pankov mandoc_msg(MANDOCERR_ARG_REP, 435260e9a87SYuri Pankov mdoc->parse, argv->line, 436260e9a87SYuri Pankov argv->pos, "Bl -compact"); 437260e9a87SYuri Pankov n->norm->Bl.comp = 1; 43895c635efSGarrett D'Amore break; 439260e9a87SYuri Pankov case MDOC_Width: 440260e9a87SYuri Pankov wa = argv; 441260e9a87SYuri Pankov if (0 == argv->sz) { 442260e9a87SYuri Pankov mandoc_msg(MANDOCERR_ARG_EMPTY, 443260e9a87SYuri Pankov mdoc->parse, argv->line, 444260e9a87SYuri Pankov argv->pos, "Bl -width"); 445260e9a87SYuri Pankov n->norm->Bl.width = "0n"; 44695c635efSGarrett D'Amore break; 44795c635efSGarrett D'Amore } 448260e9a87SYuri Pankov if (NULL != n->norm->Bl.width) 449260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_ARG_REP, 450260e9a87SYuri Pankov mdoc->parse, argv->line, 451260e9a87SYuri Pankov argv->pos, "Bl -width %s", 452260e9a87SYuri Pankov argv->value[0]); 453260e9a87SYuri Pankov rewrite_macro2len(argv->value); 454260e9a87SYuri Pankov n->norm->Bl.width = argv->value[0]; 45595c635efSGarrett D'Amore break; 456260e9a87SYuri Pankov case MDOC_Offset: 457260e9a87SYuri Pankov if (0 == argv->sz) { 458260e9a87SYuri Pankov mandoc_msg(MANDOCERR_ARG_EMPTY, 459260e9a87SYuri Pankov mdoc->parse, argv->line, 460260e9a87SYuri Pankov argv->pos, "Bl -offset"); 46195c635efSGarrett D'Amore break; 46295c635efSGarrett D'Amore } 463260e9a87SYuri Pankov if (NULL != n->norm->Bl.offs) 464260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_ARG_REP, 465260e9a87SYuri Pankov mdoc->parse, argv->line, 466260e9a87SYuri Pankov argv->pos, "Bl -offset %s", 467260e9a87SYuri Pankov argv->value[0]); 468260e9a87SYuri Pankov rewrite_macro2len(argv->value); 469260e9a87SYuri Pankov n->norm->Bl.offs = argv->value[0]; 47095c635efSGarrett D'Amore break; 47195c635efSGarrett D'Amore default: 47295c635efSGarrett D'Amore continue; 47395c635efSGarrett D'Amore } 474260e9a87SYuri Pankov if (LIST__NONE == lt) 475260e9a87SYuri Pankov continue; 476260e9a87SYuri Pankov mdoclt = argv->arg; 47795c635efSGarrett D'Amore 47895c635efSGarrett D'Amore /* Check: multiple list types. */ 47995c635efSGarrett D'Amore 480260e9a87SYuri Pankov if (LIST__NONE != n->norm->Bl.type) { 481260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_BL_REP, 482260e9a87SYuri Pankov mdoc->parse, n->line, n->pos, 483260e9a87SYuri Pankov "Bl -%s", mdoc_argnames[argv->arg]); 484260e9a87SYuri Pankov continue; 48595c635efSGarrett D'Amore } 48695c635efSGarrett D'Amore 48795c635efSGarrett D'Amore /* The list type should come first. */ 48895c635efSGarrett D'Amore 489260e9a87SYuri Pankov if (n->norm->Bl.width || 490260e9a87SYuri Pankov n->norm->Bl.offs || 491260e9a87SYuri Pankov n->norm->Bl.comp) 492260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_BL_LATETYPE, 493260e9a87SYuri Pankov mdoc->parse, n->line, n->pos, "Bl -%s", 494260e9a87SYuri Pankov mdoc_argnames[n->args->argv[0].arg]); 495260e9a87SYuri Pankov 496260e9a87SYuri Pankov n->norm->Bl.type = lt; 497260e9a87SYuri Pankov if (LIST_column == lt) { 498260e9a87SYuri Pankov n->norm->Bl.ncols = argv->sz; 499260e9a87SYuri Pankov n->norm->Bl.cols = (void *)argv->value; 500260e9a87SYuri Pankov } 50195c635efSGarrett D'Amore } 50295c635efSGarrett D'Amore 50395c635efSGarrett D'Amore /* Allow lists to default to LIST_item. */ 50495c635efSGarrett D'Amore 50595c635efSGarrett D'Amore if (LIST__NONE == n->norm->Bl.type) { 506260e9a87SYuri Pankov mandoc_msg(MANDOCERR_BL_NOTYPE, mdoc->parse, 507260e9a87SYuri Pankov n->line, n->pos, "Bl"); 50895c635efSGarrett D'Amore n->norm->Bl.type = LIST_item; 509*a40ea1a7SYuri Pankov mdoclt = MDOC_Item; 51095c635efSGarrett D'Amore } 51195c635efSGarrett D'Amore 512260e9a87SYuri Pankov /* 51395c635efSGarrett D'Amore * Validate the width field. Some list types don't need width 51495c635efSGarrett D'Amore * types and should be warned about them. Others should have it 515698f87a4SGarrett D'Amore * and must also be warned. Yet others have a default and need 516698f87a4SGarrett D'Amore * no warning. 51795c635efSGarrett D'Amore */ 51895c635efSGarrett D'Amore 51995c635efSGarrett D'Amore switch (n->norm->Bl.type) { 520260e9a87SYuri Pankov case LIST_tag: 521698f87a4SGarrett D'Amore if (NULL == n->norm->Bl.width) 522260e9a87SYuri Pankov mandoc_msg(MANDOCERR_BL_NOWIDTH, mdoc->parse, 523260e9a87SYuri Pankov n->line, n->pos, "Bl -tag"); 52495c635efSGarrett D'Amore break; 525260e9a87SYuri Pankov case LIST_column: 526260e9a87SYuri Pankov case LIST_diag: 527260e9a87SYuri Pankov case LIST_ohang: 528260e9a87SYuri Pankov case LIST_inset: 529260e9a87SYuri Pankov case LIST_item: 53095c635efSGarrett D'Amore if (n->norm->Bl.width) 531260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_BL_SKIPW, mdoc->parse, 532260e9a87SYuri Pankov wa->line, wa->pos, "Bl -%s", 533260e9a87SYuri Pankov mdoc_argnames[mdoclt]); 53495c635efSGarrett D'Amore break; 535260e9a87SYuri Pankov case LIST_bullet: 536260e9a87SYuri Pankov case LIST_dash: 537260e9a87SYuri Pankov case LIST_hyphen: 538698f87a4SGarrett D'Amore if (NULL == n->norm->Bl.width) 539698f87a4SGarrett D'Amore n->norm->Bl.width = "2n"; 540698f87a4SGarrett D'Amore break; 541260e9a87SYuri Pankov case LIST_enum: 542698f87a4SGarrett D'Amore if (NULL == n->norm->Bl.width) 543698f87a4SGarrett D'Amore n->norm->Bl.width = "3n"; 544698f87a4SGarrett D'Amore break; 54595c635efSGarrett D'Amore default: 54695c635efSGarrett D'Amore break; 54795c635efSGarrett D'Amore } 54895c635efSGarrett D'Amore } 54995c635efSGarrett D'Amore 550260e9a87SYuri Pankov static void 551371584c2SYuri Pankov post_bd(POST_ARGS) 55295c635efSGarrett D'Amore { 553371584c2SYuri Pankov struct roff_node *n; 554260e9a87SYuri Pankov struct mdoc_argv *argv; 555260e9a87SYuri Pankov int i; 556260e9a87SYuri Pankov enum mdoc_disp dt; 55795c635efSGarrett D'Amore 558371584c2SYuri Pankov n = mdoc->last; 55995c635efSGarrett D'Amore for (i = 0; n->args && i < (int)n->args->argc; i++) { 560260e9a87SYuri Pankov argv = n->args->argv + i; 56195c635efSGarrett D'Amore dt = DISP__NONE; 56295c635efSGarrett D'Amore 563260e9a87SYuri Pankov switch (argv->arg) { 564260e9a87SYuri Pankov case MDOC_Centred: 565260e9a87SYuri Pankov dt = DISP_centered; 56695c635efSGarrett D'Amore break; 567260e9a87SYuri Pankov case MDOC_Ragged: 56895c635efSGarrett D'Amore dt = DISP_ragged; 56995c635efSGarrett D'Amore break; 570260e9a87SYuri Pankov case MDOC_Unfilled: 57195c635efSGarrett D'Amore dt = DISP_unfilled; 57295c635efSGarrett D'Amore break; 573260e9a87SYuri Pankov case MDOC_Filled: 57495c635efSGarrett D'Amore dt = DISP_filled; 57595c635efSGarrett D'Amore break; 576260e9a87SYuri Pankov case MDOC_Literal: 57795c635efSGarrett D'Amore dt = DISP_literal; 57895c635efSGarrett D'Amore break; 579260e9a87SYuri Pankov case MDOC_File: 580260e9a87SYuri Pankov mandoc_msg(MANDOCERR_BD_FILE, mdoc->parse, 581260e9a87SYuri Pankov n->line, n->pos, NULL); 582260e9a87SYuri Pankov break; 583260e9a87SYuri Pankov case MDOC_Offset: 584260e9a87SYuri Pankov if (0 == argv->sz) { 585260e9a87SYuri Pankov mandoc_msg(MANDOCERR_ARG_EMPTY, 586260e9a87SYuri Pankov mdoc->parse, argv->line, 587260e9a87SYuri Pankov argv->pos, "Bd -offset"); 58895c635efSGarrett D'Amore break; 58995c635efSGarrett D'Amore } 590260e9a87SYuri Pankov if (NULL != n->norm->Bd.offs) 591260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_ARG_REP, 592260e9a87SYuri Pankov mdoc->parse, argv->line, 593260e9a87SYuri Pankov argv->pos, "Bd -offset %s", 594260e9a87SYuri Pankov argv->value[0]); 595260e9a87SYuri Pankov rewrite_macro2len(argv->value); 596260e9a87SYuri Pankov n->norm->Bd.offs = argv->value[0]; 59795c635efSGarrett D'Amore break; 598260e9a87SYuri Pankov case MDOC_Compact: 599260e9a87SYuri Pankov if (n->norm->Bd.comp) 600260e9a87SYuri Pankov mandoc_msg(MANDOCERR_ARG_REP, 601260e9a87SYuri Pankov mdoc->parse, argv->line, 602260e9a87SYuri Pankov argv->pos, "Bd -compact"); 603260e9a87SYuri Pankov n->norm->Bd.comp = 1; 60495c635efSGarrett D'Amore break; 60595c635efSGarrett D'Amore default: 60695c635efSGarrett D'Amore abort(); 60795c635efSGarrett D'Amore } 608260e9a87SYuri Pankov if (DISP__NONE == dt) 609260e9a87SYuri Pankov continue; 61095c635efSGarrett D'Amore 611260e9a87SYuri Pankov if (DISP__NONE == n->norm->Bd.type) 61295c635efSGarrett D'Amore n->norm->Bd.type = dt; 613260e9a87SYuri Pankov else 614260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_BD_REP, 615260e9a87SYuri Pankov mdoc->parse, n->line, n->pos, 616260e9a87SYuri Pankov "Bd -%s", mdoc_argnames[argv->arg]); 61795c635efSGarrett D'Amore } 61895c635efSGarrett D'Amore 61995c635efSGarrett D'Amore if (DISP__NONE == n->norm->Bd.type) { 620260e9a87SYuri Pankov mandoc_msg(MANDOCERR_BD_NOTYPE, mdoc->parse, 621260e9a87SYuri Pankov n->line, n->pos, "Bd"); 62295c635efSGarrett D'Amore n->norm->Bd.type = DISP_ragged; 62395c635efSGarrett D'Amore } 62495c635efSGarrett D'Amore } 62595c635efSGarrett D'Amore 626*a40ea1a7SYuri Pankov /* 627*a40ea1a7SYuri Pankov * Stand-alone line macros. 628*a40ea1a7SYuri Pankov */ 629*a40ea1a7SYuri Pankov 630260e9a87SYuri Pankov static void 631371584c2SYuri Pankov post_an_norm(POST_ARGS) 63295c635efSGarrett D'Amore { 633371584c2SYuri Pankov struct roff_node *n; 634260e9a87SYuri Pankov struct mdoc_argv *argv; 635260e9a87SYuri Pankov size_t i; 63695c635efSGarrett D'Amore 637371584c2SYuri Pankov n = mdoc->last; 638260e9a87SYuri Pankov if (n->args == NULL) 639260e9a87SYuri Pankov return; 64095c635efSGarrett D'Amore 641260e9a87SYuri Pankov for (i = 1; i < n->args->argc; i++) { 642260e9a87SYuri Pankov argv = n->args->argv + i; 643260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_AN_REP, 644260e9a87SYuri Pankov mdoc->parse, argv->line, argv->pos, 645260e9a87SYuri Pankov "An -%s", mdoc_argnames[argv->arg]); 646260e9a87SYuri Pankov } 647260e9a87SYuri Pankov 648260e9a87SYuri Pankov argv = n->args->argv; 649260e9a87SYuri Pankov if (argv->arg == MDOC_Split) 65095c635efSGarrett D'Amore n->norm->An.auth = AUTH_split; 651260e9a87SYuri Pankov else if (argv->arg == MDOC_Nosplit) 65295c635efSGarrett D'Amore n->norm->An.auth = AUTH_nosplit; 65395c635efSGarrett D'Amore else 65495c635efSGarrett D'Amore abort(); 65595c635efSGarrett D'Amore } 65695c635efSGarrett D'Amore 657*a40ea1a7SYuri Pankov static void 658*a40ea1a7SYuri Pankov post_eoln(POST_ARGS) 659*a40ea1a7SYuri Pankov { 660*a40ea1a7SYuri Pankov struct roff_node *n; 661*a40ea1a7SYuri Pankov 662*a40ea1a7SYuri Pankov n = mdoc->last; 663*a40ea1a7SYuri Pankov if (n->child != NULL) 664*a40ea1a7SYuri Pankov mandoc_vmsg(MANDOCERR_ARG_SKIP, mdoc->parse, 665*a40ea1a7SYuri Pankov n->line, n->pos, "%s %s", 666*a40ea1a7SYuri Pankov mdoc_macronames[n->tok], n->child->string); 667*a40ea1a7SYuri Pankov 668*a40ea1a7SYuri Pankov while (n->child != NULL) 669*a40ea1a7SYuri Pankov roff_node_delete(mdoc, n->child); 670*a40ea1a7SYuri Pankov 671*a40ea1a7SYuri Pankov roff_word_alloc(mdoc, n->line, n->pos, n->tok == MDOC_Bt ? 672*a40ea1a7SYuri Pankov "is currently in beta test." : "currently under development."); 673*a40ea1a7SYuri Pankov mdoc->last->flags |= NODE_EOS | NODE_NOSRC; 674*a40ea1a7SYuri Pankov mdoc->last = n; 675*a40ea1a7SYuri Pankov } 676*a40ea1a7SYuri Pankov 677*a40ea1a7SYuri Pankov static int 678*a40ea1a7SYuri Pankov build_list(struct roff_man *mdoc, int tok) 679*a40ea1a7SYuri Pankov { 680*a40ea1a7SYuri Pankov struct roff_node *n; 681*a40ea1a7SYuri Pankov int ic; 682*a40ea1a7SYuri Pankov 683*a40ea1a7SYuri Pankov n = mdoc->last->next; 684*a40ea1a7SYuri Pankov for (ic = 1;; ic++) { 685*a40ea1a7SYuri Pankov roff_elem_alloc(mdoc, n->line, n->pos, tok); 686*a40ea1a7SYuri Pankov mdoc->last->flags |= NODE_NOSRC; 687*a40ea1a7SYuri Pankov mdoc_node_relink(mdoc, n); 688*a40ea1a7SYuri Pankov n = mdoc->last = mdoc->last->parent; 689*a40ea1a7SYuri Pankov mdoc->next = ROFF_NEXT_SIBLING; 690*a40ea1a7SYuri Pankov if (n->next == NULL) 691*a40ea1a7SYuri Pankov return ic; 692*a40ea1a7SYuri Pankov if (ic > 1 || n->next->next != NULL) { 693*a40ea1a7SYuri Pankov roff_word_alloc(mdoc, n->line, n->pos, ","); 694*a40ea1a7SYuri Pankov mdoc->last->flags |= NODE_DELIMC | NODE_NOSRC; 695*a40ea1a7SYuri Pankov } 696*a40ea1a7SYuri Pankov n = mdoc->last->next; 697*a40ea1a7SYuri Pankov if (n->next == NULL) { 698*a40ea1a7SYuri Pankov roff_word_alloc(mdoc, n->line, n->pos, "and"); 699*a40ea1a7SYuri Pankov mdoc->last->flags |= NODE_NOSRC; 700*a40ea1a7SYuri Pankov } 701*a40ea1a7SYuri Pankov } 702*a40ea1a7SYuri Pankov } 703*a40ea1a7SYuri Pankov 704*a40ea1a7SYuri Pankov static void 705*a40ea1a7SYuri Pankov post_ex(POST_ARGS) 706*a40ea1a7SYuri Pankov { 707*a40ea1a7SYuri Pankov struct roff_node *n; 708*a40ea1a7SYuri Pankov int ic; 709*a40ea1a7SYuri Pankov 710*a40ea1a7SYuri Pankov post_std(mdoc); 711*a40ea1a7SYuri Pankov 712*a40ea1a7SYuri Pankov n = mdoc->last; 713*a40ea1a7SYuri Pankov mdoc->next = ROFF_NEXT_CHILD; 714*a40ea1a7SYuri Pankov roff_word_alloc(mdoc, n->line, n->pos, "The"); 715*a40ea1a7SYuri Pankov mdoc->last->flags |= NODE_NOSRC; 716*a40ea1a7SYuri Pankov 717*a40ea1a7SYuri Pankov if (mdoc->last->next != NULL) 718*a40ea1a7SYuri Pankov ic = build_list(mdoc, MDOC_Nm); 719*a40ea1a7SYuri Pankov else if (mdoc->meta.name != NULL) { 720*a40ea1a7SYuri Pankov roff_elem_alloc(mdoc, n->line, n->pos, MDOC_Nm); 721*a40ea1a7SYuri Pankov mdoc->last->flags |= NODE_NOSRC; 722*a40ea1a7SYuri Pankov roff_word_alloc(mdoc, n->line, n->pos, mdoc->meta.name); 723*a40ea1a7SYuri Pankov mdoc->last->flags |= NODE_NOSRC; 724*a40ea1a7SYuri Pankov mdoc->last = mdoc->last->parent; 725*a40ea1a7SYuri Pankov mdoc->next = ROFF_NEXT_SIBLING; 726*a40ea1a7SYuri Pankov ic = 1; 727*a40ea1a7SYuri Pankov } else { 728*a40ea1a7SYuri Pankov mandoc_msg(MANDOCERR_EX_NONAME, mdoc->parse, 729*a40ea1a7SYuri Pankov n->line, n->pos, "Ex"); 730*a40ea1a7SYuri Pankov ic = 0; 731*a40ea1a7SYuri Pankov } 732*a40ea1a7SYuri Pankov 733*a40ea1a7SYuri Pankov roff_word_alloc(mdoc, n->line, n->pos, 734*a40ea1a7SYuri Pankov ic > 1 ? "utilities exit\\~0" : "utility exits\\~0"); 735*a40ea1a7SYuri Pankov mdoc->last->flags |= NODE_NOSRC; 736*a40ea1a7SYuri Pankov roff_word_alloc(mdoc, n->line, n->pos, 737*a40ea1a7SYuri Pankov "on success, and\\~>0 if an error occurs."); 738*a40ea1a7SYuri Pankov mdoc->last->flags |= NODE_EOS | NODE_NOSRC; 739*a40ea1a7SYuri Pankov mdoc->last = n; 740*a40ea1a7SYuri Pankov } 741*a40ea1a7SYuri Pankov 742*a40ea1a7SYuri Pankov static void 743*a40ea1a7SYuri Pankov post_lb(POST_ARGS) 744*a40ea1a7SYuri Pankov { 745*a40ea1a7SYuri Pankov struct roff_node *n; 746*a40ea1a7SYuri Pankov const char *p; 747*a40ea1a7SYuri Pankov 748*a40ea1a7SYuri Pankov n = mdoc->last; 749*a40ea1a7SYuri Pankov assert(n->child->type == ROFFT_TEXT); 750*a40ea1a7SYuri Pankov mdoc->next = ROFF_NEXT_CHILD; 751*a40ea1a7SYuri Pankov 752*a40ea1a7SYuri Pankov if ((p = mdoc_a2lib(n->child->string)) != NULL) { 753*a40ea1a7SYuri Pankov n->child->flags |= NODE_NOPRT; 754*a40ea1a7SYuri Pankov roff_word_alloc(mdoc, n->line, n->pos, p); 755*a40ea1a7SYuri Pankov mdoc->last->flags = NODE_NOSRC; 756*a40ea1a7SYuri Pankov mdoc->last = n; 757*a40ea1a7SYuri Pankov return; 758*a40ea1a7SYuri Pankov } 759*a40ea1a7SYuri Pankov 760*a40ea1a7SYuri Pankov roff_word_alloc(mdoc, n->line, n->pos, "library"); 761*a40ea1a7SYuri Pankov mdoc->last->flags = NODE_NOSRC; 762*a40ea1a7SYuri Pankov roff_word_alloc(mdoc, n->line, n->pos, "\\(Lq"); 763*a40ea1a7SYuri Pankov mdoc->last->flags = NODE_DELIMO | NODE_NOSRC; 764*a40ea1a7SYuri Pankov mdoc->last = mdoc->last->next; 765*a40ea1a7SYuri Pankov roff_word_alloc(mdoc, n->line, n->pos, "\\(Rq"); 766*a40ea1a7SYuri Pankov mdoc->last->flags = NODE_DELIMC | NODE_NOSRC; 767*a40ea1a7SYuri Pankov mdoc->last = n; 768*a40ea1a7SYuri Pankov } 769*a40ea1a7SYuri Pankov 770*a40ea1a7SYuri Pankov static void 771*a40ea1a7SYuri Pankov post_rv(POST_ARGS) 772*a40ea1a7SYuri Pankov { 773*a40ea1a7SYuri Pankov struct roff_node *n; 774*a40ea1a7SYuri Pankov int ic; 775*a40ea1a7SYuri Pankov 776*a40ea1a7SYuri Pankov post_std(mdoc); 777*a40ea1a7SYuri Pankov 778*a40ea1a7SYuri Pankov n = mdoc->last; 779*a40ea1a7SYuri Pankov mdoc->next = ROFF_NEXT_CHILD; 780*a40ea1a7SYuri Pankov if (n->child != NULL) { 781*a40ea1a7SYuri Pankov roff_word_alloc(mdoc, n->line, n->pos, "The"); 782*a40ea1a7SYuri Pankov mdoc->last->flags |= NODE_NOSRC; 783*a40ea1a7SYuri Pankov ic = build_list(mdoc, MDOC_Fn); 784*a40ea1a7SYuri Pankov roff_word_alloc(mdoc, n->line, n->pos, 785*a40ea1a7SYuri Pankov ic > 1 ? "functions return" : "function returns"); 786*a40ea1a7SYuri Pankov mdoc->last->flags |= NODE_NOSRC; 787*a40ea1a7SYuri Pankov roff_word_alloc(mdoc, n->line, n->pos, 788*a40ea1a7SYuri Pankov "the value\\~0 if successful;"); 789*a40ea1a7SYuri Pankov } else 790*a40ea1a7SYuri Pankov roff_word_alloc(mdoc, n->line, n->pos, "Upon successful " 791*a40ea1a7SYuri Pankov "completion, the value\\~0 is returned;"); 792*a40ea1a7SYuri Pankov mdoc->last->flags |= NODE_NOSRC; 793*a40ea1a7SYuri Pankov 794*a40ea1a7SYuri Pankov roff_word_alloc(mdoc, n->line, n->pos, "otherwise " 795*a40ea1a7SYuri Pankov "the value\\~\\-1 is returned and the global variable"); 796*a40ea1a7SYuri Pankov mdoc->last->flags |= NODE_NOSRC; 797*a40ea1a7SYuri Pankov roff_elem_alloc(mdoc, n->line, n->pos, MDOC_Va); 798*a40ea1a7SYuri Pankov mdoc->last->flags |= NODE_NOSRC; 799*a40ea1a7SYuri Pankov roff_word_alloc(mdoc, n->line, n->pos, "errno"); 800*a40ea1a7SYuri Pankov mdoc->last->flags |= NODE_NOSRC; 801*a40ea1a7SYuri Pankov mdoc->last = mdoc->last->parent; 802*a40ea1a7SYuri Pankov mdoc->next = ROFF_NEXT_SIBLING; 803*a40ea1a7SYuri Pankov roff_word_alloc(mdoc, n->line, n->pos, 804*a40ea1a7SYuri Pankov "is set to indicate the error."); 805*a40ea1a7SYuri Pankov mdoc->last->flags |= NODE_EOS | NODE_NOSRC; 806*a40ea1a7SYuri Pankov mdoc->last = n; 807*a40ea1a7SYuri Pankov } 808*a40ea1a7SYuri Pankov 809260e9a87SYuri Pankov static void 810371584c2SYuri Pankov post_std(POST_ARGS) 81195c635efSGarrett D'Amore { 812371584c2SYuri Pankov struct roff_node *n; 81395c635efSGarrett D'Amore 814371584c2SYuri Pankov n = mdoc->last; 815371584c2SYuri Pankov if (n->args && n->args->argc == 1) 816371584c2SYuri Pankov if (n->args->argv[0].arg == MDOC_Std) 817260e9a87SYuri Pankov return; 81895c635efSGarrett D'Amore 819260e9a87SYuri Pankov mandoc_msg(MANDOCERR_ARG_STD, mdoc->parse, 820260e9a87SYuri Pankov n->line, n->pos, mdoc_macronames[n->tok]); 82195c635efSGarrett D'Amore } 82295c635efSGarrett D'Amore 823*a40ea1a7SYuri Pankov static void 824*a40ea1a7SYuri Pankov post_st(POST_ARGS) 825*a40ea1a7SYuri Pankov { 826*a40ea1a7SYuri Pankov struct roff_node *n, *nch; 827*a40ea1a7SYuri Pankov const char *p; 828*a40ea1a7SYuri Pankov 829*a40ea1a7SYuri Pankov n = mdoc->last; 830*a40ea1a7SYuri Pankov nch = n->child; 831*a40ea1a7SYuri Pankov assert(nch->type == ROFFT_TEXT); 832*a40ea1a7SYuri Pankov 833*a40ea1a7SYuri Pankov if ((p = mdoc_a2st(nch->string)) == NULL) { 834*a40ea1a7SYuri Pankov mandoc_vmsg(MANDOCERR_ST_BAD, mdoc->parse, 835*a40ea1a7SYuri Pankov nch->line, nch->pos, "St %s", nch->string); 836*a40ea1a7SYuri Pankov roff_node_delete(mdoc, n); 837*a40ea1a7SYuri Pankov return; 838*a40ea1a7SYuri Pankov } 839*a40ea1a7SYuri Pankov 840*a40ea1a7SYuri Pankov nch->flags |= NODE_NOPRT; 841*a40ea1a7SYuri Pankov mdoc->next = ROFF_NEXT_CHILD; 842*a40ea1a7SYuri Pankov roff_word_alloc(mdoc, nch->line, nch->pos, p); 843*a40ea1a7SYuri Pankov mdoc->last->flags |= NODE_NOSRC; 844*a40ea1a7SYuri Pankov mdoc->last= n; 845*a40ea1a7SYuri Pankov } 846*a40ea1a7SYuri Pankov 847260e9a87SYuri Pankov static void 848371584c2SYuri Pankov post_obsolete(POST_ARGS) 84995c635efSGarrett D'Amore { 850371584c2SYuri Pankov struct roff_node *n; 85195c635efSGarrett D'Amore 852371584c2SYuri Pankov n = mdoc->last; 853371584c2SYuri Pankov if (n->type == ROFFT_ELEM || n->type == ROFFT_BLOCK) 854260e9a87SYuri Pankov mandoc_msg(MANDOCERR_MACRO_OBS, mdoc->parse, 855260e9a87SYuri Pankov n->line, n->pos, mdoc_macronames[n->tok]); 856260e9a87SYuri Pankov } 85795c635efSGarrett D'Amore 858*a40ea1a7SYuri Pankov /* 859*a40ea1a7SYuri Pankov * Block macros. 860*a40ea1a7SYuri Pankov */ 861*a40ea1a7SYuri Pankov 862260e9a87SYuri Pankov static void 86395c635efSGarrett D'Amore post_bf(POST_ARGS) 86495c635efSGarrett D'Amore { 865371584c2SYuri Pankov struct roff_node *np, *nch; 86695c635efSGarrett D'Amore 86795c635efSGarrett D'Amore /* 86895c635efSGarrett D'Amore * Unlike other data pointers, these are "housed" by the HEAD 86995c635efSGarrett D'Amore * element, which contains the goods. 87095c635efSGarrett D'Amore */ 87195c635efSGarrett D'Amore 87295c635efSGarrett D'Amore np = mdoc->last; 873371584c2SYuri Pankov if (np->type != ROFFT_HEAD) 874260e9a87SYuri Pankov return; 875260e9a87SYuri Pankov 876371584c2SYuri Pankov assert(np->parent->type == ROFFT_BLOCK); 877371584c2SYuri Pankov assert(np->parent->tok == MDOC_Bf); 87895c635efSGarrett D'Amore 879260e9a87SYuri Pankov /* Check the number of arguments. */ 88095c635efSGarrett D'Amore 881260e9a87SYuri Pankov nch = np->child; 882371584c2SYuri Pankov if (np->parent->args == NULL) { 883371584c2SYuri Pankov if (nch == NULL) { 884260e9a87SYuri Pankov mandoc_msg(MANDOCERR_BF_NOFONT, mdoc->parse, 885260e9a87SYuri Pankov np->line, np->pos, "Bf"); 886260e9a87SYuri Pankov return; 887260e9a87SYuri Pankov } 888260e9a87SYuri Pankov nch = nch->next; 88995c635efSGarrett D'Amore } 890371584c2SYuri Pankov if (nch != NULL) 891260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse, 892260e9a87SYuri Pankov nch->line, nch->pos, "Bf ... %s", nch->string); 89395c635efSGarrett D'Amore 89495c635efSGarrett D'Amore /* Extract argument into data. */ 895260e9a87SYuri Pankov 896371584c2SYuri Pankov if (np->parent->args != NULL) { 897371584c2SYuri Pankov switch (np->parent->args->argv[0].arg) { 898371584c2SYuri Pankov case MDOC_Emphasis: 89995c635efSGarrett D'Amore np->norm->Bf.font = FONT_Em; 900371584c2SYuri Pankov break; 901371584c2SYuri Pankov case MDOC_Literal: 90295c635efSGarrett D'Amore np->norm->Bf.font = FONT_Li; 903371584c2SYuri Pankov break; 904371584c2SYuri Pankov case MDOC_Symbolic: 90595c635efSGarrett D'Amore np->norm->Bf.font = FONT_Sy; 906371584c2SYuri Pankov break; 907371584c2SYuri Pankov default: 90895c635efSGarrett D'Amore abort(); 909371584c2SYuri Pankov } 910260e9a87SYuri Pankov return; 91195c635efSGarrett D'Amore } 91295c635efSGarrett D'Amore 91395c635efSGarrett D'Amore /* Extract parameter into data. */ 91495c635efSGarrett D'Amore 915371584c2SYuri Pankov if ( ! strcmp(np->child->string, "Em")) 91695c635efSGarrett D'Amore np->norm->Bf.font = FONT_Em; 917371584c2SYuri Pankov else if ( ! strcmp(np->child->string, "Li")) 91895c635efSGarrett D'Amore np->norm->Bf.font = FONT_Li; 919371584c2SYuri Pankov else if ( ! strcmp(np->child->string, "Sy")) 92095c635efSGarrett D'Amore np->norm->Bf.font = FONT_Sy; 921260e9a87SYuri Pankov else 922260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_BF_BADFONT, mdoc->parse, 923260e9a87SYuri Pankov np->child->line, np->child->pos, 924260e9a87SYuri Pankov "Bf %s", np->child->string); 92595c635efSGarrett D'Amore } 92695c635efSGarrett D'Amore 927260e9a87SYuri Pankov static void 928260e9a87SYuri Pankov post_fname(POST_ARGS) 929260e9a87SYuri Pankov { 930371584c2SYuri Pankov const struct roff_node *n; 931260e9a87SYuri Pankov const char *cp; 932260e9a87SYuri Pankov size_t pos; 93395c635efSGarrett D'Amore 934260e9a87SYuri Pankov n = mdoc->last->child; 935260e9a87SYuri Pankov pos = strcspn(n->string, "()"); 936260e9a87SYuri Pankov cp = n->string + pos; 937260e9a87SYuri Pankov if ( ! (cp[0] == '\0' || (cp[0] == '(' && cp[1] == '*'))) 938260e9a87SYuri Pankov mandoc_msg(MANDOCERR_FN_PAREN, mdoc->parse, 939260e9a87SYuri Pankov n->line, n->pos + pos, n->string); 94095c635efSGarrett D'Amore } 94195c635efSGarrett D'Amore 942260e9a87SYuri Pankov static void 943260e9a87SYuri Pankov post_fn(POST_ARGS) 94495c635efSGarrett D'Amore { 94595c635efSGarrett D'Amore 946260e9a87SYuri Pankov post_fname(mdoc); 947260e9a87SYuri Pankov post_fa(mdoc); 94895c635efSGarrett D'Amore } 94995c635efSGarrett D'Amore 950260e9a87SYuri Pankov static void 951260e9a87SYuri Pankov post_fo(POST_ARGS) 952260e9a87SYuri Pankov { 953371584c2SYuri Pankov const struct roff_node *n; 95495c635efSGarrett D'Amore 955260e9a87SYuri Pankov n = mdoc->last; 956260e9a87SYuri Pankov 957371584c2SYuri Pankov if (n->type != ROFFT_HEAD) 958260e9a87SYuri Pankov return; 959260e9a87SYuri Pankov 960260e9a87SYuri Pankov if (n->child == NULL) { 961260e9a87SYuri Pankov mandoc_msg(MANDOCERR_FO_NOHEAD, mdoc->parse, 962260e9a87SYuri Pankov n->line, n->pos, "Fo"); 963260e9a87SYuri Pankov return; 964260e9a87SYuri Pankov } 965260e9a87SYuri Pankov if (n->child != n->last) { 966260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse, 967260e9a87SYuri Pankov n->child->next->line, n->child->next->pos, 968260e9a87SYuri Pankov "Fo ... %s", n->child->next->string); 969260e9a87SYuri Pankov while (n->child != n->last) 970371584c2SYuri Pankov roff_node_delete(mdoc, n->last); 971260e9a87SYuri Pankov } 972260e9a87SYuri Pankov 973260e9a87SYuri Pankov post_fname(mdoc); 974260e9a87SYuri Pankov } 975260e9a87SYuri Pankov 976260e9a87SYuri Pankov static void 977260e9a87SYuri Pankov post_fa(POST_ARGS) 978260e9a87SYuri Pankov { 979371584c2SYuri Pankov const struct roff_node *n; 980260e9a87SYuri Pankov const char *cp; 981260e9a87SYuri Pankov 982260e9a87SYuri Pankov for (n = mdoc->last->child; n != NULL; n = n->next) { 983260e9a87SYuri Pankov for (cp = n->string; *cp != '\0'; cp++) { 984260e9a87SYuri Pankov /* Ignore callbacks and alterations. */ 985260e9a87SYuri Pankov if (*cp == '(' || *cp == '{') 986260e9a87SYuri Pankov break; 987260e9a87SYuri Pankov if (*cp != ',') 988260e9a87SYuri Pankov continue; 989260e9a87SYuri Pankov mandoc_msg(MANDOCERR_FA_COMMA, mdoc->parse, 990260e9a87SYuri Pankov n->line, n->pos + (cp - n->string), 991260e9a87SYuri Pankov n->string); 992260e9a87SYuri Pankov break; 993260e9a87SYuri Pankov } 994260e9a87SYuri Pankov } 995260e9a87SYuri Pankov } 996260e9a87SYuri Pankov 997260e9a87SYuri Pankov static void 99895c635efSGarrett D'Amore post_nm(POST_ARGS) 99995c635efSGarrett D'Amore { 1000371584c2SYuri Pankov struct roff_node *n; 1001260e9a87SYuri Pankov 1002260e9a87SYuri Pankov n = mdoc->last; 1003260e9a87SYuri Pankov 1004260e9a87SYuri Pankov if (n->last != NULL && 1005260e9a87SYuri Pankov (n->last->tok == MDOC_Pp || 1006260e9a87SYuri Pankov n->last->tok == MDOC_Lp)) 1007260e9a87SYuri Pankov mdoc_node_relink(mdoc, n->last); 100895c635efSGarrett D'Amore 1009371584c2SYuri Pankov if (mdoc->meta.name == NULL) 1010*a40ea1a7SYuri Pankov deroff(&mdoc->meta.name, n); 1011*a40ea1a7SYuri Pankov 1012*a40ea1a7SYuri Pankov if (mdoc->meta.name == NULL || 1013*a40ea1a7SYuri Pankov (mdoc->lastsec == SEC_NAME && n->child == NULL)) 1014260e9a87SYuri Pankov mandoc_msg(MANDOCERR_NM_NONAME, mdoc->parse, 1015260e9a87SYuri Pankov n->line, n->pos, "Nm"); 1016*a40ea1a7SYuri Pankov 1017*a40ea1a7SYuri Pankov if ((n->type != ROFFT_ELEM && n->type != ROFFT_HEAD) || 1018*a40ea1a7SYuri Pankov (n->child != NULL && n->child->type == ROFFT_TEXT) || 1019*a40ea1a7SYuri Pankov mdoc->meta.name == NULL) 1020*a40ea1a7SYuri Pankov return; 1021*a40ea1a7SYuri Pankov 1022*a40ea1a7SYuri Pankov mdoc->next = ROFF_NEXT_CHILD; 1023*a40ea1a7SYuri Pankov roff_word_alloc(mdoc, n->line, n->pos, mdoc->meta.name); 1024*a40ea1a7SYuri Pankov mdoc->last->flags |= NODE_NOSRC; 1025*a40ea1a7SYuri Pankov mdoc->last = n; 102695c635efSGarrett D'Amore } 102795c635efSGarrett D'Amore 1028260e9a87SYuri Pankov static void 1029260e9a87SYuri Pankov post_nd(POST_ARGS) 1030260e9a87SYuri Pankov { 1031371584c2SYuri Pankov struct roff_node *n; 1032260e9a87SYuri Pankov 1033260e9a87SYuri Pankov n = mdoc->last; 1034260e9a87SYuri Pankov 1035371584c2SYuri Pankov if (n->type != ROFFT_BODY) 1036260e9a87SYuri Pankov return; 1037260e9a87SYuri Pankov 1038260e9a87SYuri Pankov if (n->child == NULL) 1039260e9a87SYuri Pankov mandoc_msg(MANDOCERR_ND_EMPTY, mdoc->parse, 1040260e9a87SYuri Pankov n->line, n->pos, "Nd"); 1041260e9a87SYuri Pankov 1042260e9a87SYuri Pankov post_hyph(mdoc); 1043260e9a87SYuri Pankov } 1044260e9a87SYuri Pankov 1045260e9a87SYuri Pankov static void 1046371584c2SYuri Pankov post_display(POST_ARGS) 1047260e9a87SYuri Pankov { 1048371584c2SYuri Pankov struct roff_node *n, *np; 1049260e9a87SYuri Pankov 1050260e9a87SYuri Pankov n = mdoc->last; 1051371584c2SYuri Pankov switch (n->type) { 1052371584c2SYuri Pankov case ROFFT_BODY: 1053*a40ea1a7SYuri Pankov if (n->end != ENDBODY_NOT) { 1054*a40ea1a7SYuri Pankov if (n->tok == MDOC_Bd && 1055*a40ea1a7SYuri Pankov n->body->parent->args == NULL) 1056*a40ea1a7SYuri Pankov roff_node_delete(mdoc, n); 1057*a40ea1a7SYuri Pankov } else if (n->child == NULL) 1058371584c2SYuri Pankov mandoc_msg(MANDOCERR_BLK_EMPTY, mdoc->parse, 1059371584c2SYuri Pankov n->line, n->pos, mdoc_macronames[n->tok]); 1060371584c2SYuri Pankov else if (n->tok == MDOC_D1) 1061371584c2SYuri Pankov post_hyph(mdoc); 1062371584c2SYuri Pankov break; 1063371584c2SYuri Pankov case ROFFT_BLOCK: 1064371584c2SYuri Pankov if (n->tok == MDOC_Bd) { 1065371584c2SYuri Pankov if (n->args == NULL) { 1066371584c2SYuri Pankov mandoc_msg(MANDOCERR_BD_NOARG, 1067371584c2SYuri Pankov mdoc->parse, n->line, n->pos, "Bd"); 1068371584c2SYuri Pankov mdoc->next = ROFF_NEXT_SIBLING; 1069371584c2SYuri Pankov while (n->body->child != NULL) 1070371584c2SYuri Pankov mdoc_node_relink(mdoc, 1071371584c2SYuri Pankov n->body->child); 1072371584c2SYuri Pankov roff_node_delete(mdoc, n); 1073371584c2SYuri Pankov break; 1074371584c2SYuri Pankov } 1075371584c2SYuri Pankov post_bd(mdoc); 1076371584c2SYuri Pankov post_prevpar(mdoc); 1077371584c2SYuri Pankov } 1078371584c2SYuri Pankov for (np = n->parent; np != NULL; np = np->parent) { 1079371584c2SYuri Pankov if (np->type == ROFFT_BLOCK && np->tok == MDOC_Bd) { 1080371584c2SYuri Pankov mandoc_vmsg(MANDOCERR_BD_NEST, 1081371584c2SYuri Pankov mdoc->parse, n->line, n->pos, 1082371584c2SYuri Pankov "%s in Bd", mdoc_macronames[n->tok]); 1083371584c2SYuri Pankov break; 1084371584c2SYuri Pankov } 1085371584c2SYuri Pankov } 1086371584c2SYuri Pankov break; 1087371584c2SYuri Pankov default: 1088371584c2SYuri Pankov break; 1089371584c2SYuri Pankov } 109095c635efSGarrett D'Amore } 109195c635efSGarrett D'Amore 1092260e9a87SYuri Pankov static void 109395c635efSGarrett D'Amore post_defaults(POST_ARGS) 109495c635efSGarrett D'Amore { 1095371584c2SYuri Pankov struct roff_node *nn; 109695c635efSGarrett D'Amore 109795c635efSGarrett D'Amore /* 109895c635efSGarrett D'Amore * The `Ar' defaults to "file ..." if no value is provided as an 109995c635efSGarrett D'Amore * argument; the `Mt' and `Pa' macros use "~"; the `Li' just 110095c635efSGarrett D'Amore * gets an empty string. 110195c635efSGarrett D'Amore */ 110295c635efSGarrett D'Amore 1103371584c2SYuri Pankov if (mdoc->last->child != NULL) 1104260e9a87SYuri Pankov return; 1105260e9a87SYuri Pankov 110695c635efSGarrett D'Amore nn = mdoc->last; 110795c635efSGarrett D'Amore 110895c635efSGarrett D'Amore switch (nn->tok) { 1109260e9a87SYuri Pankov case MDOC_Ar: 1110371584c2SYuri Pankov mdoc->next = ROFF_NEXT_CHILD; 1111371584c2SYuri Pankov roff_word_alloc(mdoc, nn->line, nn->pos, "file"); 1112*a40ea1a7SYuri Pankov mdoc->last->flags |= NODE_NOSRC; 1113371584c2SYuri Pankov roff_word_alloc(mdoc, nn->line, nn->pos, "..."); 1114*a40ea1a7SYuri Pankov mdoc->last->flags |= NODE_NOSRC; 111595c635efSGarrett D'Amore break; 1116260e9a87SYuri Pankov case MDOC_Pa: 1117260e9a87SYuri Pankov case MDOC_Mt: 1118371584c2SYuri Pankov mdoc->next = ROFF_NEXT_CHILD; 1119371584c2SYuri Pankov roff_word_alloc(mdoc, nn->line, nn->pos, "~"); 1120*a40ea1a7SYuri Pankov mdoc->last->flags |= NODE_NOSRC; 112195c635efSGarrett D'Amore break; 112295c635efSGarrett D'Amore default: 112395c635efSGarrett D'Amore abort(); 1124260e9a87SYuri Pankov } 112595c635efSGarrett D'Amore mdoc->last = nn; 112695c635efSGarrett D'Amore } 112795c635efSGarrett D'Amore 1128260e9a87SYuri Pankov static void 112995c635efSGarrett D'Amore post_at(POST_ARGS) 113095c635efSGarrett D'Amore { 1131*a40ea1a7SYuri Pankov struct roff_node *n, *nch; 1132*a40ea1a7SYuri Pankov const char *att; 1133260e9a87SYuri Pankov 1134260e9a87SYuri Pankov n = mdoc->last; 1135*a40ea1a7SYuri Pankov nch = n->child; 113695c635efSGarrett D'Amore 113795c635efSGarrett D'Amore /* 113895c635efSGarrett D'Amore * If we have a child, look it up in the standard keys. If a 113995c635efSGarrett D'Amore * key exist, use that instead of the child; if it doesn't, 114095c635efSGarrett D'Amore * prefix "AT&T UNIX " to the existing data. 114195c635efSGarrett D'Amore */ 114295c635efSGarrett D'Amore 1143*a40ea1a7SYuri Pankov att = NULL; 1144*a40ea1a7SYuri Pankov if (nch != NULL && ((att = mdoc_a2att(nch->string)) == NULL)) 1145260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_AT_BAD, mdoc->parse, 1146*a40ea1a7SYuri Pankov nch->line, nch->pos, "At %s", nch->string); 114795c635efSGarrett D'Amore 1148*a40ea1a7SYuri Pankov mdoc->next = ROFF_NEXT_CHILD; 1149*a40ea1a7SYuri Pankov if (att != NULL) { 1150*a40ea1a7SYuri Pankov roff_word_alloc(mdoc, nch->line, nch->pos, att); 1151*a40ea1a7SYuri Pankov nch->flags |= NODE_NOPRT; 1152*a40ea1a7SYuri Pankov } else 1153*a40ea1a7SYuri Pankov roff_word_alloc(mdoc, n->line, n->pos, "AT&T UNIX"); 1154*a40ea1a7SYuri Pankov mdoc->last->flags |= NODE_NOSRC; 1155*a40ea1a7SYuri Pankov mdoc->last = n; 115695c635efSGarrett D'Amore } 115795c635efSGarrett D'Amore 1158260e9a87SYuri Pankov static void 115995c635efSGarrett D'Amore post_an(POST_ARGS) 116095c635efSGarrett D'Amore { 1161371584c2SYuri Pankov struct roff_node *np, *nch; 1162371584c2SYuri Pankov 1163371584c2SYuri Pankov post_an_norm(mdoc); 116495c635efSGarrett D'Amore 116595c635efSGarrett D'Amore np = mdoc->last; 1166260e9a87SYuri Pankov nch = np->child; 1167260e9a87SYuri Pankov if (np->norm->An.auth == AUTH__NONE) { 1168260e9a87SYuri Pankov if (nch == NULL) 1169260e9a87SYuri Pankov mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse, 1170260e9a87SYuri Pankov np->line, np->pos, "An"); 1171260e9a87SYuri Pankov } else if (nch != NULL) 1172260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse, 1173260e9a87SYuri Pankov nch->line, nch->pos, "An ... %s", nch->string); 1174260e9a87SYuri Pankov } 1175260e9a87SYuri Pankov 1176260e9a87SYuri Pankov static void 1177260e9a87SYuri Pankov post_en(POST_ARGS) 1178260e9a87SYuri Pankov { 117995c635efSGarrett D'Amore 1180371584c2SYuri Pankov post_obsolete(mdoc); 1181371584c2SYuri Pankov if (mdoc->last->type == ROFFT_BLOCK) 1182260e9a87SYuri Pankov mdoc->last->norm->Es = mdoc->last_es; 118395c635efSGarrett D'Amore } 118495c635efSGarrett D'Amore 1185260e9a87SYuri Pankov static void 1186260e9a87SYuri Pankov post_es(POST_ARGS) 1187260e9a87SYuri Pankov { 118895c635efSGarrett D'Amore 1189371584c2SYuri Pankov post_obsolete(mdoc); 1190260e9a87SYuri Pankov mdoc->last_es = mdoc->last; 1191260e9a87SYuri Pankov } 1192260e9a87SYuri Pankov 1193*a40ea1a7SYuri Pankov static void 1194*a40ea1a7SYuri Pankov post_xx(POST_ARGS) 1195*a40ea1a7SYuri Pankov { 1196*a40ea1a7SYuri Pankov struct roff_node *n; 1197*a40ea1a7SYuri Pankov const char *os; 1198*a40ea1a7SYuri Pankov 1199*a40ea1a7SYuri Pankov n = mdoc->last; 1200*a40ea1a7SYuri Pankov switch (n->tok) { 1201*a40ea1a7SYuri Pankov case MDOC_Bsx: 1202*a40ea1a7SYuri Pankov os = "BSD/OS"; 1203*a40ea1a7SYuri Pankov break; 1204*a40ea1a7SYuri Pankov case MDOC_Dx: 1205*a40ea1a7SYuri Pankov os = "DragonFly"; 1206*a40ea1a7SYuri Pankov break; 1207*a40ea1a7SYuri Pankov case MDOC_Fx: 1208*a40ea1a7SYuri Pankov os = "FreeBSD"; 1209*a40ea1a7SYuri Pankov break; 1210*a40ea1a7SYuri Pankov case MDOC_Nx: 1211*a40ea1a7SYuri Pankov os = "NetBSD"; 1212*a40ea1a7SYuri Pankov break; 1213*a40ea1a7SYuri Pankov case MDOC_Ox: 1214*a40ea1a7SYuri Pankov os = "OpenBSD"; 1215*a40ea1a7SYuri Pankov break; 1216*a40ea1a7SYuri Pankov case MDOC_Ux: 1217*a40ea1a7SYuri Pankov os = "UNIX"; 1218*a40ea1a7SYuri Pankov break; 1219*a40ea1a7SYuri Pankov default: 1220*a40ea1a7SYuri Pankov abort(); 1221*a40ea1a7SYuri Pankov } 1222*a40ea1a7SYuri Pankov mdoc->next = ROFF_NEXT_CHILD; 1223*a40ea1a7SYuri Pankov roff_word_alloc(mdoc, n->line, n->pos, os); 1224*a40ea1a7SYuri Pankov mdoc->last->flags |= NODE_NOSRC; 1225*a40ea1a7SYuri Pankov mdoc->last = n; 1226*a40ea1a7SYuri Pankov } 1227*a40ea1a7SYuri Pankov 1228260e9a87SYuri Pankov static void 122995c635efSGarrett D'Amore post_it(POST_ARGS) 123095c635efSGarrett D'Amore { 1231371584c2SYuri Pankov struct roff_node *nbl, *nit, *nch; 123295c635efSGarrett D'Amore int i, cols; 123395c635efSGarrett D'Amore enum mdoc_list lt; 1234371584c2SYuri Pankov 1235371584c2SYuri Pankov post_prevpar(mdoc); 123695c635efSGarrett D'Amore 1237260e9a87SYuri Pankov nit = mdoc->last; 1238371584c2SYuri Pankov if (nit->type != ROFFT_BLOCK) 1239260e9a87SYuri Pankov return; 124095c635efSGarrett D'Amore 1241260e9a87SYuri Pankov nbl = nit->parent->parent; 1242260e9a87SYuri Pankov lt = nbl->norm->Bl.type; 124395c635efSGarrett D'Amore 124495c635efSGarrett D'Amore switch (lt) { 1245260e9a87SYuri Pankov case LIST_tag: 1246260e9a87SYuri Pankov case LIST_hang: 1247260e9a87SYuri Pankov case LIST_ohang: 1248260e9a87SYuri Pankov case LIST_inset: 1249260e9a87SYuri Pankov case LIST_diag: 1250260e9a87SYuri Pankov if (nit->head->child == NULL) 1251260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_IT_NOHEAD, 1252260e9a87SYuri Pankov mdoc->parse, nit->line, nit->pos, 1253260e9a87SYuri Pankov "Bl -%s It", 1254260e9a87SYuri Pankov mdoc_argnames[nbl->args->argv[0].arg]); 125595c635efSGarrett D'Amore break; 1256260e9a87SYuri Pankov case LIST_bullet: 1257260e9a87SYuri Pankov case LIST_dash: 1258260e9a87SYuri Pankov case LIST_enum: 1259260e9a87SYuri Pankov case LIST_hyphen: 1260260e9a87SYuri Pankov if (nit->body == NULL || nit->body->child == NULL) 1261260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_IT_NOBODY, 1262260e9a87SYuri Pankov mdoc->parse, nit->line, nit->pos, 1263260e9a87SYuri Pankov "Bl -%s It", 1264260e9a87SYuri Pankov mdoc_argnames[nbl->args->argv[0].arg]); 126595c635efSGarrett D'Amore /* FALLTHROUGH */ 1266260e9a87SYuri Pankov case LIST_item: 1267*a40ea1a7SYuri Pankov if ((nch = nit->head->child) != NULL) 1268260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_ARG_SKIP, 1269260e9a87SYuri Pankov mdoc->parse, nit->line, nit->pos, 1270*a40ea1a7SYuri Pankov "It %s", nch->string == NULL ? 1271*a40ea1a7SYuri Pankov mdoc_macronames[nch->tok] : nch->string); 127295c635efSGarrett D'Amore break; 1273260e9a87SYuri Pankov case LIST_column: 1274260e9a87SYuri Pankov cols = (int)nbl->norm->Bl.ncols; 127595c635efSGarrett D'Amore 1276260e9a87SYuri Pankov assert(nit->head->child == NULL); 127795c635efSGarrett D'Amore 1278371584c2SYuri Pankov i = 0; 1279371584c2SYuri Pankov for (nch = nit->child; nch != NULL; nch = nch->next) 1280371584c2SYuri Pankov if (nch->type == ROFFT_BODY) 128195c635efSGarrett D'Amore i++; 128295c635efSGarrett D'Amore 1283260e9a87SYuri Pankov if (i < cols || i > cols + 1) 1284260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_BL_COL, 1285260e9a87SYuri Pankov mdoc->parse, nit->line, nit->pos, 1286260e9a87SYuri Pankov "%d columns, %d cells", cols, i); 128795c635efSGarrett D'Amore break; 1288260e9a87SYuri Pankov default: 1289260e9a87SYuri Pankov abort(); 129095c635efSGarrett D'Amore } 129195c635efSGarrett D'Amore } 129295c635efSGarrett D'Amore 1293260e9a87SYuri Pankov static void 1294260e9a87SYuri Pankov post_bl_block(POST_ARGS) 129595c635efSGarrett D'Amore { 1296371584c2SYuri Pankov struct roff_node *n, *ni, *nc; 1297371584c2SYuri Pankov 1298371584c2SYuri Pankov post_prevpar(mdoc); 129995c635efSGarrett D'Amore 130095c635efSGarrett D'Amore n = mdoc->last; 1301371584c2SYuri Pankov for (ni = n->body->child; ni != NULL; ni = ni->next) { 1302371584c2SYuri Pankov if (ni->body == NULL) 1303698f87a4SGarrett D'Amore continue; 1304698f87a4SGarrett D'Amore nc = ni->body->last; 1305371584c2SYuri Pankov while (nc != NULL) { 1306698f87a4SGarrett D'Amore switch (nc->tok) { 1307260e9a87SYuri Pankov case MDOC_Pp: 1308260e9a87SYuri Pankov case MDOC_Lp: 1309260e9a87SYuri Pankov case MDOC_br: 1310698f87a4SGarrett D'Amore break; 1311698f87a4SGarrett D'Amore default: 1312698f87a4SGarrett D'Amore nc = NULL; 1313698f87a4SGarrett D'Amore continue; 1314698f87a4SGarrett D'Amore } 1315371584c2SYuri Pankov if (ni->next == NULL) { 1316260e9a87SYuri Pankov mandoc_msg(MANDOCERR_PAR_MOVE, 1317260e9a87SYuri Pankov mdoc->parse, nc->line, nc->pos, 1318260e9a87SYuri Pankov mdoc_macronames[nc->tok]); 1319260e9a87SYuri Pankov mdoc_node_relink(mdoc, nc); 1320371584c2SYuri Pankov } else if (n->norm->Bl.comp == 0 && 1321371584c2SYuri Pankov n->norm->Bl.type != LIST_column) { 1322260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_PAR_SKIP, 1323260e9a87SYuri Pankov mdoc->parse, nc->line, nc->pos, 1324260e9a87SYuri Pankov "%s before It", 1325260e9a87SYuri Pankov mdoc_macronames[nc->tok]); 1326371584c2SYuri Pankov roff_node_delete(mdoc, nc); 1327698f87a4SGarrett D'Amore } else 1328698f87a4SGarrett D'Amore break; 1329698f87a4SGarrett D'Amore nc = ni->body->last; 1330698f87a4SGarrett D'Amore } 1331698f87a4SGarrett D'Amore } 133295c635efSGarrett D'Amore } 133395c635efSGarrett D'Amore 1334260e9a87SYuri Pankov /* 1335260e9a87SYuri Pankov * If the argument of -offset or -width is a macro, 1336260e9a87SYuri Pankov * replace it with the associated default width. 1337260e9a87SYuri Pankov */ 1338260e9a87SYuri Pankov void 1339260e9a87SYuri Pankov rewrite_macro2len(char **arg) 134095c635efSGarrett D'Amore { 134195c635efSGarrett D'Amore size_t width; 1342371584c2SYuri Pankov int tok; 134395c635efSGarrett D'Amore 1344260e9a87SYuri Pankov if (*arg == NULL) 1345260e9a87SYuri Pankov return; 1346260e9a87SYuri Pankov else if ( ! strcmp(*arg, "Ds")) 134795c635efSGarrett D'Amore width = 6; 1348371584c2SYuri Pankov else if ((tok = mdoc_hash_find(*arg)) == TOKEN_NONE) 1349260e9a87SYuri Pankov return; 1350260e9a87SYuri Pankov else 1351260e9a87SYuri Pankov width = macro2len(tok); 135295c635efSGarrett D'Amore 1353260e9a87SYuri Pankov free(*arg); 1354260e9a87SYuri Pankov mandoc_asprintf(arg, "%zun", width); 135595c635efSGarrett D'Amore } 135695c635efSGarrett D'Amore 1357260e9a87SYuri Pankov static void 1358260e9a87SYuri Pankov post_bl_head(POST_ARGS) 135995c635efSGarrett D'Amore { 1360371584c2SYuri Pankov struct roff_node *nbl, *nh, *nch, *nnext; 1361260e9a87SYuri Pankov struct mdoc_argv *argv; 136295c635efSGarrett D'Amore int i, j; 136395c635efSGarrett D'Amore 1364371584c2SYuri Pankov post_bl_norm(mdoc); 1365260e9a87SYuri Pankov 1366371584c2SYuri Pankov nh = mdoc->last; 1367260e9a87SYuri Pankov if (nh->norm->Bl.type != LIST_column) { 1368260e9a87SYuri Pankov if ((nch = nh->child) == NULL) 1369260e9a87SYuri Pankov return; 1370260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse, 1371260e9a87SYuri Pankov nch->line, nch->pos, "Bl ... %s", nch->string); 1372260e9a87SYuri Pankov while (nch != NULL) { 1373371584c2SYuri Pankov roff_node_delete(mdoc, nch); 1374260e9a87SYuri Pankov nch = nh->child; 1375260e9a87SYuri Pankov } 1376260e9a87SYuri Pankov return; 1377260e9a87SYuri Pankov } 137895c635efSGarrett D'Amore 137995c635efSGarrett D'Amore /* 1380260e9a87SYuri Pankov * Append old-style lists, where the column width specifiers 138195c635efSGarrett D'Amore * trail as macro parameters, to the new-style ("normal-form") 138295c635efSGarrett D'Amore * lists where they're argument values following -column. 138395c635efSGarrett D'Amore */ 138495c635efSGarrett D'Amore 1385260e9a87SYuri Pankov if (nh->child == NULL) 1386260e9a87SYuri Pankov return; 138795c635efSGarrett D'Amore 1388260e9a87SYuri Pankov nbl = nh->parent; 1389260e9a87SYuri Pankov for (j = 0; j < (int)nbl->args->argc; j++) 1390260e9a87SYuri Pankov if (nbl->args->argv[j].arg == MDOC_Column) 139195c635efSGarrett D'Amore break; 139295c635efSGarrett D'Amore 1393260e9a87SYuri Pankov assert(j < (int)nbl->args->argc); 139495c635efSGarrett D'Amore 139595c635efSGarrett D'Amore /* 139695c635efSGarrett D'Amore * Accommodate for new-style groff column syntax. Shuffle the 139795c635efSGarrett D'Amore * child nodes, all of which must be TEXT, as arguments for the 139895c635efSGarrett D'Amore * column field. Then, delete the head children. 139995c635efSGarrett D'Amore */ 140095c635efSGarrett D'Amore 1401260e9a87SYuri Pankov argv = nbl->args->argv + j; 1402260e9a87SYuri Pankov i = argv->sz; 1403371584c2SYuri Pankov for (nch = nh->child; nch != NULL; nch = nch->next) 1404371584c2SYuri Pankov argv->sz++; 1405260e9a87SYuri Pankov argv->value = mandoc_reallocarray(argv->value, 1406260e9a87SYuri Pankov argv->sz, sizeof(char *)); 140795c635efSGarrett D'Amore 1408260e9a87SYuri Pankov nh->norm->Bl.ncols = argv->sz; 1409260e9a87SYuri Pankov nh->norm->Bl.cols = (void *)argv->value; 141095c635efSGarrett D'Amore 1411260e9a87SYuri Pankov for (nch = nh->child; nch != NULL; nch = nnext) { 1412260e9a87SYuri Pankov argv->value[i++] = nch->string; 1413260e9a87SYuri Pankov nch->string = NULL; 1414260e9a87SYuri Pankov nnext = nch->next; 1415371584c2SYuri Pankov roff_node_delete(NULL, nch); 141695c635efSGarrett D'Amore } 1417260e9a87SYuri Pankov nh->child = NULL; 141895c635efSGarrett D'Amore } 141995c635efSGarrett D'Amore 1420260e9a87SYuri Pankov static void 142195c635efSGarrett D'Amore post_bl(POST_ARGS) 142295c635efSGarrett D'Amore { 1423371584c2SYuri Pankov struct roff_node *nparent, *nprev; /* of the Bl block */ 1424371584c2SYuri Pankov struct roff_node *nblock, *nbody; /* of the Bl */ 1425371584c2SYuri Pankov struct roff_node *nchild, *nnext; /* of the Bl body */ 142695c635efSGarrett D'Amore 1427698f87a4SGarrett D'Amore nbody = mdoc->last; 1428698f87a4SGarrett D'Amore switch (nbody->type) { 1429371584c2SYuri Pankov case ROFFT_BLOCK: 1430260e9a87SYuri Pankov post_bl_block(mdoc); 1431260e9a87SYuri Pankov return; 1432371584c2SYuri Pankov case ROFFT_HEAD: 1433260e9a87SYuri Pankov post_bl_head(mdoc); 1434260e9a87SYuri Pankov return; 1435371584c2SYuri Pankov case ROFFT_BODY: 1436698f87a4SGarrett D'Amore break; 1437698f87a4SGarrett D'Amore default: 1438260e9a87SYuri Pankov return; 1439698f87a4SGarrett D'Amore } 1440371584c2SYuri Pankov if (nbody->end != ENDBODY_NOT) 1441371584c2SYuri Pankov return; 144295c635efSGarrett D'Amore 1443698f87a4SGarrett D'Amore nchild = nbody->child; 1444260e9a87SYuri Pankov if (nchild == NULL) { 1445260e9a87SYuri Pankov mandoc_msg(MANDOCERR_BLK_EMPTY, mdoc->parse, 1446260e9a87SYuri Pankov nbody->line, nbody->pos, "Bl"); 1447260e9a87SYuri Pankov return; 1448260e9a87SYuri Pankov } 1449260e9a87SYuri Pankov while (nchild != NULL) { 1450*a40ea1a7SYuri Pankov nnext = nchild->next; 1451260e9a87SYuri Pankov if (nchild->tok == MDOC_It || 1452260e9a87SYuri Pankov (nchild->tok == MDOC_Sm && 1453*a40ea1a7SYuri Pankov nnext != NULL && nnext->tok == MDOC_It)) { 1454*a40ea1a7SYuri Pankov nchild = nnext; 1455*a40ea1a7SYuri Pankov continue; 1456*a40ea1a7SYuri Pankov } 1457*a40ea1a7SYuri Pankov 1458*a40ea1a7SYuri Pankov /* 1459*a40ea1a7SYuri Pankov * In .Bl -column, the first rows may be implicit, 1460*a40ea1a7SYuri Pankov * that is, they may not start with .It macros. 1461*a40ea1a7SYuri Pankov * Such rows may be followed by nodes generated on the 1462*a40ea1a7SYuri Pankov * roff level, for example .TS, which cannot be moved 1463*a40ea1a7SYuri Pankov * out of the list. In that case, wrap such roff nodes 1464*a40ea1a7SYuri Pankov * into an implicit row. 1465*a40ea1a7SYuri Pankov */ 1466*a40ea1a7SYuri Pankov 1467*a40ea1a7SYuri Pankov if (nchild->prev != NULL) { 1468*a40ea1a7SYuri Pankov mdoc->last = nchild; 1469*a40ea1a7SYuri Pankov mdoc->next = ROFF_NEXT_SIBLING; 1470*a40ea1a7SYuri Pankov roff_block_alloc(mdoc, nchild->line, 1471*a40ea1a7SYuri Pankov nchild->pos, MDOC_It); 1472*a40ea1a7SYuri Pankov roff_head_alloc(mdoc, nchild->line, 1473*a40ea1a7SYuri Pankov nchild->pos, MDOC_It); 1474*a40ea1a7SYuri Pankov mdoc->next = ROFF_NEXT_SIBLING; 1475*a40ea1a7SYuri Pankov roff_body_alloc(mdoc, nchild->line, 1476*a40ea1a7SYuri Pankov nchild->pos, MDOC_It); 1477*a40ea1a7SYuri Pankov while (nchild->tok != MDOC_It) { 1478*a40ea1a7SYuri Pankov mdoc_node_relink(mdoc, nchild); 1479*a40ea1a7SYuri Pankov if ((nchild = nnext) == NULL) 1480*a40ea1a7SYuri Pankov break; 1481*a40ea1a7SYuri Pankov nnext = nchild->next; 1482*a40ea1a7SYuri Pankov mdoc->next = ROFF_NEXT_SIBLING; 1483*a40ea1a7SYuri Pankov } 1484*a40ea1a7SYuri Pankov mdoc->last = nbody; 148595c635efSGarrett D'Amore continue; 148695c635efSGarrett D'Amore } 148795c635efSGarrett D'Amore 1488260e9a87SYuri Pankov mandoc_msg(MANDOCERR_BL_MOVE, mdoc->parse, 1489260e9a87SYuri Pankov nchild->line, nchild->pos, 1490260e9a87SYuri Pankov mdoc_macronames[nchild->tok]); 1491698f87a4SGarrett D'Amore 1492698f87a4SGarrett D'Amore /* 1493698f87a4SGarrett D'Amore * Move the node out of the Bl block. 1494698f87a4SGarrett D'Amore * First, collect all required node pointers. 1495698f87a4SGarrett D'Amore */ 1496698f87a4SGarrett D'Amore 1497698f87a4SGarrett D'Amore nblock = nbody->parent; 1498698f87a4SGarrett D'Amore nprev = nblock->prev; 1499698f87a4SGarrett D'Amore nparent = nblock->parent; 1500698f87a4SGarrett D'Amore 1501698f87a4SGarrett D'Amore /* 1502698f87a4SGarrett D'Amore * Unlink this child. 1503698f87a4SGarrett D'Amore */ 1504698f87a4SGarrett D'Amore 1505371584c2SYuri Pankov nbody->child = nnext; 1506371584c2SYuri Pankov if (nnext == NULL) 1507698f87a4SGarrett D'Amore nbody->last = NULL; 1508371584c2SYuri Pankov else 1509698f87a4SGarrett D'Amore nnext->prev = NULL; 1510698f87a4SGarrett D'Amore 1511698f87a4SGarrett D'Amore /* 1512698f87a4SGarrett D'Amore * Relink this child. 1513698f87a4SGarrett D'Amore */ 1514698f87a4SGarrett D'Amore 1515698f87a4SGarrett D'Amore nchild->parent = nparent; 1516698f87a4SGarrett D'Amore nchild->prev = nprev; 1517698f87a4SGarrett D'Amore nchild->next = nblock; 1518698f87a4SGarrett D'Amore 1519698f87a4SGarrett D'Amore nblock->prev = nchild; 1520371584c2SYuri Pankov if (nprev == NULL) 1521698f87a4SGarrett D'Amore nparent->child = nchild; 1522698f87a4SGarrett D'Amore else 1523698f87a4SGarrett D'Amore nprev->next = nchild; 1524698f87a4SGarrett D'Amore 1525698f87a4SGarrett D'Amore nchild = nnext; 152695c635efSGarrett D'Amore } 1527260e9a87SYuri Pankov } 1528260e9a87SYuri Pankov 1529260e9a87SYuri Pankov static void 1530260e9a87SYuri Pankov post_bk(POST_ARGS) 1531260e9a87SYuri Pankov { 1532371584c2SYuri Pankov struct roff_node *n; 1533260e9a87SYuri Pankov 1534260e9a87SYuri Pankov n = mdoc->last; 153595c635efSGarrett D'Amore 1536371584c2SYuri Pankov if (n->type == ROFFT_BLOCK && n->body->child == NULL) { 1537260e9a87SYuri Pankov mandoc_msg(MANDOCERR_BLK_EMPTY, 1538260e9a87SYuri Pankov mdoc->parse, n->line, n->pos, "Bk"); 1539371584c2SYuri Pankov roff_node_delete(mdoc, n); 1540260e9a87SYuri Pankov } 154195c635efSGarrett D'Amore } 154295c635efSGarrett D'Amore 1543260e9a87SYuri Pankov static void 1544371584c2SYuri Pankov post_sm(POST_ARGS) 154595c635efSGarrett D'Amore { 1546371584c2SYuri Pankov struct roff_node *nch; 154795c635efSGarrett D'Amore 1548260e9a87SYuri Pankov nch = mdoc->last->child; 1549260e9a87SYuri Pankov 1550260e9a87SYuri Pankov if (nch == NULL) { 1551260e9a87SYuri Pankov mdoc->flags ^= MDOC_SMOFF; 1552260e9a87SYuri Pankov return; 155395c635efSGarrett D'Amore } 155495c635efSGarrett D'Amore 1555371584c2SYuri Pankov assert(nch->type == ROFFT_TEXT); 155695c635efSGarrett D'Amore 1557260e9a87SYuri Pankov if ( ! strcmp(nch->string, "on")) { 1558260e9a87SYuri Pankov mdoc->flags &= ~MDOC_SMOFF; 1559260e9a87SYuri Pankov return; 1560698f87a4SGarrett D'Amore } 1561260e9a87SYuri Pankov if ( ! strcmp(nch->string, "off")) { 1562260e9a87SYuri Pankov mdoc->flags |= MDOC_SMOFF; 1563260e9a87SYuri Pankov return; 1564698f87a4SGarrett D'Amore } 156595c635efSGarrett D'Amore 1566260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_SM_BAD, 1567260e9a87SYuri Pankov mdoc->parse, nch->line, nch->pos, 1568260e9a87SYuri Pankov "%s %s", mdoc_macronames[mdoc->last->tok], nch->string); 1569260e9a87SYuri Pankov mdoc_node_relink(mdoc, nch); 1570260e9a87SYuri Pankov return; 157195c635efSGarrett D'Amore } 157295c635efSGarrett D'Amore 1573260e9a87SYuri Pankov static void 157495c635efSGarrett D'Amore post_root(POST_ARGS) 157595c635efSGarrett D'Amore { 1576371584c2SYuri Pankov struct roff_node *n; 157795c635efSGarrett D'Amore 1578260e9a87SYuri Pankov /* Add missing prologue data. */ 157995c635efSGarrett D'Amore 1580260e9a87SYuri Pankov if (mdoc->meta.date == NULL) 1581260e9a87SYuri Pankov mdoc->meta.date = mdoc->quick ? 1582260e9a87SYuri Pankov mandoc_strdup("") : 1583260e9a87SYuri Pankov mandoc_normdate(mdoc->parse, NULL, 0, 0); 158495c635efSGarrett D'Amore 1585260e9a87SYuri Pankov if (mdoc->meta.title == NULL) { 1586260e9a87SYuri Pankov mandoc_msg(MANDOCERR_DT_NOTITLE, 1587260e9a87SYuri Pankov mdoc->parse, 0, 0, "EOF"); 1588260e9a87SYuri Pankov mdoc->meta.title = mandoc_strdup("UNTITLED"); 158995c635efSGarrett D'Amore } 159095c635efSGarrett D'Amore 1591260e9a87SYuri Pankov if (mdoc->meta.vol == NULL) 1592260e9a87SYuri Pankov mdoc->meta.vol = mandoc_strdup("LOCAL"); 159395c635efSGarrett D'Amore 1594260e9a87SYuri Pankov if (mdoc->meta.os == NULL) { 1595260e9a87SYuri Pankov mandoc_msg(MANDOCERR_OS_MISSING, 1596260e9a87SYuri Pankov mdoc->parse, 0, 0, NULL); 1597260e9a87SYuri Pankov mdoc->meta.os = mandoc_strdup(""); 159895c635efSGarrett D'Amore } 159995c635efSGarrett D'Amore 1600260e9a87SYuri Pankov /* Check that we begin with a proper `Sh'. */ 1601260e9a87SYuri Pankov 1602260e9a87SYuri Pankov n = mdoc->first->child; 1603371584c2SYuri Pankov while (n != NULL && n->tok != TOKEN_NONE && 1604371584c2SYuri Pankov mdoc_macros[n->tok].flags & MDOC_PROLOGUE) 1605260e9a87SYuri Pankov n = n->next; 1606260e9a87SYuri Pankov 1607260e9a87SYuri Pankov if (n == NULL) 1608260e9a87SYuri Pankov mandoc_msg(MANDOCERR_DOC_EMPTY, mdoc->parse, 0, 0, NULL); 1609260e9a87SYuri Pankov else if (n->tok != MDOC_Sh) 1610260e9a87SYuri Pankov mandoc_msg(MANDOCERR_SEC_BEFORE, mdoc->parse, 1611260e9a87SYuri Pankov n->line, n->pos, mdoc_macronames[n->tok]); 161295c635efSGarrett D'Amore } 161395c635efSGarrett D'Amore 1614260e9a87SYuri Pankov static void 161595c635efSGarrett D'Amore post_rs(POST_ARGS) 161695c635efSGarrett D'Amore { 1617371584c2SYuri Pankov struct roff_node *np, *nch, *next, *prev; 161895c635efSGarrett D'Amore int i, j; 161995c635efSGarrett D'Amore 1620260e9a87SYuri Pankov np = mdoc->last; 162195c635efSGarrett D'Amore 1622371584c2SYuri Pankov if (np->type != ROFFT_BODY) 1623260e9a87SYuri Pankov return; 162495c635efSGarrett D'Amore 1625260e9a87SYuri Pankov if (np->child == NULL) { 1626260e9a87SYuri Pankov mandoc_msg(MANDOCERR_RS_EMPTY, mdoc->parse, 1627260e9a87SYuri Pankov np->line, np->pos, "Rs"); 1628260e9a87SYuri Pankov return; 162995c635efSGarrett D'Amore } 163095c635efSGarrett D'Amore 163195c635efSGarrett D'Amore /* 163295c635efSGarrett D'Amore * The full `Rs' block needs special handling to order the 163395c635efSGarrett D'Amore * sub-elements according to `rsord'. Pick through each element 1634260e9a87SYuri Pankov * and correctly order it. This is an insertion sort. 163595c635efSGarrett D'Amore */ 163695c635efSGarrett D'Amore 163795c635efSGarrett D'Amore next = NULL; 1638260e9a87SYuri Pankov for (nch = np->child->next; nch != NULL; nch = next) { 1639260e9a87SYuri Pankov /* Determine order number of this child. */ 164095c635efSGarrett D'Amore for (i = 0; i < RSORD_MAX; i++) 1641260e9a87SYuri Pankov if (rsord[i] == nch->tok) 164295c635efSGarrett D'Amore break; 164395c635efSGarrett D'Amore 1644260e9a87SYuri Pankov if (i == RSORD_MAX) { 1645260e9a87SYuri Pankov mandoc_msg(MANDOCERR_RS_BAD, 1646260e9a87SYuri Pankov mdoc->parse, nch->line, nch->pos, 1647260e9a87SYuri Pankov mdoc_macronames[nch->tok]); 1648260e9a87SYuri Pankov i = -1; 1649260e9a87SYuri Pankov } else if (nch->tok == MDOC__J || nch->tok == MDOC__B) 1650260e9a87SYuri Pankov np->norm->Rs.quote_T++; 1651260e9a87SYuri Pankov 1652260e9a87SYuri Pankov /* 1653260e9a87SYuri Pankov * Remove this child from the chain. This somewhat 1654371584c2SYuri Pankov * repeats roff_node_unlink(), but since we're 165595c635efSGarrett D'Amore * just re-ordering, there's no need for the 165695c635efSGarrett D'Amore * full unlink process. 165795c635efSGarrett D'Amore */ 165895c635efSGarrett D'Amore 1659260e9a87SYuri Pankov if ((next = nch->next) != NULL) 1660260e9a87SYuri Pankov next->prev = nch->prev; 166195c635efSGarrett D'Amore 1662260e9a87SYuri Pankov if ((prev = nch->prev) != NULL) 1663260e9a87SYuri Pankov prev->next = nch->next; 166495c635efSGarrett D'Amore 1665260e9a87SYuri Pankov nch->prev = nch->next = NULL; 1666260e9a87SYuri Pankov 1667260e9a87SYuri Pankov /* 166895c635efSGarrett D'Amore * Scan back until we reach a node that's 1669260e9a87SYuri Pankov * to be ordered before this child. 167095c635efSGarrett D'Amore */ 167195c635efSGarrett D'Amore 167295c635efSGarrett D'Amore for ( ; prev ; prev = prev->prev) { 167395c635efSGarrett D'Amore /* Determine order of `prev'. */ 167495c635efSGarrett D'Amore for (j = 0; j < RSORD_MAX; j++) 167595c635efSGarrett D'Amore if (rsord[j] == prev->tok) 167695c635efSGarrett D'Amore break; 1677260e9a87SYuri Pankov if (j == RSORD_MAX) 1678260e9a87SYuri Pankov j = -1; 167995c635efSGarrett D'Amore 168095c635efSGarrett D'Amore if (j <= i) 168195c635efSGarrett D'Amore break; 168295c635efSGarrett D'Amore } 168395c635efSGarrett D'Amore 168495c635efSGarrett D'Amore /* 1685260e9a87SYuri Pankov * Set this child back into its correct place 1686260e9a87SYuri Pankov * in front of the `prev' node. 168795c635efSGarrett D'Amore */ 168895c635efSGarrett D'Amore 1689260e9a87SYuri Pankov nch->prev = prev; 169095c635efSGarrett D'Amore 1691260e9a87SYuri Pankov if (prev == NULL) { 1692260e9a87SYuri Pankov np->child->prev = nch; 1693260e9a87SYuri Pankov nch->next = np->child; 1694260e9a87SYuri Pankov np->child = nch; 169595c635efSGarrett D'Amore } else { 1696260e9a87SYuri Pankov if (prev->next) 1697260e9a87SYuri Pankov prev->next->prev = nch; 1698260e9a87SYuri Pankov nch->next = prev->next; 1699260e9a87SYuri Pankov prev->next = nch; 170095c635efSGarrett D'Amore } 170195c635efSGarrett D'Amore } 170295c635efSGarrett D'Amore } 170395c635efSGarrett D'Amore 1704698f87a4SGarrett D'Amore /* 1705698f87a4SGarrett D'Amore * For some arguments of some macros, 1706698f87a4SGarrett D'Amore * convert all breakable hyphens into ASCII_HYPH. 1707698f87a4SGarrett D'Amore */ 1708260e9a87SYuri Pankov static void 1709698f87a4SGarrett D'Amore post_hyph(POST_ARGS) 1710698f87a4SGarrett D'Amore { 1711371584c2SYuri Pankov struct roff_node *nch; 1712698f87a4SGarrett D'Amore char *cp; 1713698f87a4SGarrett D'Amore 1714260e9a87SYuri Pankov for (nch = mdoc->last->child; nch != NULL; nch = nch->next) { 1715371584c2SYuri Pankov if (nch->type != ROFFT_TEXT) 1716698f87a4SGarrett D'Amore continue; 1717698f87a4SGarrett D'Amore cp = nch->string; 1718260e9a87SYuri Pankov if (*cp == '\0') 1719698f87a4SGarrett D'Amore continue; 1720260e9a87SYuri Pankov while (*(++cp) != '\0') 1721260e9a87SYuri Pankov if (*cp == '-' && 1722698f87a4SGarrett D'Amore isalpha((unsigned char)cp[-1]) && 1723698f87a4SGarrett D'Amore isalpha((unsigned char)cp[1])) 1724698f87a4SGarrett D'Amore *cp = ASCII_HYPH; 1725698f87a4SGarrett D'Amore } 1726698f87a4SGarrett D'Amore } 1727698f87a4SGarrett D'Amore 1728260e9a87SYuri Pankov static void 172995c635efSGarrett D'Amore post_ns(POST_ARGS) 173095c635efSGarrett D'Amore { 173195c635efSGarrett D'Amore 1732*a40ea1a7SYuri Pankov if (mdoc->last->flags & NODE_LINE) 1733260e9a87SYuri Pankov mandoc_msg(MANDOCERR_NS_SKIP, mdoc->parse, 1734260e9a87SYuri Pankov mdoc->last->line, mdoc->last->pos, NULL); 173595c635efSGarrett D'Amore } 173695c635efSGarrett D'Amore 1737260e9a87SYuri Pankov static void 173895c635efSGarrett D'Amore post_sh(POST_ARGS) 173995c635efSGarrett D'Amore { 174095c635efSGarrett D'Amore 1741260e9a87SYuri Pankov post_ignpar(mdoc); 174295c635efSGarrett D'Amore 1743260e9a87SYuri Pankov switch (mdoc->last->type) { 1744371584c2SYuri Pankov case ROFFT_HEAD: 1745260e9a87SYuri Pankov post_sh_head(mdoc); 1746260e9a87SYuri Pankov break; 1747371584c2SYuri Pankov case ROFFT_BODY: 1748260e9a87SYuri Pankov switch (mdoc->lastsec) { 1749260e9a87SYuri Pankov case SEC_NAME: 1750260e9a87SYuri Pankov post_sh_name(mdoc); 1751260e9a87SYuri Pankov break; 1752260e9a87SYuri Pankov case SEC_SEE_ALSO: 1753260e9a87SYuri Pankov post_sh_see_also(mdoc); 1754260e9a87SYuri Pankov break; 1755260e9a87SYuri Pankov case SEC_AUTHORS: 1756260e9a87SYuri Pankov post_sh_authors(mdoc); 1757260e9a87SYuri Pankov break; 1758260e9a87SYuri Pankov default: 1759260e9a87SYuri Pankov break; 1760260e9a87SYuri Pankov } 1761260e9a87SYuri Pankov break; 1762260e9a87SYuri Pankov default: 1763260e9a87SYuri Pankov break; 1764260e9a87SYuri Pankov } 176595c635efSGarrett D'Amore } 176695c635efSGarrett D'Amore 1767260e9a87SYuri Pankov static void 1768260e9a87SYuri Pankov post_sh_name(POST_ARGS) 176995c635efSGarrett D'Amore { 1770371584c2SYuri Pankov struct roff_node *n; 1771260e9a87SYuri Pankov int hasnm, hasnd; 177295c635efSGarrett D'Amore 1773260e9a87SYuri Pankov hasnm = hasnd = 0; 177495c635efSGarrett D'Amore 1775260e9a87SYuri Pankov for (n = mdoc->last->child; n != NULL; n = n->next) { 1776260e9a87SYuri Pankov switch (n->tok) { 1777260e9a87SYuri Pankov case MDOC_Nm: 1778*a40ea1a7SYuri Pankov if (hasnm && n->child != NULL) 1779*a40ea1a7SYuri Pankov mandoc_vmsg(MANDOCERR_NAMESEC_PUNCT, 1780*a40ea1a7SYuri Pankov mdoc->parse, n->line, n->pos, 1781*a40ea1a7SYuri Pankov "Nm %s", n->child->string); 1782260e9a87SYuri Pankov hasnm = 1; 1783*a40ea1a7SYuri Pankov continue; 1784260e9a87SYuri Pankov case MDOC_Nd: 1785260e9a87SYuri Pankov hasnd = 1; 1786260e9a87SYuri Pankov if (n->next != NULL) 1787260e9a87SYuri Pankov mandoc_msg(MANDOCERR_NAMESEC_ND, 1788260e9a87SYuri Pankov mdoc->parse, n->line, n->pos, NULL); 1789260e9a87SYuri Pankov break; 1790371584c2SYuri Pankov case TOKEN_NONE: 1791*a40ea1a7SYuri Pankov if (n->type == ROFFT_TEXT && 1792*a40ea1a7SYuri Pankov n->string[0] == ',' && n->string[1] == '\0' && 1793*a40ea1a7SYuri Pankov n->next != NULL && n->next->tok == MDOC_Nm) { 1794*a40ea1a7SYuri Pankov n = n->next; 1795*a40ea1a7SYuri Pankov continue; 1796*a40ea1a7SYuri Pankov } 1797260e9a87SYuri Pankov /* FALLTHROUGH */ 1798260e9a87SYuri Pankov default: 1799260e9a87SYuri Pankov mandoc_msg(MANDOCERR_NAMESEC_BAD, mdoc->parse, 1800260e9a87SYuri Pankov n->line, n->pos, mdoc_macronames[n->tok]); 1801*a40ea1a7SYuri Pankov continue; 1802260e9a87SYuri Pankov } 1803*a40ea1a7SYuri Pankov break; 180495c635efSGarrett D'Amore } 180595c635efSGarrett D'Amore 1806260e9a87SYuri Pankov if ( ! hasnm) 1807260e9a87SYuri Pankov mandoc_msg(MANDOCERR_NAMESEC_NONM, mdoc->parse, 1808260e9a87SYuri Pankov mdoc->last->line, mdoc->last->pos, NULL); 1809260e9a87SYuri Pankov if ( ! hasnd) 1810260e9a87SYuri Pankov mandoc_msg(MANDOCERR_NAMESEC_NOND, mdoc->parse, 1811260e9a87SYuri Pankov mdoc->last->line, mdoc->last->pos, NULL); 1812260e9a87SYuri Pankov } 1813260e9a87SYuri Pankov 1814260e9a87SYuri Pankov static void 1815260e9a87SYuri Pankov post_sh_see_also(POST_ARGS) 1816260e9a87SYuri Pankov { 1817371584c2SYuri Pankov const struct roff_node *n; 1818260e9a87SYuri Pankov const char *name, *sec; 1819260e9a87SYuri Pankov const char *lastname, *lastsec, *lastpunct; 1820260e9a87SYuri Pankov int cmp; 1821260e9a87SYuri Pankov 1822260e9a87SYuri Pankov n = mdoc->last->child; 1823260e9a87SYuri Pankov lastname = lastsec = lastpunct = NULL; 1824260e9a87SYuri Pankov while (n != NULL) { 1825371584c2SYuri Pankov if (n->tok != MDOC_Xr || 1826371584c2SYuri Pankov n->child == NULL || 1827371584c2SYuri Pankov n->child->next == NULL) 1828260e9a87SYuri Pankov break; 1829260e9a87SYuri Pankov 1830260e9a87SYuri Pankov /* Process one .Xr node. */ 1831260e9a87SYuri Pankov 1832260e9a87SYuri Pankov name = n->child->string; 1833260e9a87SYuri Pankov sec = n->child->next->string; 1834260e9a87SYuri Pankov if (lastsec != NULL) { 1835260e9a87SYuri Pankov if (lastpunct[0] != ',' || lastpunct[1] != '\0') 1836260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_XR_PUNCT, 1837260e9a87SYuri Pankov mdoc->parse, n->line, n->pos, 1838260e9a87SYuri Pankov "%s before %s(%s)", lastpunct, 1839260e9a87SYuri Pankov name, sec); 1840260e9a87SYuri Pankov cmp = strcmp(lastsec, sec); 1841260e9a87SYuri Pankov if (cmp > 0) 1842260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_XR_ORDER, 1843260e9a87SYuri Pankov mdoc->parse, n->line, n->pos, 1844260e9a87SYuri Pankov "%s(%s) after %s(%s)", name, 1845260e9a87SYuri Pankov sec, lastname, lastsec); 1846260e9a87SYuri Pankov else if (cmp == 0 && 1847260e9a87SYuri Pankov strcasecmp(lastname, name) > 0) 1848260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_XR_ORDER, 1849260e9a87SYuri Pankov mdoc->parse, n->line, n->pos, 1850260e9a87SYuri Pankov "%s after %s", name, lastname); 1851260e9a87SYuri Pankov } 1852260e9a87SYuri Pankov lastname = name; 1853260e9a87SYuri Pankov lastsec = sec; 1854260e9a87SYuri Pankov 1855260e9a87SYuri Pankov /* Process the following node. */ 1856260e9a87SYuri Pankov 1857260e9a87SYuri Pankov n = n->next; 1858260e9a87SYuri Pankov if (n == NULL) 1859260e9a87SYuri Pankov break; 1860260e9a87SYuri Pankov if (n->tok == MDOC_Xr) { 1861260e9a87SYuri Pankov lastpunct = "none"; 186295c635efSGarrett D'Amore continue; 1863260e9a87SYuri Pankov } 1864371584c2SYuri Pankov if (n->type != ROFFT_TEXT) 1865260e9a87SYuri Pankov break; 1866260e9a87SYuri Pankov for (name = n->string; *name != '\0'; name++) 1867260e9a87SYuri Pankov if (isalpha((const unsigned char)*name)) 1868260e9a87SYuri Pankov return; 1869260e9a87SYuri Pankov lastpunct = n->string; 1870260e9a87SYuri Pankov if (n->next == NULL) 1871260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_XR_PUNCT, mdoc->parse, 1872260e9a87SYuri Pankov n->line, n->pos, "%s after %s(%s)", 1873260e9a87SYuri Pankov lastpunct, lastname, lastsec); 1874260e9a87SYuri Pankov n = n->next; 187595c635efSGarrett D'Amore } 1876260e9a87SYuri Pankov } 187795c635efSGarrett D'Amore 1878260e9a87SYuri Pankov static int 1879371584c2SYuri Pankov child_an(const struct roff_node *n) 1880260e9a87SYuri Pankov { 188195c635efSGarrett D'Amore 1882260e9a87SYuri Pankov for (n = n->child; n != NULL; n = n->next) 1883371584c2SYuri Pankov if ((n->tok == MDOC_An && n->child != NULL) || child_an(n)) 1884371584c2SYuri Pankov return 1; 1885371584c2SYuri Pankov return 0; 188695c635efSGarrett D'Amore } 188795c635efSGarrett D'Amore 1888260e9a87SYuri Pankov static void 1889260e9a87SYuri Pankov post_sh_authors(POST_ARGS) 1890260e9a87SYuri Pankov { 1891260e9a87SYuri Pankov 1892260e9a87SYuri Pankov if ( ! child_an(mdoc->last)) 1893260e9a87SYuri Pankov mandoc_msg(MANDOCERR_AN_MISSING, mdoc->parse, 1894260e9a87SYuri Pankov mdoc->last->line, mdoc->last->pos, NULL); 1895260e9a87SYuri Pankov } 1896260e9a87SYuri Pankov 1897260e9a87SYuri Pankov static void 189895c635efSGarrett D'Amore post_sh_head(POST_ARGS) 189995c635efSGarrett D'Amore { 1900*a40ea1a7SYuri Pankov struct roff_node *nch; 1901*a40ea1a7SYuri Pankov const char *goodsec; 1902*a40ea1a7SYuri Pankov enum roff_sec sec; 190395c635efSGarrett D'Amore 190495c635efSGarrett D'Amore /* 190595c635efSGarrett D'Amore * Process a new section. Sections are either "named" or 190695c635efSGarrett D'Amore * "custom". Custom sections are user-defined, while named ones 190795c635efSGarrett D'Amore * follow a conventional order and may only appear in certain 190895c635efSGarrett D'Amore * manual sections. 190995c635efSGarrett D'Amore */ 191095c635efSGarrett D'Amore 1911371584c2SYuri Pankov sec = mdoc->last->sec; 191295c635efSGarrett D'Amore 191395c635efSGarrett D'Amore /* The NAME should be first. */ 191495c635efSGarrett D'Amore 1915*a40ea1a7SYuri Pankov if (sec != SEC_NAME && mdoc->lastnamed == SEC_NONE) 1916260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_NAMESEC_FIRST, mdoc->parse, 1917*a40ea1a7SYuri Pankov mdoc->last->line, mdoc->last->pos, "Sh %s", 1918*a40ea1a7SYuri Pankov sec != SEC_CUSTOM ? secnames[sec] : 1919*a40ea1a7SYuri Pankov (nch = mdoc->last->child) == NULL ? "" : 1920*a40ea1a7SYuri Pankov nch->type == ROFFT_TEXT ? nch->string : 1921*a40ea1a7SYuri Pankov mdoc_macronames[nch->tok]); 192295c635efSGarrett D'Amore 192395c635efSGarrett D'Amore /* The SYNOPSIS gets special attention in other areas. */ 192495c635efSGarrett D'Amore 1925371584c2SYuri Pankov if (sec == SEC_SYNOPSIS) { 1926698f87a4SGarrett D'Amore roff_setreg(mdoc->roff, "nS", 1, '='); 192795c635efSGarrett D'Amore mdoc->flags |= MDOC_SYNOPSIS; 1928698f87a4SGarrett D'Amore } else { 1929698f87a4SGarrett D'Amore roff_setreg(mdoc->roff, "nS", 0, '='); 193095c635efSGarrett D'Amore mdoc->flags &= ~MDOC_SYNOPSIS; 1931698f87a4SGarrett D'Amore } 193295c635efSGarrett D'Amore 193395c635efSGarrett D'Amore /* Mark our last section. */ 193495c635efSGarrett D'Amore 193595c635efSGarrett D'Amore mdoc->lastsec = sec; 193695c635efSGarrett D'Amore 193795c635efSGarrett D'Amore /* We don't care about custom sections after this. */ 193895c635efSGarrett D'Amore 1939371584c2SYuri Pankov if (sec == SEC_CUSTOM) 1940260e9a87SYuri Pankov return; 194195c635efSGarrett D'Amore 194295c635efSGarrett D'Amore /* 194395c635efSGarrett D'Amore * Check whether our non-custom section is being repeated or is 194495c635efSGarrett D'Amore * out of order. 194595c635efSGarrett D'Amore */ 194695c635efSGarrett D'Amore 194795c635efSGarrett D'Amore if (sec == mdoc->lastnamed) 1948260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_SEC_REP, mdoc->parse, 1949260e9a87SYuri Pankov mdoc->last->line, mdoc->last->pos, 1950371584c2SYuri Pankov "Sh %s", secnames[sec]); 195195c635efSGarrett D'Amore 195295c635efSGarrett D'Amore if (sec < mdoc->lastnamed) 1953260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_SEC_ORDER, mdoc->parse, 1954260e9a87SYuri Pankov mdoc->last->line, mdoc->last->pos, 1955371584c2SYuri Pankov "Sh %s", secnames[sec]); 195695c635efSGarrett D'Amore 195795c635efSGarrett D'Amore /* Mark the last named section. */ 195895c635efSGarrett D'Amore 195995c635efSGarrett D'Amore mdoc->lastnamed = sec; 196095c635efSGarrett D'Amore 196195c635efSGarrett D'Amore /* Check particular section/manual conventions. */ 196295c635efSGarrett D'Amore 1963371584c2SYuri Pankov if (mdoc->meta.msec == NULL) 1964260e9a87SYuri Pankov return; 196595c635efSGarrett D'Amore 1966260e9a87SYuri Pankov goodsec = NULL; 196795c635efSGarrett D'Amore switch (sec) { 1968260e9a87SYuri Pankov case SEC_ERRORS: 1969260e9a87SYuri Pankov if (*mdoc->meta.msec == '4') 1970260e9a87SYuri Pankov break; 1971260e9a87SYuri Pankov goodsec = "2, 3, 4, 9"; 197295c635efSGarrett D'Amore /* FALLTHROUGH */ 1973260e9a87SYuri Pankov case SEC_RETURN_VALUES: 1974260e9a87SYuri Pankov case SEC_LIBRARY: 197595c635efSGarrett D'Amore if (*mdoc->meta.msec == '2') 197695c635efSGarrett D'Amore break; 197795c635efSGarrett D'Amore if (*mdoc->meta.msec == '3') 197895c635efSGarrett D'Amore break; 1979260e9a87SYuri Pankov if (NULL == goodsec) 1980260e9a87SYuri Pankov goodsec = "2, 3, 9"; 1981260e9a87SYuri Pankov /* FALLTHROUGH */ 1982260e9a87SYuri Pankov case SEC_CONTEXT: 198395c635efSGarrett D'Amore if (*mdoc->meta.msec == '9') 198495c635efSGarrett D'Amore break; 1985260e9a87SYuri Pankov if (NULL == goodsec) 1986260e9a87SYuri Pankov goodsec = "9"; 1987260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_SEC_MSEC, mdoc->parse, 1988260e9a87SYuri Pankov mdoc->last->line, mdoc->last->pos, 1989371584c2SYuri Pankov "Sh %s for %s only", secnames[sec], goodsec); 199095c635efSGarrett D'Amore break; 199195c635efSGarrett D'Amore default: 199295c635efSGarrett D'Amore break; 199395c635efSGarrett D'Amore } 199495c635efSGarrett D'Amore } 199595c635efSGarrett D'Amore 1996*a40ea1a7SYuri Pankov static void 1997*a40ea1a7SYuri Pankov post_xr(POST_ARGS) 1998*a40ea1a7SYuri Pankov { 1999*a40ea1a7SYuri Pankov struct roff_node *n, *nch; 2000*a40ea1a7SYuri Pankov 2001*a40ea1a7SYuri Pankov n = mdoc->last; 2002*a40ea1a7SYuri Pankov nch = n->child; 2003*a40ea1a7SYuri Pankov if (nch->next == NULL) { 2004*a40ea1a7SYuri Pankov mandoc_vmsg(MANDOCERR_XR_NOSEC, mdoc->parse, 2005*a40ea1a7SYuri Pankov n->line, n->pos, "Xr %s", nch->string); 2006*a40ea1a7SYuri Pankov return; 2007*a40ea1a7SYuri Pankov } 2008*a40ea1a7SYuri Pankov assert(nch->next == n->last); 2009*a40ea1a7SYuri Pankov } 2010*a40ea1a7SYuri Pankov 2011260e9a87SYuri Pankov static void 201295c635efSGarrett D'Amore post_ignpar(POST_ARGS) 201395c635efSGarrett D'Amore { 2014371584c2SYuri Pankov struct roff_node *np; 201595c635efSGarrett D'Amore 2016260e9a87SYuri Pankov switch (mdoc->last->type) { 2017371584c2SYuri Pankov case ROFFT_HEAD: 2018260e9a87SYuri Pankov post_hyph(mdoc); 2019260e9a87SYuri Pankov return; 2020371584c2SYuri Pankov case ROFFT_BODY: 2021260e9a87SYuri Pankov break; 2022260e9a87SYuri Pankov default: 2023260e9a87SYuri Pankov return; 2024260e9a87SYuri Pankov } 202595c635efSGarrett D'Amore 2026371584c2SYuri Pankov if ((np = mdoc->last->child) != NULL) 2027371584c2SYuri Pankov if (np->tok == MDOC_Pp || np->tok == MDOC_Lp) { 2028260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_PAR_SKIP, 2029260e9a87SYuri Pankov mdoc->parse, np->line, np->pos, 2030260e9a87SYuri Pankov "%s after %s", mdoc_macronames[np->tok], 2031260e9a87SYuri Pankov mdoc_macronames[mdoc->last->tok]); 2032371584c2SYuri Pankov roff_node_delete(mdoc, np); 203395c635efSGarrett D'Amore } 203495c635efSGarrett D'Amore 2035371584c2SYuri Pankov if ((np = mdoc->last->last) != NULL) 2036371584c2SYuri Pankov if (np->tok == MDOC_Pp || np->tok == MDOC_Lp) { 2037260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse, 2038260e9a87SYuri Pankov np->line, np->pos, "%s at the end of %s", 2039260e9a87SYuri Pankov mdoc_macronames[np->tok], 2040260e9a87SYuri Pankov mdoc_macronames[mdoc->last->tok]); 2041371584c2SYuri Pankov roff_node_delete(mdoc, np); 204295c635efSGarrett D'Amore } 204395c635efSGarrett D'Amore } 204495c635efSGarrett D'Amore 2045260e9a87SYuri Pankov static void 2046371584c2SYuri Pankov post_prevpar(POST_ARGS) 204795c635efSGarrett D'Amore { 2048371584c2SYuri Pankov struct roff_node *n; 204995c635efSGarrett D'Amore 2050371584c2SYuri Pankov n = mdoc->last; 2051371584c2SYuri Pankov if (NULL == n->prev) 2052260e9a87SYuri Pankov return; 2053371584c2SYuri Pankov if (n->type != ROFFT_ELEM && n->type != ROFFT_BLOCK) 2054260e9a87SYuri Pankov return; 205595c635efSGarrett D'Amore 2056260e9a87SYuri Pankov /* 205795c635efSGarrett D'Amore * Don't allow prior `Lp' or `Pp' prior to a paragraph-type 205895c635efSGarrett D'Amore * block: `Lp', `Pp', or non-compact `Bd' or `Bl'. 205995c635efSGarrett D'Amore */ 206095c635efSGarrett D'Amore 2061371584c2SYuri Pankov if (n->prev->tok != MDOC_Pp && 2062371584c2SYuri Pankov n->prev->tok != MDOC_Lp && 2063371584c2SYuri Pankov n->prev->tok != MDOC_br) 2064260e9a87SYuri Pankov return; 2065371584c2SYuri Pankov if (n->tok == MDOC_Bl && n->norm->Bl.comp) 2066260e9a87SYuri Pankov return; 2067371584c2SYuri Pankov if (n->tok == MDOC_Bd && n->norm->Bd.comp) 2068260e9a87SYuri Pankov return; 2069371584c2SYuri Pankov if (n->tok == MDOC_It && n->parent->norm->Bl.comp) 2070260e9a87SYuri Pankov return; 207195c635efSGarrett D'Amore 2072260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse, 2073371584c2SYuri Pankov n->prev->line, n->prev->pos, 2074371584c2SYuri Pankov "%s before %s", mdoc_macronames[n->prev->tok], 2075260e9a87SYuri Pankov mdoc_macronames[n->tok]); 2076371584c2SYuri Pankov roff_node_delete(mdoc, n->prev); 207795c635efSGarrett D'Amore } 207895c635efSGarrett D'Amore 2079260e9a87SYuri Pankov static void 2080698f87a4SGarrett D'Amore post_par(POST_ARGS) 2081698f87a4SGarrett D'Amore { 2082371584c2SYuri Pankov struct roff_node *np; 2083698f87a4SGarrett D'Amore 2084260e9a87SYuri Pankov np = mdoc->last; 2085371584c2SYuri Pankov if (np->tok != MDOC_br && np->tok != MDOC_sp) 2086371584c2SYuri Pankov post_prevpar(mdoc); 2087698f87a4SGarrett D'Amore 2088260e9a87SYuri Pankov if (np->tok == MDOC_sp) { 2089371584c2SYuri Pankov if (np->child != NULL && np->child->next != NULL) 2090260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse, 2091260e9a87SYuri Pankov np->child->next->line, np->child->next->pos, 2092260e9a87SYuri Pankov "sp ... %s", np->child->next->string); 2093260e9a87SYuri Pankov } else if (np->child != NULL) 2094260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_ARG_SKIP, 2095260e9a87SYuri Pankov mdoc->parse, np->line, np->pos, "%s %s", 2096260e9a87SYuri Pankov mdoc_macronames[np->tok], np->child->string); 2097260e9a87SYuri Pankov 2098371584c2SYuri Pankov if ((np = mdoc->last->prev) == NULL) { 2099260e9a87SYuri Pankov np = mdoc->last->parent; 2100371584c2SYuri Pankov if (np->tok != MDOC_Sh && np->tok != MDOC_Ss) 2101260e9a87SYuri Pankov return; 2102371584c2SYuri Pankov } else if (np->tok != MDOC_Pp && np->tok != MDOC_Lp && 2103371584c2SYuri Pankov (mdoc->last->tok != MDOC_br || 2104371584c2SYuri Pankov (np->tok != MDOC_sp && np->tok != MDOC_br))) 2105260e9a87SYuri Pankov return; 2106698f87a4SGarrett D'Amore 2107260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse, 2108260e9a87SYuri Pankov mdoc->last->line, mdoc->last->pos, 2109260e9a87SYuri Pankov "%s after %s", mdoc_macronames[mdoc->last->tok], 2110260e9a87SYuri Pankov mdoc_macronames[np->tok]); 2111371584c2SYuri Pankov roff_node_delete(mdoc, mdoc->last); 211295c635efSGarrett D'Amore } 211395c635efSGarrett D'Amore 2114260e9a87SYuri Pankov static void 211595c635efSGarrett D'Amore post_dd(POST_ARGS) 211695c635efSGarrett D'Amore { 2117371584c2SYuri Pankov struct roff_node *n; 2118260e9a87SYuri Pankov char *datestr; 211995c635efSGarrett D'Amore 2120371584c2SYuri Pankov n = mdoc->last; 2121*a40ea1a7SYuri Pankov n->flags |= NODE_NOPRT; 2122*a40ea1a7SYuri Pankov 2123371584c2SYuri Pankov if (mdoc->meta.date != NULL) { 2124371584c2SYuri Pankov mandoc_msg(MANDOCERR_PROLOG_REP, mdoc->parse, 2125371584c2SYuri Pankov n->line, n->pos, "Dd"); 212695c635efSGarrett D'Amore free(mdoc->meta.date); 2127371584c2SYuri Pankov } else if (mdoc->flags & MDOC_PBODY) 2128371584c2SYuri Pankov mandoc_msg(MANDOCERR_PROLOG_LATE, mdoc->parse, 2129371584c2SYuri Pankov n->line, n->pos, "Dd"); 2130371584c2SYuri Pankov else if (mdoc->meta.title != NULL) 2131371584c2SYuri Pankov mandoc_msg(MANDOCERR_PROLOG_ORDER, mdoc->parse, 2132371584c2SYuri Pankov n->line, n->pos, "Dd after Dt"); 2133371584c2SYuri Pankov else if (mdoc->meta.os != NULL) 2134371584c2SYuri Pankov mandoc_msg(MANDOCERR_PROLOG_ORDER, mdoc->parse, 2135371584c2SYuri Pankov n->line, n->pos, "Dd after Os"); 213695c635efSGarrett D'Amore 2137371584c2SYuri Pankov if (n->child == NULL || n->child->string[0] == '\0') { 2138260e9a87SYuri Pankov mdoc->meta.date = mdoc->quick ? mandoc_strdup("") : 2139260e9a87SYuri Pankov mandoc_normdate(mdoc->parse, NULL, n->line, n->pos); 2140*a40ea1a7SYuri Pankov return; 214195c635efSGarrett D'Amore } 214295c635efSGarrett D'Amore 2143260e9a87SYuri Pankov datestr = NULL; 2144371584c2SYuri Pankov deroff(&datestr, n); 2145260e9a87SYuri Pankov if (mdoc->quick) 2146260e9a87SYuri Pankov mdoc->meta.date = datestr; 2147260e9a87SYuri Pankov else { 2148260e9a87SYuri Pankov mdoc->meta.date = mandoc_normdate(mdoc->parse, 2149260e9a87SYuri Pankov datestr, n->line, n->pos); 2150260e9a87SYuri Pankov free(datestr); 215195c635efSGarrett D'Amore } 215295c635efSGarrett D'Amore } 215395c635efSGarrett D'Amore 2154260e9a87SYuri Pankov static void 215595c635efSGarrett D'Amore post_dt(POST_ARGS) 215695c635efSGarrett D'Amore { 2157371584c2SYuri Pankov struct roff_node *nn, *n; 215895c635efSGarrett D'Amore const char *cp; 215995c635efSGarrett D'Amore char *p; 216095c635efSGarrett D'Amore 216195c635efSGarrett D'Amore n = mdoc->last; 2162*a40ea1a7SYuri Pankov n->flags |= NODE_NOPRT; 2163*a40ea1a7SYuri Pankov 2164371584c2SYuri Pankov if (mdoc->flags & MDOC_PBODY) { 2165371584c2SYuri Pankov mandoc_msg(MANDOCERR_DT_LATE, mdoc->parse, 2166371584c2SYuri Pankov n->line, n->pos, "Dt"); 2167*a40ea1a7SYuri Pankov return; 2168371584c2SYuri Pankov } 2169371584c2SYuri Pankov 2170371584c2SYuri Pankov if (mdoc->meta.title != NULL) 2171371584c2SYuri Pankov mandoc_msg(MANDOCERR_PROLOG_REP, mdoc->parse, 2172371584c2SYuri Pankov n->line, n->pos, "Dt"); 2173371584c2SYuri Pankov else if (mdoc->meta.os != NULL) 2174371584c2SYuri Pankov mandoc_msg(MANDOCERR_PROLOG_ORDER, mdoc->parse, 2175371584c2SYuri Pankov n->line, n->pos, "Dt after Os"); 217695c635efSGarrett D'Amore 2177260e9a87SYuri Pankov free(mdoc->meta.title); 2178260e9a87SYuri Pankov free(mdoc->meta.msec); 2179260e9a87SYuri Pankov free(mdoc->meta.vol); 2180260e9a87SYuri Pankov free(mdoc->meta.arch); 218195c635efSGarrett D'Amore 2182260e9a87SYuri Pankov mdoc->meta.title = NULL; 2183260e9a87SYuri Pankov mdoc->meta.msec = NULL; 2184260e9a87SYuri Pankov mdoc->meta.vol = NULL; 2185260e9a87SYuri Pankov mdoc->meta.arch = NULL; 218695c635efSGarrett D'Amore 2187260e9a87SYuri Pankov /* Mandatory first argument: title. */ 218895c635efSGarrett D'Amore 2189260e9a87SYuri Pankov nn = n->child; 2190260e9a87SYuri Pankov if (nn == NULL || *nn->string == '\0') { 2191260e9a87SYuri Pankov mandoc_msg(MANDOCERR_DT_NOTITLE, 2192260e9a87SYuri Pankov mdoc->parse, n->line, n->pos, "Dt"); 2193260e9a87SYuri Pankov mdoc->meta.title = mandoc_strdup("UNTITLED"); 2194260e9a87SYuri Pankov } else { 2195260e9a87SYuri Pankov mdoc->meta.title = mandoc_strdup(nn->string); 219695c635efSGarrett D'Amore 2197260e9a87SYuri Pankov /* Check that all characters are uppercase. */ 219895c635efSGarrett D'Amore 2199260e9a87SYuri Pankov for (p = nn->string; *p != '\0'; p++) 2200260e9a87SYuri Pankov if (islower((unsigned char)*p)) { 2201260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_TITLE_CASE, 2202260e9a87SYuri Pankov mdoc->parse, nn->line, 2203260e9a87SYuri Pankov nn->pos + (p - nn->string), 2204260e9a87SYuri Pankov "Dt %s", nn->string); 2205260e9a87SYuri Pankov break; 2206260e9a87SYuri Pankov } 220795c635efSGarrett D'Amore } 220895c635efSGarrett D'Amore 2209*a40ea1a7SYuri Pankov /* Mandatory second argument: section. */ 221095c635efSGarrett D'Amore 2211260e9a87SYuri Pankov if (nn != NULL) 2212260e9a87SYuri Pankov nn = nn->next; 221395c635efSGarrett D'Amore 2214260e9a87SYuri Pankov if (nn == NULL) { 2215260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_MSEC_MISSING, 2216260e9a87SYuri Pankov mdoc->parse, n->line, n->pos, 2217260e9a87SYuri Pankov "Dt %s", mdoc->meta.title); 221895c635efSGarrett D'Amore mdoc->meta.vol = mandoc_strdup("LOCAL"); 2219*a40ea1a7SYuri Pankov return; /* msec and arch remain NULL. */ 222095c635efSGarrett D'Amore } 222195c635efSGarrett D'Amore 2222260e9a87SYuri Pankov mdoc->meta.msec = mandoc_strdup(nn->string); 2223260e9a87SYuri Pankov 2224260e9a87SYuri Pankov /* Infer volume title from section number. */ 222595c635efSGarrett D'Amore 222695c635efSGarrett D'Amore cp = mandoc_a2msec(nn->string); 2227260e9a87SYuri Pankov if (cp == NULL) { 2228260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_MSEC_BAD, mdoc->parse, 2229260e9a87SYuri Pankov nn->line, nn->pos, "Dt ... %s", nn->string); 223095c635efSGarrett D'Amore mdoc->meta.vol = mandoc_strdup(nn->string); 2231260e9a87SYuri Pankov } else 2232260e9a87SYuri Pankov mdoc->meta.vol = mandoc_strdup(cp); 223395c635efSGarrett D'Amore 2234260e9a87SYuri Pankov /* Optional third argument: architecture. */ 223595c635efSGarrett D'Amore 2236260e9a87SYuri Pankov if ((nn = nn->next) == NULL) 2237*a40ea1a7SYuri Pankov return; 223895c635efSGarrett D'Amore 2239260e9a87SYuri Pankov for (p = nn->string; *p != '\0'; p++) 2240260e9a87SYuri Pankov *p = tolower((unsigned char)*p); 2241260e9a87SYuri Pankov mdoc->meta.arch = mandoc_strdup(nn->string); 224295c635efSGarrett D'Amore 2243260e9a87SYuri Pankov /* Ignore fourth and later arguments. */ 224495c635efSGarrett D'Amore 2245260e9a87SYuri Pankov if ((nn = nn->next) != NULL) 2246260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse, 2247260e9a87SYuri Pankov nn->line, nn->pos, "Dt ... %s", nn->string); 224895c635efSGarrett D'Amore } 224995c635efSGarrett D'Amore 2250260e9a87SYuri Pankov static void 225195c635efSGarrett D'Amore post_bx(POST_ARGS) 225295c635efSGarrett D'Amore { 2253*a40ea1a7SYuri Pankov struct roff_node *n, *nch; 2254*a40ea1a7SYuri Pankov 2255*a40ea1a7SYuri Pankov n = mdoc->last; 2256*a40ea1a7SYuri Pankov nch = n->child; 2257*a40ea1a7SYuri Pankov 2258*a40ea1a7SYuri Pankov if (nch != NULL) { 2259*a40ea1a7SYuri Pankov mdoc->last = nch; 2260*a40ea1a7SYuri Pankov nch = nch->next; 2261*a40ea1a7SYuri Pankov mdoc->next = ROFF_NEXT_SIBLING; 2262*a40ea1a7SYuri Pankov roff_elem_alloc(mdoc, n->line, n->pos, MDOC_Ns); 2263*a40ea1a7SYuri Pankov mdoc->last->flags |= NODE_NOSRC; 2264*a40ea1a7SYuri Pankov mdoc->next = ROFF_NEXT_SIBLING; 2265*a40ea1a7SYuri Pankov } else 2266*a40ea1a7SYuri Pankov mdoc->next = ROFF_NEXT_CHILD; 2267*a40ea1a7SYuri Pankov roff_word_alloc(mdoc, n->line, n->pos, "BSD"); 2268*a40ea1a7SYuri Pankov mdoc->last->flags |= NODE_NOSRC; 2269*a40ea1a7SYuri Pankov 2270*a40ea1a7SYuri Pankov if (nch == NULL) { 2271*a40ea1a7SYuri Pankov mdoc->last = n; 2272*a40ea1a7SYuri Pankov return; 2273*a40ea1a7SYuri Pankov } 2274*a40ea1a7SYuri Pankov 2275*a40ea1a7SYuri Pankov roff_elem_alloc(mdoc, n->line, n->pos, MDOC_Ns); 2276*a40ea1a7SYuri Pankov mdoc->last->flags |= NODE_NOSRC; 2277*a40ea1a7SYuri Pankov mdoc->next = ROFF_NEXT_SIBLING; 2278*a40ea1a7SYuri Pankov roff_word_alloc(mdoc, n->line, n->pos, "-"); 2279*a40ea1a7SYuri Pankov mdoc->last->flags |= NODE_NOSRC; 2280*a40ea1a7SYuri Pankov roff_elem_alloc(mdoc, n->line, n->pos, MDOC_Ns); 2281*a40ea1a7SYuri Pankov mdoc->last->flags |= NODE_NOSRC; 2282*a40ea1a7SYuri Pankov mdoc->last = n; 228395c635efSGarrett D'Amore 2284260e9a87SYuri Pankov /* 228595c635efSGarrett D'Amore * Make `Bx's second argument always start with an uppercase 228695c635efSGarrett D'Amore * letter. Groff checks if it's an "accepted" term, but we just 228795c635efSGarrett D'Amore * uppercase blindly. 228895c635efSGarrett D'Amore */ 228995c635efSGarrett D'Amore 2290*a40ea1a7SYuri Pankov *nch->string = (char)toupper((unsigned char)*nch->string); 229195c635efSGarrett D'Amore } 229295c635efSGarrett D'Amore 2293260e9a87SYuri Pankov static void 229495c635efSGarrett D'Amore post_os(POST_ARGS) 229595c635efSGarrett D'Amore { 229695c635efSGarrett D'Amore #ifndef OSNAME 229795c635efSGarrett D'Amore struct utsname utsname; 2298260e9a87SYuri Pankov static char *defbuf; 229995c635efSGarrett D'Amore #endif 2300371584c2SYuri Pankov struct roff_node *n; 230195c635efSGarrett D'Amore 230295c635efSGarrett D'Amore n = mdoc->last; 2303*a40ea1a7SYuri Pankov n->flags |= NODE_NOPRT; 2304*a40ea1a7SYuri Pankov 2305371584c2SYuri Pankov if (mdoc->meta.os != NULL) 2306371584c2SYuri Pankov mandoc_msg(MANDOCERR_PROLOG_REP, mdoc->parse, 2307371584c2SYuri Pankov n->line, n->pos, "Os"); 2308371584c2SYuri Pankov else if (mdoc->flags & MDOC_PBODY) 2309371584c2SYuri Pankov mandoc_msg(MANDOCERR_PROLOG_LATE, mdoc->parse, 2310371584c2SYuri Pankov n->line, n->pos, "Os"); 231195c635efSGarrett D'Amore 231295c635efSGarrett D'Amore /* 2313698f87a4SGarrett D'Amore * Set the operating system by way of the `Os' macro. 2314698f87a4SGarrett D'Amore * The order of precedence is: 2315698f87a4SGarrett D'Amore * 1. the argument of the `Os' macro, unless empty 2316698f87a4SGarrett D'Amore * 2. the -Ios=foo command line argument, if provided 2317698f87a4SGarrett D'Amore * 3. -DOSNAME="\"foo\"", if provided during compilation 2318698f87a4SGarrett D'Amore * 4. "sysname release" from uname(3) 2319260e9a87SYuri Pankov */ 232095c635efSGarrett D'Amore 2321698f87a4SGarrett D'Amore free(mdoc->meta.os); 2322260e9a87SYuri Pankov mdoc->meta.os = NULL; 2323371584c2SYuri Pankov deroff(&mdoc->meta.os, n); 2324260e9a87SYuri Pankov if (mdoc->meta.os) 2325*a40ea1a7SYuri Pankov return; 232695c635efSGarrett D'Amore 2327260e9a87SYuri Pankov if (mdoc->defos) { 2328260e9a87SYuri Pankov mdoc->meta.os = mandoc_strdup(mdoc->defos); 2329*a40ea1a7SYuri Pankov return; 233095c635efSGarrett D'Amore } 233195c635efSGarrett D'Amore 233295c635efSGarrett D'Amore #ifdef OSNAME 2333260e9a87SYuri Pankov mdoc->meta.os = mandoc_strdup(OSNAME); 233495c635efSGarrett D'Amore #else /*!OSNAME */ 2335371584c2SYuri Pankov if (defbuf == NULL) { 2336371584c2SYuri Pankov if (uname(&utsname) == -1) { 2337260e9a87SYuri Pankov mandoc_msg(MANDOCERR_OS_UNAME, mdoc->parse, 2338260e9a87SYuri Pankov n->line, n->pos, "Os"); 2339260e9a87SYuri Pankov defbuf = mandoc_strdup("UNKNOWN"); 2340260e9a87SYuri Pankov } else 2341260e9a87SYuri Pankov mandoc_asprintf(&defbuf, "%s %s", 2342260e9a87SYuri Pankov utsname.sysname, utsname.release); 234395c635efSGarrett D'Amore } 2344260e9a87SYuri Pankov mdoc->meta.os = mandoc_strdup(defbuf); 2345260e9a87SYuri Pankov #endif /*!OSNAME*/ 234695c635efSGarrett D'Amore } 234795c635efSGarrett D'Amore 2348371584c2SYuri Pankov enum roff_sec 2349371584c2SYuri Pankov mdoc_a2sec(const char *p) 235095c635efSGarrett D'Amore { 235195c635efSGarrett D'Amore int i; 235295c635efSGarrett D'Amore 2353260e9a87SYuri Pankov for (i = 0; i < (int)SEC__MAX; i++) 235495c635efSGarrett D'Amore if (secnames[i] && 0 == strcmp(p, secnames[i])) 2355371584c2SYuri Pankov return (enum roff_sec)i; 235695c635efSGarrett D'Amore 2357371584c2SYuri Pankov return SEC_CUSTOM; 235895c635efSGarrett D'Amore } 235995c635efSGarrett D'Amore 236095c635efSGarrett D'Amore static size_t 2361371584c2SYuri Pankov macro2len(int macro) 236295c635efSGarrett D'Amore { 236395c635efSGarrett D'Amore 236495c635efSGarrett D'Amore switch (macro) { 2365260e9a87SYuri Pankov case MDOC_Ad: 2366371584c2SYuri Pankov return 12; 2367260e9a87SYuri Pankov case MDOC_Ao: 2368371584c2SYuri Pankov return 12; 2369260e9a87SYuri Pankov case MDOC_An: 2370371584c2SYuri Pankov return 12; 2371260e9a87SYuri Pankov case MDOC_Aq: 2372371584c2SYuri Pankov return 12; 2373260e9a87SYuri Pankov case MDOC_Ar: 2374371584c2SYuri Pankov return 12; 2375260e9a87SYuri Pankov case MDOC_Bo: 2376371584c2SYuri Pankov return 12; 2377260e9a87SYuri Pankov case MDOC_Bq: 2378371584c2SYuri Pankov return 12; 2379260e9a87SYuri Pankov case MDOC_Cd: 2380371584c2SYuri Pankov return 12; 2381260e9a87SYuri Pankov case MDOC_Cm: 2382371584c2SYuri Pankov return 10; 2383260e9a87SYuri Pankov case MDOC_Do: 2384371584c2SYuri Pankov return 10; 2385260e9a87SYuri Pankov case MDOC_Dq: 2386371584c2SYuri Pankov return 12; 2387260e9a87SYuri Pankov case MDOC_Dv: 2388371584c2SYuri Pankov return 12; 2389260e9a87SYuri Pankov case MDOC_Eo: 2390371584c2SYuri Pankov return 12; 2391260e9a87SYuri Pankov case MDOC_Em: 2392371584c2SYuri Pankov return 10; 2393260e9a87SYuri Pankov case MDOC_Er: 2394371584c2SYuri Pankov return 17; 2395260e9a87SYuri Pankov case MDOC_Ev: 2396371584c2SYuri Pankov return 15; 2397260e9a87SYuri Pankov case MDOC_Fa: 2398371584c2SYuri Pankov return 12; 2399260e9a87SYuri Pankov case MDOC_Fl: 2400371584c2SYuri Pankov return 10; 2401260e9a87SYuri Pankov case MDOC_Fo: 2402371584c2SYuri Pankov return 16; 2403260e9a87SYuri Pankov case MDOC_Fn: 2404371584c2SYuri Pankov return 16; 2405260e9a87SYuri Pankov case MDOC_Ic: 2406371584c2SYuri Pankov return 10; 2407260e9a87SYuri Pankov case MDOC_Li: 2408371584c2SYuri Pankov return 16; 2409260e9a87SYuri Pankov case MDOC_Ms: 2410371584c2SYuri Pankov return 6; 2411260e9a87SYuri Pankov case MDOC_Nm: 2412371584c2SYuri Pankov return 10; 2413260e9a87SYuri Pankov case MDOC_No: 2414371584c2SYuri Pankov return 12; 2415260e9a87SYuri Pankov case MDOC_Oo: 2416371584c2SYuri Pankov return 10; 2417260e9a87SYuri Pankov case MDOC_Op: 2418371584c2SYuri Pankov return 14; 2419260e9a87SYuri Pankov case MDOC_Pa: 2420371584c2SYuri Pankov return 32; 2421260e9a87SYuri Pankov case MDOC_Pf: 2422371584c2SYuri Pankov return 12; 2423260e9a87SYuri Pankov case MDOC_Po: 2424371584c2SYuri Pankov return 12; 2425260e9a87SYuri Pankov case MDOC_Pq: 2426371584c2SYuri Pankov return 12; 2427260e9a87SYuri Pankov case MDOC_Ql: 2428371584c2SYuri Pankov return 16; 2429260e9a87SYuri Pankov case MDOC_Qo: 2430371584c2SYuri Pankov return 12; 2431260e9a87SYuri Pankov case MDOC_So: 2432371584c2SYuri Pankov return 12; 2433260e9a87SYuri Pankov case MDOC_Sq: 2434371584c2SYuri Pankov return 12; 2435260e9a87SYuri Pankov case MDOC_Sy: 2436371584c2SYuri Pankov return 6; 2437260e9a87SYuri Pankov case MDOC_Sx: 2438371584c2SYuri Pankov return 16; 2439260e9a87SYuri Pankov case MDOC_Tn: 2440371584c2SYuri Pankov return 10; 2441260e9a87SYuri Pankov case MDOC_Va: 2442371584c2SYuri Pankov return 12; 2443260e9a87SYuri Pankov case MDOC_Vt: 2444371584c2SYuri Pankov return 12; 2445260e9a87SYuri Pankov case MDOC_Xr: 2446371584c2SYuri Pankov return 10; 244795c635efSGarrett D'Amore default: 244895c635efSGarrett D'Amore break; 244995c635efSGarrett D'Amore }; 2450371584c2SYuri Pankov return 0; 245195c635efSGarrett D'Amore } 2452