1*698f87a4SGarrett D'Amore /* $Id: mdoc_validate.c,v 1.198 2013/12/15 21:23:52 schwarze Exp $ */ 295c635efSGarrett D'Amore /* 3*698f87a4SGarrett D'Amore * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv> 4*698f87a4SGarrett D'Amore * Copyright (c) 2010, 2011, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org> 595c635efSGarrett D'Amore * 695c635efSGarrett D'Amore * Permission to use, copy, modify, and distribute this software for any 795c635efSGarrett D'Amore * purpose with or without fee is hereby granted, provided that the above 895c635efSGarrett D'Amore * copyright notice and this permission notice appear in all copies. 995c635efSGarrett D'Amore * 1095c635efSGarrett D'Amore * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1195c635efSGarrett D'Amore * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1295c635efSGarrett D'Amore * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1395c635efSGarrett D'Amore * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1495c635efSGarrett D'Amore * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1595c635efSGarrett D'Amore * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1695c635efSGarrett D'Amore * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1795c635efSGarrett D'Amore */ 1895c635efSGarrett D'Amore #ifdef HAVE_CONFIG_H 1995c635efSGarrett D'Amore #include "config.h" 2095c635efSGarrett D'Amore #endif 2195c635efSGarrett D'Amore 22*698f87a4SGarrett D'Amore #ifndef OSNAME 2395c635efSGarrett D'Amore #include <sys/utsname.h> 2495c635efSGarrett D'Amore #endif 2595c635efSGarrett D'Amore 2695c635efSGarrett D'Amore #include <sys/types.h> 2795c635efSGarrett D'Amore 2895c635efSGarrett D'Amore #include <assert.h> 2995c635efSGarrett D'Amore #include <ctype.h> 3095c635efSGarrett D'Amore #include <limits.h> 3195c635efSGarrett D'Amore #include <stdio.h> 3295c635efSGarrett D'Amore #include <stdlib.h> 3395c635efSGarrett D'Amore #include <string.h> 3495c635efSGarrett D'Amore #include <time.h> 3595c635efSGarrett D'Amore 3695c635efSGarrett D'Amore #include "mdoc.h" 3795c635efSGarrett D'Amore #include "mandoc.h" 3895c635efSGarrett D'Amore #include "libmdoc.h" 3995c635efSGarrett D'Amore #include "libmandoc.h" 4095c635efSGarrett D'Amore 4195c635efSGarrett D'Amore /* FIXME: .Bl -diag can't have non-text children in HEAD. */ 4295c635efSGarrett D'Amore 4395c635efSGarrett D'Amore #define PRE_ARGS struct mdoc *mdoc, struct mdoc_node *n 4495c635efSGarrett D'Amore #define POST_ARGS struct mdoc *mdoc 4595c635efSGarrett D'Amore 4695c635efSGarrett D'Amore #define NUMSIZ 32 4795c635efSGarrett D'Amore #define DATESIZE 32 4895c635efSGarrett D'Amore 4995c635efSGarrett D'Amore enum check_ineq { 5095c635efSGarrett D'Amore CHECK_LT, 5195c635efSGarrett D'Amore CHECK_GT, 5295c635efSGarrett D'Amore CHECK_EQ 5395c635efSGarrett D'Amore }; 5495c635efSGarrett D'Amore 5595c635efSGarrett D'Amore enum check_lvl { 5695c635efSGarrett D'Amore CHECK_WARN, 5795c635efSGarrett D'Amore CHECK_ERROR, 5895c635efSGarrett D'Amore }; 5995c635efSGarrett D'Amore 6095c635efSGarrett D'Amore typedef int (*v_pre)(PRE_ARGS); 6195c635efSGarrett D'Amore typedef int (*v_post)(POST_ARGS); 6295c635efSGarrett D'Amore 6395c635efSGarrett D'Amore struct valids { 6495c635efSGarrett D'Amore v_pre *pre; 6595c635efSGarrett D'Amore v_post *post; 6695c635efSGarrett D'Amore }; 6795c635efSGarrett D'Amore 6895c635efSGarrett D'Amore static int check_count(struct mdoc *, enum mdoc_type, 6995c635efSGarrett D'Amore enum check_lvl, enum check_ineq, int); 7095c635efSGarrett D'Amore static int check_parent(PRE_ARGS, enum mdoct, enum mdoc_type); 7195c635efSGarrett D'Amore static void check_text(struct mdoc *, int, int, char *); 7295c635efSGarrett D'Amore static void check_argv(struct mdoc *, 7395c635efSGarrett D'Amore struct mdoc_node *, struct mdoc_argv *); 7495c635efSGarrett D'Amore static void check_args(struct mdoc *, struct mdoc_node *); 7595c635efSGarrett D'Amore static int concat(char *, const struct mdoc_node *, size_t); 7695c635efSGarrett D'Amore static enum mdoc_sec a2sec(const char *); 7795c635efSGarrett D'Amore static size_t macro2len(enum mdoct); 7895c635efSGarrett D'Amore 7995c635efSGarrett D'Amore static int ebool(POST_ARGS); 8095c635efSGarrett D'Amore static int berr_ge1(POST_ARGS); 8195c635efSGarrett D'Amore static int bwarn_ge1(POST_ARGS); 8295c635efSGarrett D'Amore static int ewarn_eq0(POST_ARGS); 8395c635efSGarrett D'Amore static int ewarn_eq1(POST_ARGS); 8495c635efSGarrett D'Amore static int ewarn_ge1(POST_ARGS); 8595c635efSGarrett D'Amore static int ewarn_le1(POST_ARGS); 8695c635efSGarrett D'Amore static int hwarn_eq0(POST_ARGS); 8795c635efSGarrett D'Amore static int hwarn_eq1(POST_ARGS); 8895c635efSGarrett D'Amore static int hwarn_ge1(POST_ARGS); 8995c635efSGarrett D'Amore static int hwarn_le1(POST_ARGS); 9095c635efSGarrett D'Amore 9195c635efSGarrett D'Amore static int post_an(POST_ARGS); 9295c635efSGarrett D'Amore static int post_at(POST_ARGS); 9395c635efSGarrett D'Amore static int post_bf(POST_ARGS); 9495c635efSGarrett D'Amore static int post_bl(POST_ARGS); 9595c635efSGarrett D'Amore static int post_bl_block(POST_ARGS); 9695c635efSGarrett D'Amore static int post_bl_block_width(POST_ARGS); 9795c635efSGarrett D'Amore static int post_bl_block_tag(POST_ARGS); 9895c635efSGarrett D'Amore static int post_bl_head(POST_ARGS); 9995c635efSGarrett D'Amore static int post_bx(POST_ARGS); 100*698f87a4SGarrett D'Amore static int post_defaults(POST_ARGS); 10195c635efSGarrett D'Amore static int post_dd(POST_ARGS); 10295c635efSGarrett D'Amore static int post_dt(POST_ARGS); 10395c635efSGarrett D'Amore static int post_eoln(POST_ARGS); 104*698f87a4SGarrett D'Amore static int post_hyph(POST_ARGS); 105*698f87a4SGarrett D'Amore static int post_ignpar(POST_ARGS); 10695c635efSGarrett D'Amore static int post_it(POST_ARGS); 10795c635efSGarrett D'Amore static int post_lb(POST_ARGS); 108*698f87a4SGarrett D'Amore static int post_literal(POST_ARGS); 10995c635efSGarrett D'Amore static int post_nm(POST_ARGS); 11095c635efSGarrett D'Amore static int post_ns(POST_ARGS); 11195c635efSGarrett D'Amore static int post_os(POST_ARGS); 112*698f87a4SGarrett D'Amore static int post_par(POST_ARGS); 11395c635efSGarrett D'Amore static int post_prol(POST_ARGS); 11495c635efSGarrett D'Amore static int post_root(POST_ARGS); 11595c635efSGarrett D'Amore static int post_rs(POST_ARGS); 11695c635efSGarrett D'Amore static int post_sh(POST_ARGS); 11795c635efSGarrett D'Amore static int post_sh_body(POST_ARGS); 11895c635efSGarrett D'Amore static int post_sh_head(POST_ARGS); 11995c635efSGarrett D'Amore static int post_st(POST_ARGS); 12095c635efSGarrett D'Amore static int post_std(POST_ARGS); 12195c635efSGarrett D'Amore static int post_vt(POST_ARGS); 12295c635efSGarrett D'Amore static int pre_an(PRE_ARGS); 12395c635efSGarrett D'Amore static int pre_bd(PRE_ARGS); 12495c635efSGarrett D'Amore static int pre_bl(PRE_ARGS); 12595c635efSGarrett D'Amore static int pre_dd(PRE_ARGS); 12695c635efSGarrett D'Amore static int pre_display(PRE_ARGS); 12795c635efSGarrett D'Amore static int pre_dt(PRE_ARGS); 12895c635efSGarrett D'Amore static int pre_it(PRE_ARGS); 12995c635efSGarrett D'Amore static int pre_literal(PRE_ARGS); 13095c635efSGarrett D'Amore static int pre_os(PRE_ARGS); 13195c635efSGarrett D'Amore static int pre_par(PRE_ARGS); 13295c635efSGarrett D'Amore static int pre_sh(PRE_ARGS); 13395c635efSGarrett D'Amore static int pre_ss(PRE_ARGS); 13495c635efSGarrett D'Amore static int pre_std(PRE_ARGS); 13595c635efSGarrett D'Amore 13695c635efSGarrett D'Amore static v_post posts_an[] = { post_an, NULL }; 13795c635efSGarrett D'Amore static v_post posts_at[] = { post_at, post_defaults, NULL }; 13895c635efSGarrett D'Amore static v_post posts_bd[] = { post_literal, hwarn_eq0, bwarn_ge1, NULL }; 13995c635efSGarrett D'Amore static v_post posts_bf[] = { hwarn_le1, post_bf, NULL }; 14095c635efSGarrett D'Amore static v_post posts_bk[] = { hwarn_eq0, bwarn_ge1, NULL }; 14195c635efSGarrett D'Amore static v_post posts_bl[] = { bwarn_ge1, post_bl, NULL }; 14295c635efSGarrett D'Amore static v_post posts_bx[] = { post_bx, NULL }; 14395c635efSGarrett D'Amore static v_post posts_bool[] = { ebool, NULL }; 14495c635efSGarrett D'Amore static v_post posts_eoln[] = { post_eoln, NULL }; 14595c635efSGarrett D'Amore static v_post posts_defaults[] = { post_defaults, NULL }; 146*698f87a4SGarrett D'Amore static v_post posts_d1[] = { bwarn_ge1, post_hyph, NULL }; 14795c635efSGarrett D'Amore static v_post posts_dd[] = { post_dd, post_prol, NULL }; 14895c635efSGarrett D'Amore static v_post posts_dl[] = { post_literal, bwarn_ge1, NULL }; 14995c635efSGarrett D'Amore static v_post posts_dt[] = { post_dt, post_prol, NULL }; 15095c635efSGarrett D'Amore static v_post posts_fo[] = { hwarn_eq1, bwarn_ge1, NULL }; 151*698f87a4SGarrett D'Amore static v_post posts_hyph[] = { post_hyph, NULL }; 152*698f87a4SGarrett D'Amore static v_post posts_hyphtext[] = { ewarn_ge1, post_hyph, NULL }; 15395c635efSGarrett D'Amore static v_post posts_it[] = { post_it, NULL }; 15495c635efSGarrett D'Amore static v_post posts_lb[] = { post_lb, NULL }; 155*698f87a4SGarrett D'Amore static v_post posts_nd[] = { berr_ge1, post_hyph, NULL }; 15695c635efSGarrett D'Amore static v_post posts_nm[] = { post_nm, NULL }; 15795c635efSGarrett D'Amore static v_post posts_notext[] = { ewarn_eq0, NULL }; 15895c635efSGarrett D'Amore static v_post posts_ns[] = { post_ns, NULL }; 15995c635efSGarrett D'Amore static v_post posts_os[] = { post_os, post_prol, NULL }; 160*698f87a4SGarrett D'Amore static v_post posts_pp[] = { post_par, ewarn_eq0, NULL }; 16195c635efSGarrett D'Amore static v_post posts_rs[] = { post_rs, NULL }; 162*698f87a4SGarrett D'Amore static v_post posts_sh[] = { post_ignpar,hwarn_ge1,post_sh,post_hyph,NULL }; 163*698f87a4SGarrett D'Amore static v_post posts_sp[] = { post_par, ewarn_le1, NULL }; 164*698f87a4SGarrett D'Amore static v_post posts_ss[] = { post_ignpar, hwarn_ge1, post_hyph, NULL }; 16595c635efSGarrett D'Amore static v_post posts_st[] = { post_st, NULL }; 16695c635efSGarrett D'Amore static v_post posts_std[] = { post_std, NULL }; 16795c635efSGarrett D'Amore static v_post posts_text[] = { ewarn_ge1, NULL }; 16895c635efSGarrett D'Amore static v_post posts_text1[] = { ewarn_eq1, NULL }; 16995c635efSGarrett D'Amore static v_post posts_vt[] = { post_vt, NULL }; 17095c635efSGarrett D'Amore static v_pre pres_an[] = { pre_an, NULL }; 17195c635efSGarrett D'Amore static v_pre pres_bd[] = { pre_display, pre_bd, pre_literal, pre_par, NULL }; 17295c635efSGarrett D'Amore static v_pre pres_bl[] = { pre_bl, pre_par, NULL }; 17395c635efSGarrett D'Amore static v_pre pres_d1[] = { pre_display, NULL }; 17495c635efSGarrett D'Amore static v_pre pres_dl[] = { pre_literal, pre_display, NULL }; 17595c635efSGarrett D'Amore static v_pre pres_dd[] = { pre_dd, NULL }; 17695c635efSGarrett D'Amore static v_pre pres_dt[] = { pre_dt, NULL }; 17795c635efSGarrett D'Amore static v_pre pres_it[] = { pre_it, pre_par, NULL }; 17895c635efSGarrett D'Amore static v_pre pres_os[] = { pre_os, NULL }; 17995c635efSGarrett D'Amore static v_pre pres_pp[] = { pre_par, NULL }; 18095c635efSGarrett D'Amore static v_pre pres_sh[] = { pre_sh, NULL }; 18195c635efSGarrett D'Amore static v_pre pres_ss[] = { pre_ss, NULL }; 18295c635efSGarrett D'Amore static v_pre pres_std[] = { pre_std, NULL }; 18395c635efSGarrett D'Amore 18495c635efSGarrett D'Amore static const struct valids mdoc_valids[MDOC_MAX] = { 18595c635efSGarrett D'Amore { NULL, NULL }, /* Ap */ 18695c635efSGarrett D'Amore { pres_dd, posts_dd }, /* Dd */ 18795c635efSGarrett D'Amore { pres_dt, posts_dt }, /* Dt */ 18895c635efSGarrett D'Amore { pres_os, posts_os }, /* Os */ 18995c635efSGarrett D'Amore { pres_sh, posts_sh }, /* Sh */ 19095c635efSGarrett D'Amore { pres_ss, posts_ss }, /* Ss */ 191*698f87a4SGarrett D'Amore { pres_pp, posts_pp }, /* Pp */ 192*698f87a4SGarrett D'Amore { pres_d1, posts_d1 }, /* D1 */ 19395c635efSGarrett D'Amore { pres_dl, posts_dl }, /* Dl */ 19495c635efSGarrett D'Amore { pres_bd, posts_bd }, /* Bd */ 19595c635efSGarrett D'Amore { NULL, NULL }, /* Ed */ 19695c635efSGarrett D'Amore { pres_bl, posts_bl }, /* Bl */ 19795c635efSGarrett D'Amore { NULL, NULL }, /* El */ 19895c635efSGarrett D'Amore { pres_it, posts_it }, /* It */ 19995c635efSGarrett D'Amore { NULL, NULL }, /* Ad */ 20095c635efSGarrett D'Amore { pres_an, posts_an }, /* An */ 20195c635efSGarrett D'Amore { NULL, posts_defaults }, /* Ar */ 20295c635efSGarrett D'Amore { NULL, NULL }, /* Cd */ 20395c635efSGarrett D'Amore { NULL, NULL }, /* Cm */ 20495c635efSGarrett D'Amore { NULL, NULL }, /* Dv */ 205*698f87a4SGarrett D'Amore { NULL, NULL }, /* Er */ 20695c635efSGarrett D'Amore { NULL, NULL }, /* Ev */ 20795c635efSGarrett D'Amore { pres_std, posts_std }, /* Ex */ 20895c635efSGarrett D'Amore { NULL, NULL }, /* Fa */ 209*698f87a4SGarrett D'Amore { NULL, posts_text }, /* Fd */ 21095c635efSGarrett D'Amore { NULL, NULL }, /* Fl */ 21195c635efSGarrett D'Amore { NULL, NULL }, /* Fn */ 21295c635efSGarrett D'Amore { NULL, NULL }, /* Ft */ 21395c635efSGarrett D'Amore { NULL, NULL }, /* Ic */ 21495c635efSGarrett D'Amore { NULL, posts_text1 }, /* In */ 21595c635efSGarrett D'Amore { NULL, posts_defaults }, /* Li */ 21695c635efSGarrett D'Amore { NULL, posts_nd }, /* Nd */ 21795c635efSGarrett D'Amore { NULL, posts_nm }, /* Nm */ 21895c635efSGarrett D'Amore { NULL, NULL }, /* Op */ 21995c635efSGarrett D'Amore { NULL, NULL }, /* Ot */ 22095c635efSGarrett D'Amore { NULL, posts_defaults }, /* Pa */ 22195c635efSGarrett D'Amore { pres_std, posts_std }, /* Rv */ 22295c635efSGarrett D'Amore { NULL, posts_st }, /* St */ 22395c635efSGarrett D'Amore { NULL, NULL }, /* Va */ 22495c635efSGarrett D'Amore { NULL, posts_vt }, /* Vt */ 22595c635efSGarrett D'Amore { NULL, posts_text }, /* Xr */ 22695c635efSGarrett D'Amore { NULL, posts_text }, /* %A */ 227*698f87a4SGarrett D'Amore { NULL, posts_hyphtext }, /* %B */ /* FIXME: can be used outside Rs/Re. */ 22895c635efSGarrett D'Amore { NULL, posts_text }, /* %D */ 22995c635efSGarrett D'Amore { NULL, posts_text }, /* %I */ 23095c635efSGarrett D'Amore { NULL, posts_text }, /* %J */ 231*698f87a4SGarrett D'Amore { NULL, posts_hyphtext }, /* %N */ 232*698f87a4SGarrett D'Amore { NULL, posts_hyphtext }, /* %O */ 23395c635efSGarrett D'Amore { NULL, posts_text }, /* %P */ 234*698f87a4SGarrett D'Amore { NULL, posts_hyphtext }, /* %R */ 235*698f87a4SGarrett D'Amore { NULL, posts_hyphtext }, /* %T */ /* FIXME: can be used outside Rs/Re. */ 23695c635efSGarrett D'Amore { NULL, posts_text }, /* %V */ 23795c635efSGarrett D'Amore { NULL, NULL }, /* Ac */ 23895c635efSGarrett D'Amore { NULL, NULL }, /* Ao */ 23995c635efSGarrett D'Amore { NULL, NULL }, /* Aq */ 24095c635efSGarrett D'Amore { NULL, posts_at }, /* At */ 24195c635efSGarrett D'Amore { NULL, NULL }, /* Bc */ 24295c635efSGarrett D'Amore { NULL, posts_bf }, /* Bf */ 24395c635efSGarrett D'Amore { NULL, NULL }, /* Bo */ 24495c635efSGarrett D'Amore { NULL, NULL }, /* Bq */ 24595c635efSGarrett D'Amore { NULL, NULL }, /* Bsx */ 24695c635efSGarrett D'Amore { NULL, posts_bx }, /* Bx */ 24795c635efSGarrett D'Amore { NULL, posts_bool }, /* Db */ 24895c635efSGarrett D'Amore { NULL, NULL }, /* Dc */ 24995c635efSGarrett D'Amore { NULL, NULL }, /* Do */ 25095c635efSGarrett D'Amore { NULL, NULL }, /* Dq */ 25195c635efSGarrett D'Amore { NULL, NULL }, /* Ec */ 25295c635efSGarrett D'Amore { NULL, NULL }, /* Ef */ 25395c635efSGarrett D'Amore { NULL, NULL }, /* Em */ 25495c635efSGarrett D'Amore { NULL, NULL }, /* Eo */ 25595c635efSGarrett D'Amore { NULL, NULL }, /* Fx */ 25695c635efSGarrett D'Amore { NULL, NULL }, /* Ms */ 25795c635efSGarrett D'Amore { NULL, posts_notext }, /* No */ 25895c635efSGarrett D'Amore { NULL, posts_ns }, /* Ns */ 25995c635efSGarrett D'Amore { NULL, NULL }, /* Nx */ 26095c635efSGarrett D'Amore { NULL, NULL }, /* Ox */ 26195c635efSGarrett D'Amore { NULL, NULL }, /* Pc */ 26295c635efSGarrett D'Amore { NULL, posts_text1 }, /* Pf */ 26395c635efSGarrett D'Amore { NULL, NULL }, /* Po */ 26495c635efSGarrett D'Amore { NULL, NULL }, /* Pq */ 26595c635efSGarrett D'Amore { NULL, NULL }, /* Qc */ 26695c635efSGarrett D'Amore { NULL, NULL }, /* Ql */ 26795c635efSGarrett D'Amore { NULL, NULL }, /* Qo */ 26895c635efSGarrett D'Amore { NULL, NULL }, /* Qq */ 26995c635efSGarrett D'Amore { NULL, NULL }, /* Re */ 27095c635efSGarrett D'Amore { NULL, posts_rs }, /* Rs */ 27195c635efSGarrett D'Amore { NULL, NULL }, /* Sc */ 27295c635efSGarrett D'Amore { NULL, NULL }, /* So */ 27395c635efSGarrett D'Amore { NULL, NULL }, /* Sq */ 27495c635efSGarrett D'Amore { NULL, posts_bool }, /* Sm */ 275*698f87a4SGarrett D'Amore { NULL, posts_hyph }, /* Sx */ 27695c635efSGarrett D'Amore { NULL, NULL }, /* Sy */ 27795c635efSGarrett D'Amore { NULL, NULL }, /* Tn */ 27895c635efSGarrett D'Amore { NULL, NULL }, /* Ux */ 27995c635efSGarrett D'Amore { NULL, NULL }, /* Xc */ 28095c635efSGarrett D'Amore { NULL, NULL }, /* Xo */ 28195c635efSGarrett D'Amore { NULL, posts_fo }, /* Fo */ 28295c635efSGarrett D'Amore { NULL, NULL }, /* Fc */ 28395c635efSGarrett D'Amore { NULL, NULL }, /* Oo */ 28495c635efSGarrett D'Amore { NULL, NULL }, /* Oc */ 28595c635efSGarrett D'Amore { NULL, posts_bk }, /* Bk */ 28695c635efSGarrett D'Amore { NULL, NULL }, /* Ek */ 28795c635efSGarrett D'Amore { NULL, posts_eoln }, /* Bt */ 28895c635efSGarrett D'Amore { NULL, NULL }, /* Hf */ 28995c635efSGarrett D'Amore { NULL, NULL }, /* Fr */ 29095c635efSGarrett D'Amore { NULL, posts_eoln }, /* Ud */ 29195c635efSGarrett D'Amore { NULL, posts_lb }, /* Lb */ 292*698f87a4SGarrett D'Amore { pres_pp, posts_pp }, /* Lp */ 29395c635efSGarrett D'Amore { NULL, NULL }, /* Lk */ 29495c635efSGarrett D'Amore { NULL, posts_defaults }, /* Mt */ 29595c635efSGarrett D'Amore { NULL, NULL }, /* Brq */ 29695c635efSGarrett D'Amore { NULL, NULL }, /* Bro */ 29795c635efSGarrett D'Amore { NULL, NULL }, /* Brc */ 29895c635efSGarrett D'Amore { NULL, posts_text }, /* %C */ 29995c635efSGarrett D'Amore { NULL, NULL }, /* Es */ 30095c635efSGarrett D'Amore { NULL, NULL }, /* En */ 30195c635efSGarrett D'Amore { NULL, NULL }, /* Dx */ 30295c635efSGarrett D'Amore { NULL, posts_text }, /* %Q */ 303*698f87a4SGarrett D'Amore { NULL, posts_pp }, /* br */ 304*698f87a4SGarrett D'Amore { NULL, posts_sp }, /* sp */ 30595c635efSGarrett D'Amore { NULL, posts_text1 }, /* %U */ 30695c635efSGarrett D'Amore { NULL, NULL }, /* Ta */ 30795c635efSGarrett D'Amore }; 30895c635efSGarrett D'Amore 30995c635efSGarrett D'Amore #define RSORD_MAX 14 /* Number of `Rs' blocks. */ 31095c635efSGarrett D'Amore 31195c635efSGarrett D'Amore static const enum mdoct rsord[RSORD_MAX] = { 31295c635efSGarrett D'Amore MDOC__A, 31395c635efSGarrett D'Amore MDOC__T, 31495c635efSGarrett D'Amore MDOC__B, 31595c635efSGarrett D'Amore MDOC__I, 31695c635efSGarrett D'Amore MDOC__J, 31795c635efSGarrett D'Amore MDOC__R, 31895c635efSGarrett D'Amore MDOC__N, 31995c635efSGarrett D'Amore MDOC__V, 320*698f87a4SGarrett D'Amore MDOC__U, 32195c635efSGarrett D'Amore MDOC__P, 32295c635efSGarrett D'Amore MDOC__Q, 32395c635efSGarrett D'Amore MDOC__C, 324*698f87a4SGarrett D'Amore MDOC__D, 325*698f87a4SGarrett D'Amore MDOC__O 32695c635efSGarrett D'Amore }; 32795c635efSGarrett D'Amore 32895c635efSGarrett D'Amore static const char * const secnames[SEC__MAX] = { 32995c635efSGarrett D'Amore NULL, 33095c635efSGarrett D'Amore "NAME", 33195c635efSGarrett D'Amore "LIBRARY", 33295c635efSGarrett D'Amore "SYNOPSIS", 33395c635efSGarrett D'Amore "DESCRIPTION", 33495c635efSGarrett D'Amore "IMPLEMENTATION NOTES", 33595c635efSGarrett D'Amore "RETURN VALUES", 33695c635efSGarrett D'Amore "ENVIRONMENT", 33795c635efSGarrett D'Amore "FILES", 33895c635efSGarrett D'Amore "EXIT STATUS", 33995c635efSGarrett D'Amore "EXAMPLES", 34095c635efSGarrett D'Amore "DIAGNOSTICS", 34195c635efSGarrett D'Amore "COMPATIBILITY", 34295c635efSGarrett D'Amore "ERRORS", 34395c635efSGarrett D'Amore "SEE ALSO", 34495c635efSGarrett D'Amore "STANDARDS", 34595c635efSGarrett D'Amore "HISTORY", 34695c635efSGarrett D'Amore "AUTHORS", 34795c635efSGarrett D'Amore "CAVEATS", 34895c635efSGarrett D'Amore "BUGS", 34995c635efSGarrett D'Amore "SECURITY CONSIDERATIONS", 35095c635efSGarrett D'Amore NULL 35195c635efSGarrett D'Amore }; 35295c635efSGarrett D'Amore 35395c635efSGarrett D'Amore int 35495c635efSGarrett D'Amore mdoc_valid_pre(struct mdoc *mdoc, struct mdoc_node *n) 35595c635efSGarrett D'Amore { 35695c635efSGarrett D'Amore v_pre *p; 35795c635efSGarrett D'Amore int line, pos; 35895c635efSGarrett D'Amore char *tp; 35995c635efSGarrett D'Amore 36095c635efSGarrett D'Amore switch (n->type) { 36195c635efSGarrett D'Amore case (MDOC_TEXT): 36295c635efSGarrett D'Amore tp = n->string; 36395c635efSGarrett D'Amore line = n->line; 36495c635efSGarrett D'Amore pos = n->pos; 36595c635efSGarrett D'Amore check_text(mdoc, line, pos, tp); 36695c635efSGarrett D'Amore /* FALLTHROUGH */ 36795c635efSGarrett D'Amore case (MDOC_TBL): 36895c635efSGarrett D'Amore /* FALLTHROUGH */ 36995c635efSGarrett D'Amore case (MDOC_EQN): 37095c635efSGarrett D'Amore /* FALLTHROUGH */ 37195c635efSGarrett D'Amore case (MDOC_ROOT): 37295c635efSGarrett D'Amore return(1); 37395c635efSGarrett D'Amore default: 37495c635efSGarrett D'Amore break; 37595c635efSGarrett D'Amore } 37695c635efSGarrett D'Amore 37795c635efSGarrett D'Amore check_args(mdoc, n); 37895c635efSGarrett D'Amore 37995c635efSGarrett D'Amore if (NULL == mdoc_valids[n->tok].pre) 38095c635efSGarrett D'Amore return(1); 38195c635efSGarrett D'Amore for (p = mdoc_valids[n->tok].pre; *p; p++) 38295c635efSGarrett D'Amore if ( ! (*p)(mdoc, n)) 38395c635efSGarrett D'Amore return(0); 38495c635efSGarrett D'Amore return(1); 38595c635efSGarrett D'Amore } 38695c635efSGarrett D'Amore 38795c635efSGarrett D'Amore 38895c635efSGarrett D'Amore int 38995c635efSGarrett D'Amore mdoc_valid_post(struct mdoc *mdoc) 39095c635efSGarrett D'Amore { 39195c635efSGarrett D'Amore v_post *p; 39295c635efSGarrett D'Amore 39395c635efSGarrett D'Amore if (MDOC_VALID & mdoc->last->flags) 39495c635efSGarrett D'Amore return(1); 39595c635efSGarrett D'Amore mdoc->last->flags |= MDOC_VALID; 39695c635efSGarrett D'Amore 39795c635efSGarrett D'Amore switch (mdoc->last->type) { 39895c635efSGarrett D'Amore case (MDOC_TEXT): 39995c635efSGarrett D'Amore /* FALLTHROUGH */ 40095c635efSGarrett D'Amore case (MDOC_EQN): 40195c635efSGarrett D'Amore /* FALLTHROUGH */ 40295c635efSGarrett D'Amore case (MDOC_TBL): 40395c635efSGarrett D'Amore return(1); 40495c635efSGarrett D'Amore case (MDOC_ROOT): 40595c635efSGarrett D'Amore return(post_root(mdoc)); 40695c635efSGarrett D'Amore default: 40795c635efSGarrett D'Amore break; 40895c635efSGarrett D'Amore } 40995c635efSGarrett D'Amore 41095c635efSGarrett D'Amore if (NULL == mdoc_valids[mdoc->last->tok].post) 41195c635efSGarrett D'Amore return(1); 41295c635efSGarrett D'Amore for (p = mdoc_valids[mdoc->last->tok].post; *p; p++) 41395c635efSGarrett D'Amore if ( ! (*p)(mdoc)) 41495c635efSGarrett D'Amore return(0); 41595c635efSGarrett D'Amore 41695c635efSGarrett D'Amore return(1); 41795c635efSGarrett D'Amore } 41895c635efSGarrett D'Amore 41995c635efSGarrett D'Amore static int 420*698f87a4SGarrett D'Amore check_count(struct mdoc *mdoc, enum mdoc_type type, 42195c635efSGarrett D'Amore enum check_lvl lvl, enum check_ineq ineq, int val) 42295c635efSGarrett D'Amore { 42395c635efSGarrett D'Amore const char *p; 42495c635efSGarrett D'Amore enum mandocerr t; 42595c635efSGarrett D'Amore 426*698f87a4SGarrett D'Amore if (mdoc->last->type != type) 42795c635efSGarrett D'Amore return(1); 42895c635efSGarrett D'Amore 42995c635efSGarrett D'Amore switch (ineq) { 43095c635efSGarrett D'Amore case (CHECK_LT): 43195c635efSGarrett D'Amore p = "less than "; 432*698f87a4SGarrett D'Amore if (mdoc->last->nchild < val) 43395c635efSGarrett D'Amore return(1); 43495c635efSGarrett D'Amore break; 43595c635efSGarrett D'Amore case (CHECK_GT): 43695c635efSGarrett D'Amore p = "more than "; 437*698f87a4SGarrett D'Amore if (mdoc->last->nchild > val) 43895c635efSGarrett D'Amore return(1); 43995c635efSGarrett D'Amore break; 44095c635efSGarrett D'Amore case (CHECK_EQ): 44195c635efSGarrett D'Amore p = ""; 442*698f87a4SGarrett D'Amore if (val == mdoc->last->nchild) 44395c635efSGarrett D'Amore return(1); 44495c635efSGarrett D'Amore break; 44595c635efSGarrett D'Amore default: 44695c635efSGarrett D'Amore abort(); 44795c635efSGarrett D'Amore /* NOTREACHED */ 44895c635efSGarrett D'Amore } 44995c635efSGarrett D'Amore 45095c635efSGarrett D'Amore t = lvl == CHECK_WARN ? MANDOCERR_ARGCWARN : MANDOCERR_ARGCOUNT; 451*698f87a4SGarrett D'Amore mandoc_vmsg(t, mdoc->parse, mdoc->last->line, mdoc->last->pos, 45295c635efSGarrett D'Amore "want %s%d children (have %d)", 453*698f87a4SGarrett D'Amore p, val, mdoc->last->nchild); 45495c635efSGarrett D'Amore return(1); 45595c635efSGarrett D'Amore } 45695c635efSGarrett D'Amore 45795c635efSGarrett D'Amore static int 45895c635efSGarrett D'Amore berr_ge1(POST_ARGS) 45995c635efSGarrett D'Amore { 46095c635efSGarrett D'Amore 46195c635efSGarrett D'Amore return(check_count(mdoc, MDOC_BODY, CHECK_ERROR, CHECK_GT, 0)); 46295c635efSGarrett D'Amore } 46395c635efSGarrett D'Amore 46495c635efSGarrett D'Amore static int 46595c635efSGarrett D'Amore bwarn_ge1(POST_ARGS) 46695c635efSGarrett D'Amore { 46795c635efSGarrett D'Amore return(check_count(mdoc, MDOC_BODY, CHECK_WARN, CHECK_GT, 0)); 46895c635efSGarrett D'Amore } 46995c635efSGarrett D'Amore 47095c635efSGarrett D'Amore static int 47195c635efSGarrett D'Amore ewarn_eq0(POST_ARGS) 47295c635efSGarrett D'Amore { 47395c635efSGarrett D'Amore return(check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 0)); 47495c635efSGarrett D'Amore } 47595c635efSGarrett D'Amore 47695c635efSGarrett D'Amore static int 47795c635efSGarrett D'Amore ewarn_eq1(POST_ARGS) 47895c635efSGarrett D'Amore { 47995c635efSGarrett D'Amore return(check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 1)); 48095c635efSGarrett D'Amore } 48195c635efSGarrett D'Amore 48295c635efSGarrett D'Amore static int 48395c635efSGarrett D'Amore ewarn_ge1(POST_ARGS) 48495c635efSGarrett D'Amore { 48595c635efSGarrett D'Amore return(check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_GT, 0)); 48695c635efSGarrett D'Amore } 48795c635efSGarrett D'Amore 48895c635efSGarrett D'Amore static int 48995c635efSGarrett D'Amore ewarn_le1(POST_ARGS) 49095c635efSGarrett D'Amore { 49195c635efSGarrett D'Amore return(check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_LT, 2)); 49295c635efSGarrett D'Amore } 49395c635efSGarrett D'Amore 49495c635efSGarrett D'Amore static int 49595c635efSGarrett D'Amore hwarn_eq0(POST_ARGS) 49695c635efSGarrett D'Amore { 49795c635efSGarrett D'Amore return(check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_EQ, 0)); 49895c635efSGarrett D'Amore } 49995c635efSGarrett D'Amore 50095c635efSGarrett D'Amore static int 50195c635efSGarrett D'Amore hwarn_eq1(POST_ARGS) 50295c635efSGarrett D'Amore { 50395c635efSGarrett D'Amore return(check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_EQ, 1)); 50495c635efSGarrett D'Amore } 50595c635efSGarrett D'Amore 50695c635efSGarrett D'Amore static int 50795c635efSGarrett D'Amore hwarn_ge1(POST_ARGS) 50895c635efSGarrett D'Amore { 50995c635efSGarrett D'Amore return(check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_GT, 0)); 51095c635efSGarrett D'Amore } 51195c635efSGarrett D'Amore 51295c635efSGarrett D'Amore static int 51395c635efSGarrett D'Amore hwarn_le1(POST_ARGS) 51495c635efSGarrett D'Amore { 51595c635efSGarrett D'Amore return(check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_LT, 2)); 51695c635efSGarrett D'Amore } 51795c635efSGarrett D'Amore 51895c635efSGarrett D'Amore static void 519*698f87a4SGarrett D'Amore check_args(struct mdoc *mdoc, struct mdoc_node *n) 52095c635efSGarrett D'Amore { 52195c635efSGarrett D'Amore int i; 52295c635efSGarrett D'Amore 52395c635efSGarrett D'Amore if (NULL == n->args) 52495c635efSGarrett D'Amore return; 52595c635efSGarrett D'Amore 52695c635efSGarrett D'Amore assert(n->args->argc); 52795c635efSGarrett D'Amore for (i = 0; i < (int)n->args->argc; i++) 528*698f87a4SGarrett D'Amore check_argv(mdoc, n, &n->args->argv[i]); 52995c635efSGarrett D'Amore } 53095c635efSGarrett D'Amore 53195c635efSGarrett D'Amore static void 532*698f87a4SGarrett D'Amore check_argv(struct mdoc *mdoc, struct mdoc_node *n, struct mdoc_argv *v) 53395c635efSGarrett D'Amore { 53495c635efSGarrett D'Amore int i; 53595c635efSGarrett D'Amore 53695c635efSGarrett D'Amore for (i = 0; i < (int)v->sz; i++) 537*698f87a4SGarrett D'Amore check_text(mdoc, v->line, v->pos, v->value[i]); 53895c635efSGarrett D'Amore 53995c635efSGarrett D'Amore /* FIXME: move to post_std(). */ 54095c635efSGarrett D'Amore 54195c635efSGarrett D'Amore if (MDOC_Std == v->arg) 542*698f87a4SGarrett D'Amore if ( ! (v->sz || mdoc->meta.name)) 543*698f87a4SGarrett D'Amore mdoc_nmsg(mdoc, n, MANDOCERR_NONAME); 54495c635efSGarrett D'Amore } 54595c635efSGarrett D'Amore 54695c635efSGarrett D'Amore static void 547*698f87a4SGarrett D'Amore check_text(struct mdoc *mdoc, int ln, int pos, char *p) 54895c635efSGarrett D'Amore { 54995c635efSGarrett D'Amore char *cp; 55095c635efSGarrett D'Amore 551*698f87a4SGarrett D'Amore if (MDOC_LITERAL & mdoc->flags) 55295c635efSGarrett D'Amore return; 55395c635efSGarrett D'Amore 55495c635efSGarrett D'Amore for (cp = p; NULL != (p = strchr(p, '\t')); p++) 555*698f87a4SGarrett D'Amore mdoc_pmsg(mdoc, ln, pos + (int)(p - cp), MANDOCERR_BADTAB); 55695c635efSGarrett D'Amore } 55795c635efSGarrett D'Amore 55895c635efSGarrett D'Amore static int 55995c635efSGarrett D'Amore check_parent(PRE_ARGS, enum mdoct tok, enum mdoc_type t) 56095c635efSGarrett D'Amore { 56195c635efSGarrett D'Amore 56295c635efSGarrett D'Amore assert(n->parent); 56395c635efSGarrett D'Amore if ((MDOC_ROOT == t || tok == n->parent->tok) && 56495c635efSGarrett D'Amore (t == n->parent->type)) 56595c635efSGarrett D'Amore return(1); 56695c635efSGarrett D'Amore 56795c635efSGarrett D'Amore mandoc_vmsg(MANDOCERR_SYNTCHILD, mdoc->parse, n->line, 56895c635efSGarrett D'Amore n->pos, "want parent %s", MDOC_ROOT == t ? 56995c635efSGarrett D'Amore "<root>" : mdoc_macronames[tok]); 57095c635efSGarrett D'Amore return(0); 57195c635efSGarrett D'Amore } 57295c635efSGarrett D'Amore 57395c635efSGarrett D'Amore 57495c635efSGarrett D'Amore static int 57595c635efSGarrett D'Amore pre_display(PRE_ARGS) 57695c635efSGarrett D'Amore { 57795c635efSGarrett D'Amore struct mdoc_node *node; 57895c635efSGarrett D'Amore 57995c635efSGarrett D'Amore if (MDOC_BLOCK != n->type) 58095c635efSGarrett D'Amore return(1); 58195c635efSGarrett D'Amore 58295c635efSGarrett D'Amore for (node = mdoc->last->parent; node; node = node->parent) 58395c635efSGarrett D'Amore if (MDOC_BLOCK == node->type) 58495c635efSGarrett D'Amore if (MDOC_Bd == node->tok) 58595c635efSGarrett D'Amore break; 58695c635efSGarrett D'Amore 58795c635efSGarrett D'Amore if (node) 58895c635efSGarrett D'Amore mdoc_nmsg(mdoc, n, MANDOCERR_NESTEDDISP); 58995c635efSGarrett D'Amore 59095c635efSGarrett D'Amore return(1); 59195c635efSGarrett D'Amore } 59295c635efSGarrett D'Amore 59395c635efSGarrett D'Amore 59495c635efSGarrett D'Amore static int 59595c635efSGarrett D'Amore pre_bl(PRE_ARGS) 59695c635efSGarrett D'Amore { 59795c635efSGarrett D'Amore int i, comp, dup; 59895c635efSGarrett D'Amore const char *offs, *width; 59995c635efSGarrett D'Amore enum mdoc_list lt; 60095c635efSGarrett D'Amore struct mdoc_node *np; 60195c635efSGarrett D'Amore 60295c635efSGarrett D'Amore if (MDOC_BLOCK != n->type) { 60395c635efSGarrett D'Amore if (ENDBODY_NOT != n->end) { 60495c635efSGarrett D'Amore assert(n->pending); 60595c635efSGarrett D'Amore np = n->pending->parent; 60695c635efSGarrett D'Amore } else 60795c635efSGarrett D'Amore np = n->parent; 60895c635efSGarrett D'Amore 60995c635efSGarrett D'Amore assert(np); 61095c635efSGarrett D'Amore assert(MDOC_BLOCK == np->type); 61195c635efSGarrett D'Amore assert(MDOC_Bl == np->tok); 61295c635efSGarrett D'Amore return(1); 61395c635efSGarrett D'Amore } 61495c635efSGarrett D'Amore 61595c635efSGarrett D'Amore /* 61695c635efSGarrett D'Amore * First figure out which kind of list to use: bind ourselves to 61795c635efSGarrett D'Amore * the first mentioned list type and warn about any remaining 61895c635efSGarrett D'Amore * ones. If we find no list type, we default to LIST_item. 61995c635efSGarrett D'Amore */ 62095c635efSGarrett D'Amore 62195c635efSGarrett D'Amore /* LINTED */ 62295c635efSGarrett D'Amore for (i = 0; n->args && i < (int)n->args->argc; i++) { 62395c635efSGarrett D'Amore lt = LIST__NONE; 62495c635efSGarrett D'Amore dup = comp = 0; 62595c635efSGarrett D'Amore width = offs = NULL; 62695c635efSGarrett D'Amore switch (n->args->argv[i].arg) { 62795c635efSGarrett D'Amore /* Set list types. */ 62895c635efSGarrett D'Amore case (MDOC_Bullet): 62995c635efSGarrett D'Amore lt = LIST_bullet; 63095c635efSGarrett D'Amore break; 63195c635efSGarrett D'Amore case (MDOC_Dash): 63295c635efSGarrett D'Amore lt = LIST_dash; 63395c635efSGarrett D'Amore break; 63495c635efSGarrett D'Amore case (MDOC_Enum): 63595c635efSGarrett D'Amore lt = LIST_enum; 63695c635efSGarrett D'Amore break; 63795c635efSGarrett D'Amore case (MDOC_Hyphen): 63895c635efSGarrett D'Amore lt = LIST_hyphen; 63995c635efSGarrett D'Amore break; 64095c635efSGarrett D'Amore case (MDOC_Item): 64195c635efSGarrett D'Amore lt = LIST_item; 64295c635efSGarrett D'Amore break; 64395c635efSGarrett D'Amore case (MDOC_Tag): 64495c635efSGarrett D'Amore lt = LIST_tag; 64595c635efSGarrett D'Amore break; 64695c635efSGarrett D'Amore case (MDOC_Diag): 64795c635efSGarrett D'Amore lt = LIST_diag; 64895c635efSGarrett D'Amore break; 64995c635efSGarrett D'Amore case (MDOC_Hang): 65095c635efSGarrett D'Amore lt = LIST_hang; 65195c635efSGarrett D'Amore break; 65295c635efSGarrett D'Amore case (MDOC_Ohang): 65395c635efSGarrett D'Amore lt = LIST_ohang; 65495c635efSGarrett D'Amore break; 65595c635efSGarrett D'Amore case (MDOC_Inset): 65695c635efSGarrett D'Amore lt = LIST_inset; 65795c635efSGarrett D'Amore break; 65895c635efSGarrett D'Amore case (MDOC_Column): 65995c635efSGarrett D'Amore lt = LIST_column; 66095c635efSGarrett D'Amore break; 66195c635efSGarrett D'Amore /* Set list arguments. */ 66295c635efSGarrett D'Amore case (MDOC_Compact): 66395c635efSGarrett D'Amore dup = n->norm->Bl.comp; 66495c635efSGarrett D'Amore comp = 1; 66595c635efSGarrett D'Amore break; 66695c635efSGarrett D'Amore case (MDOC_Width): 66795c635efSGarrett D'Amore /* NB: this can be empty! */ 66895c635efSGarrett D'Amore if (n->args->argv[i].sz) { 66995c635efSGarrett D'Amore width = n->args->argv[i].value[0]; 67095c635efSGarrett D'Amore dup = (NULL != n->norm->Bl.width); 67195c635efSGarrett D'Amore break; 67295c635efSGarrett D'Amore } 67395c635efSGarrett D'Amore mdoc_nmsg(mdoc, n, MANDOCERR_IGNARGV); 67495c635efSGarrett D'Amore break; 67595c635efSGarrett D'Amore case (MDOC_Offset): 67695c635efSGarrett D'Amore /* NB: this can be empty! */ 67795c635efSGarrett D'Amore if (n->args->argv[i].sz) { 67895c635efSGarrett D'Amore offs = n->args->argv[i].value[0]; 67995c635efSGarrett D'Amore dup = (NULL != n->norm->Bl.offs); 68095c635efSGarrett D'Amore break; 68195c635efSGarrett D'Amore } 68295c635efSGarrett D'Amore mdoc_nmsg(mdoc, n, MANDOCERR_IGNARGV); 68395c635efSGarrett D'Amore break; 68495c635efSGarrett D'Amore default: 68595c635efSGarrett D'Amore continue; 68695c635efSGarrett D'Amore } 68795c635efSGarrett D'Amore 68895c635efSGarrett D'Amore /* Check: duplicate auxiliary arguments. */ 68995c635efSGarrett D'Amore 69095c635efSGarrett D'Amore if (dup) 69195c635efSGarrett D'Amore mdoc_nmsg(mdoc, n, MANDOCERR_ARGVREP); 69295c635efSGarrett D'Amore 69395c635efSGarrett D'Amore if (comp && ! dup) 69495c635efSGarrett D'Amore n->norm->Bl.comp = comp; 69595c635efSGarrett D'Amore if (offs && ! dup) 69695c635efSGarrett D'Amore n->norm->Bl.offs = offs; 69795c635efSGarrett D'Amore if (width && ! dup) 69895c635efSGarrett D'Amore n->norm->Bl.width = width; 69995c635efSGarrett D'Amore 70095c635efSGarrett D'Amore /* Check: multiple list types. */ 70195c635efSGarrett D'Amore 70295c635efSGarrett D'Amore if (LIST__NONE != lt && n->norm->Bl.type != LIST__NONE) 70395c635efSGarrett D'Amore mdoc_nmsg(mdoc, n, MANDOCERR_LISTREP); 70495c635efSGarrett D'Amore 70595c635efSGarrett D'Amore /* Assign list type. */ 70695c635efSGarrett D'Amore 70795c635efSGarrett D'Amore if (LIST__NONE != lt && n->norm->Bl.type == LIST__NONE) { 70895c635efSGarrett D'Amore n->norm->Bl.type = lt; 70995c635efSGarrett D'Amore /* Set column information, too. */ 71095c635efSGarrett D'Amore if (LIST_column == lt) { 71195c635efSGarrett D'Amore n->norm->Bl.ncols = 71295c635efSGarrett D'Amore n->args->argv[i].sz; 71395c635efSGarrett D'Amore n->norm->Bl.cols = (void *) 71495c635efSGarrett D'Amore n->args->argv[i].value; 71595c635efSGarrett D'Amore } 71695c635efSGarrett D'Amore } 71795c635efSGarrett D'Amore 71895c635efSGarrett D'Amore /* The list type should come first. */ 71995c635efSGarrett D'Amore 72095c635efSGarrett D'Amore if (n->norm->Bl.type == LIST__NONE) 72195c635efSGarrett D'Amore if (n->norm->Bl.width || 72295c635efSGarrett D'Amore n->norm->Bl.offs || 72395c635efSGarrett D'Amore n->norm->Bl.comp) 72495c635efSGarrett D'Amore mdoc_nmsg(mdoc, n, MANDOCERR_LISTFIRST); 72595c635efSGarrett D'Amore 72695c635efSGarrett D'Amore continue; 72795c635efSGarrett D'Amore } 72895c635efSGarrett D'Amore 72995c635efSGarrett D'Amore /* Allow lists to default to LIST_item. */ 73095c635efSGarrett D'Amore 73195c635efSGarrett D'Amore if (LIST__NONE == n->norm->Bl.type) { 73295c635efSGarrett D'Amore mdoc_nmsg(mdoc, n, MANDOCERR_LISTTYPE); 73395c635efSGarrett D'Amore n->norm->Bl.type = LIST_item; 73495c635efSGarrett D'Amore } 73595c635efSGarrett D'Amore 73695c635efSGarrett D'Amore /* 73795c635efSGarrett D'Amore * Validate the width field. Some list types don't need width 73895c635efSGarrett D'Amore * types and should be warned about them. Others should have it 739*698f87a4SGarrett D'Amore * and must also be warned. Yet others have a default and need 740*698f87a4SGarrett D'Amore * no warning. 74195c635efSGarrett D'Amore */ 74295c635efSGarrett D'Amore 74395c635efSGarrett D'Amore switch (n->norm->Bl.type) { 74495c635efSGarrett D'Amore case (LIST_tag): 745*698f87a4SGarrett D'Amore if (NULL == n->norm->Bl.width) 746*698f87a4SGarrett D'Amore mdoc_nmsg(mdoc, n, MANDOCERR_NOWIDTHARG); 74795c635efSGarrett D'Amore break; 74895c635efSGarrett D'Amore case (LIST_column): 74995c635efSGarrett D'Amore /* FALLTHROUGH */ 75095c635efSGarrett D'Amore case (LIST_diag): 75195c635efSGarrett D'Amore /* FALLTHROUGH */ 75295c635efSGarrett D'Amore case (LIST_ohang): 75395c635efSGarrett D'Amore /* FALLTHROUGH */ 75495c635efSGarrett D'Amore case (LIST_inset): 75595c635efSGarrett D'Amore /* FALLTHROUGH */ 75695c635efSGarrett D'Amore case (LIST_item): 75795c635efSGarrett D'Amore if (n->norm->Bl.width) 75895c635efSGarrett D'Amore mdoc_nmsg(mdoc, n, MANDOCERR_IGNARGV); 75995c635efSGarrett D'Amore break; 760*698f87a4SGarrett D'Amore case (LIST_bullet): 761*698f87a4SGarrett D'Amore /* FALLTHROUGH */ 762*698f87a4SGarrett D'Amore case (LIST_dash): 763*698f87a4SGarrett D'Amore /* FALLTHROUGH */ 764*698f87a4SGarrett D'Amore case (LIST_hyphen): 765*698f87a4SGarrett D'Amore if (NULL == n->norm->Bl.width) 766*698f87a4SGarrett D'Amore n->norm->Bl.width = "2n"; 767*698f87a4SGarrett D'Amore break; 768*698f87a4SGarrett D'Amore case (LIST_enum): 769*698f87a4SGarrett D'Amore if (NULL == n->norm->Bl.width) 770*698f87a4SGarrett D'Amore n->norm->Bl.width = "3n"; 771*698f87a4SGarrett D'Amore break; 77295c635efSGarrett D'Amore default: 77395c635efSGarrett D'Amore break; 77495c635efSGarrett D'Amore } 77595c635efSGarrett D'Amore 77695c635efSGarrett D'Amore return(1); 77795c635efSGarrett D'Amore } 77895c635efSGarrett D'Amore 77995c635efSGarrett D'Amore 78095c635efSGarrett D'Amore static int 78195c635efSGarrett D'Amore pre_bd(PRE_ARGS) 78295c635efSGarrett D'Amore { 78395c635efSGarrett D'Amore int i, dup, comp; 78495c635efSGarrett D'Amore enum mdoc_disp dt; 78595c635efSGarrett D'Amore const char *offs; 78695c635efSGarrett D'Amore struct mdoc_node *np; 78795c635efSGarrett D'Amore 78895c635efSGarrett D'Amore if (MDOC_BLOCK != n->type) { 78995c635efSGarrett D'Amore if (ENDBODY_NOT != n->end) { 79095c635efSGarrett D'Amore assert(n->pending); 79195c635efSGarrett D'Amore np = n->pending->parent; 79295c635efSGarrett D'Amore } else 79395c635efSGarrett D'Amore np = n->parent; 79495c635efSGarrett D'Amore 79595c635efSGarrett D'Amore assert(np); 79695c635efSGarrett D'Amore assert(MDOC_BLOCK == np->type); 79795c635efSGarrett D'Amore assert(MDOC_Bd == np->tok); 79895c635efSGarrett D'Amore return(1); 79995c635efSGarrett D'Amore } 80095c635efSGarrett D'Amore 80195c635efSGarrett D'Amore /* LINTED */ 80295c635efSGarrett D'Amore for (i = 0; n->args && i < (int)n->args->argc; i++) { 80395c635efSGarrett D'Amore dt = DISP__NONE; 80495c635efSGarrett D'Amore dup = comp = 0; 80595c635efSGarrett D'Amore offs = NULL; 80695c635efSGarrett D'Amore 80795c635efSGarrett D'Amore switch (n->args->argv[i].arg) { 80895c635efSGarrett D'Amore case (MDOC_Centred): 80995c635efSGarrett D'Amore dt = DISP_centred; 81095c635efSGarrett D'Amore break; 81195c635efSGarrett D'Amore case (MDOC_Ragged): 81295c635efSGarrett D'Amore dt = DISP_ragged; 81395c635efSGarrett D'Amore break; 81495c635efSGarrett D'Amore case (MDOC_Unfilled): 81595c635efSGarrett D'Amore dt = DISP_unfilled; 81695c635efSGarrett D'Amore break; 81795c635efSGarrett D'Amore case (MDOC_Filled): 81895c635efSGarrett D'Amore dt = DISP_filled; 81995c635efSGarrett D'Amore break; 82095c635efSGarrett D'Amore case (MDOC_Literal): 82195c635efSGarrett D'Amore dt = DISP_literal; 82295c635efSGarrett D'Amore break; 82395c635efSGarrett D'Amore case (MDOC_File): 82495c635efSGarrett D'Amore mdoc_nmsg(mdoc, n, MANDOCERR_BADDISP); 82595c635efSGarrett D'Amore return(0); 82695c635efSGarrett D'Amore case (MDOC_Offset): 82795c635efSGarrett D'Amore /* NB: this can be empty! */ 82895c635efSGarrett D'Amore if (n->args->argv[i].sz) { 82995c635efSGarrett D'Amore offs = n->args->argv[i].value[0]; 83095c635efSGarrett D'Amore dup = (NULL != n->norm->Bd.offs); 83195c635efSGarrett D'Amore break; 83295c635efSGarrett D'Amore } 83395c635efSGarrett D'Amore mdoc_nmsg(mdoc, n, MANDOCERR_IGNARGV); 83495c635efSGarrett D'Amore break; 83595c635efSGarrett D'Amore case (MDOC_Compact): 83695c635efSGarrett D'Amore comp = 1; 83795c635efSGarrett D'Amore dup = n->norm->Bd.comp; 83895c635efSGarrett D'Amore break; 83995c635efSGarrett D'Amore default: 84095c635efSGarrett D'Amore abort(); 84195c635efSGarrett D'Amore /* NOTREACHED */ 84295c635efSGarrett D'Amore } 84395c635efSGarrett D'Amore 84495c635efSGarrett D'Amore /* Check whether we have duplicates. */ 84595c635efSGarrett D'Amore 84695c635efSGarrett D'Amore if (dup) 84795c635efSGarrett D'Amore mdoc_nmsg(mdoc, n, MANDOCERR_ARGVREP); 84895c635efSGarrett D'Amore 84995c635efSGarrett D'Amore /* Make our auxiliary assignments. */ 85095c635efSGarrett D'Amore 85195c635efSGarrett D'Amore if (offs && ! dup) 85295c635efSGarrett D'Amore n->norm->Bd.offs = offs; 85395c635efSGarrett D'Amore if (comp && ! dup) 85495c635efSGarrett D'Amore n->norm->Bd.comp = comp; 85595c635efSGarrett D'Amore 85695c635efSGarrett D'Amore /* Check whether a type has already been assigned. */ 85795c635efSGarrett D'Amore 85895c635efSGarrett D'Amore if (DISP__NONE != dt && n->norm->Bd.type != DISP__NONE) 85995c635efSGarrett D'Amore mdoc_nmsg(mdoc, n, MANDOCERR_DISPREP); 86095c635efSGarrett D'Amore 86195c635efSGarrett D'Amore /* Make our type assignment. */ 86295c635efSGarrett D'Amore 86395c635efSGarrett D'Amore if (DISP__NONE != dt && n->norm->Bd.type == DISP__NONE) 86495c635efSGarrett D'Amore n->norm->Bd.type = dt; 86595c635efSGarrett D'Amore } 86695c635efSGarrett D'Amore 86795c635efSGarrett D'Amore if (DISP__NONE == n->norm->Bd.type) { 86895c635efSGarrett D'Amore mdoc_nmsg(mdoc, n, MANDOCERR_DISPTYPE); 86995c635efSGarrett D'Amore n->norm->Bd.type = DISP_ragged; 87095c635efSGarrett D'Amore } 87195c635efSGarrett D'Amore 87295c635efSGarrett D'Amore return(1); 87395c635efSGarrett D'Amore } 87495c635efSGarrett D'Amore 87595c635efSGarrett D'Amore 87695c635efSGarrett D'Amore static int 87795c635efSGarrett D'Amore pre_ss(PRE_ARGS) 87895c635efSGarrett D'Amore { 87995c635efSGarrett D'Amore 88095c635efSGarrett D'Amore if (MDOC_BLOCK != n->type) 88195c635efSGarrett D'Amore return(1); 88295c635efSGarrett D'Amore return(check_parent(mdoc, n, MDOC_Sh, MDOC_BODY)); 88395c635efSGarrett D'Amore } 88495c635efSGarrett D'Amore 88595c635efSGarrett D'Amore 88695c635efSGarrett D'Amore static int 88795c635efSGarrett D'Amore pre_sh(PRE_ARGS) 88895c635efSGarrett D'Amore { 88995c635efSGarrett D'Amore 89095c635efSGarrett D'Amore if (MDOC_BLOCK != n->type) 89195c635efSGarrett D'Amore return(1); 89295c635efSGarrett D'Amore return(check_parent(mdoc, n, MDOC_MAX, MDOC_ROOT)); 89395c635efSGarrett D'Amore } 89495c635efSGarrett D'Amore 89595c635efSGarrett D'Amore 89695c635efSGarrett D'Amore static int 89795c635efSGarrett D'Amore pre_it(PRE_ARGS) 89895c635efSGarrett D'Amore { 89995c635efSGarrett D'Amore 90095c635efSGarrett D'Amore if (MDOC_BLOCK != n->type) 90195c635efSGarrett D'Amore return(1); 90295c635efSGarrett D'Amore 90395c635efSGarrett D'Amore return(check_parent(mdoc, n, MDOC_Bl, MDOC_BODY)); 90495c635efSGarrett D'Amore } 90595c635efSGarrett D'Amore 90695c635efSGarrett D'Amore 90795c635efSGarrett D'Amore static int 90895c635efSGarrett D'Amore pre_an(PRE_ARGS) 90995c635efSGarrett D'Amore { 91095c635efSGarrett D'Amore int i; 91195c635efSGarrett D'Amore 91295c635efSGarrett D'Amore if (NULL == n->args) 91395c635efSGarrett D'Amore return(1); 91495c635efSGarrett D'Amore 91595c635efSGarrett D'Amore for (i = 1; i < (int)n->args->argc; i++) 91695c635efSGarrett D'Amore mdoc_pmsg(mdoc, n->args->argv[i].line, 91795c635efSGarrett D'Amore n->args->argv[i].pos, MANDOCERR_IGNARGV); 91895c635efSGarrett D'Amore 91995c635efSGarrett D'Amore if (MDOC_Split == n->args->argv[0].arg) 92095c635efSGarrett D'Amore n->norm->An.auth = AUTH_split; 92195c635efSGarrett D'Amore else if (MDOC_Nosplit == n->args->argv[0].arg) 92295c635efSGarrett D'Amore n->norm->An.auth = AUTH_nosplit; 92395c635efSGarrett D'Amore else 92495c635efSGarrett D'Amore abort(); 92595c635efSGarrett D'Amore 92695c635efSGarrett D'Amore return(1); 92795c635efSGarrett D'Amore } 92895c635efSGarrett D'Amore 92995c635efSGarrett D'Amore static int 93095c635efSGarrett D'Amore pre_std(PRE_ARGS) 93195c635efSGarrett D'Amore { 93295c635efSGarrett D'Amore 93395c635efSGarrett D'Amore if (n->args && 1 == n->args->argc) 93495c635efSGarrett D'Amore if (MDOC_Std == n->args->argv[0].arg) 93595c635efSGarrett D'Amore return(1); 93695c635efSGarrett D'Amore 93795c635efSGarrett D'Amore mdoc_nmsg(mdoc, n, MANDOCERR_NOARGV); 93895c635efSGarrett D'Amore return(1); 93995c635efSGarrett D'Amore } 94095c635efSGarrett D'Amore 94195c635efSGarrett D'Amore static int 94295c635efSGarrett D'Amore pre_dt(PRE_ARGS) 94395c635efSGarrett D'Amore { 94495c635efSGarrett D'Amore 94595c635efSGarrett D'Amore if (NULL == mdoc->meta.date || mdoc->meta.os) 94695c635efSGarrett D'Amore mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGOOO); 94795c635efSGarrett D'Amore 94895c635efSGarrett D'Amore if (mdoc->meta.title) 94995c635efSGarrett D'Amore mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGREP); 95095c635efSGarrett D'Amore 95195c635efSGarrett D'Amore return(1); 95295c635efSGarrett D'Amore } 95395c635efSGarrett D'Amore 95495c635efSGarrett D'Amore static int 95595c635efSGarrett D'Amore pre_os(PRE_ARGS) 95695c635efSGarrett D'Amore { 95795c635efSGarrett D'Amore 95895c635efSGarrett D'Amore if (NULL == mdoc->meta.title || NULL == mdoc->meta.date) 95995c635efSGarrett D'Amore mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGOOO); 96095c635efSGarrett D'Amore 96195c635efSGarrett D'Amore if (mdoc->meta.os) 96295c635efSGarrett D'Amore mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGREP); 96395c635efSGarrett D'Amore 96495c635efSGarrett D'Amore return(1); 96595c635efSGarrett D'Amore } 96695c635efSGarrett D'Amore 96795c635efSGarrett D'Amore static int 96895c635efSGarrett D'Amore pre_dd(PRE_ARGS) 96995c635efSGarrett D'Amore { 97095c635efSGarrett D'Amore 97195c635efSGarrett D'Amore if (mdoc->meta.title || mdoc->meta.os) 97295c635efSGarrett D'Amore mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGOOO); 97395c635efSGarrett D'Amore 97495c635efSGarrett D'Amore if (mdoc->meta.date) 97595c635efSGarrett D'Amore mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGREP); 97695c635efSGarrett D'Amore 97795c635efSGarrett D'Amore return(1); 97895c635efSGarrett D'Amore } 97995c635efSGarrett D'Amore 98095c635efSGarrett D'Amore 98195c635efSGarrett D'Amore static int 98295c635efSGarrett D'Amore post_bf(POST_ARGS) 98395c635efSGarrett D'Amore { 98495c635efSGarrett D'Amore struct mdoc_node *np; 98595c635efSGarrett D'Amore enum mdocargt arg; 98695c635efSGarrett D'Amore 98795c635efSGarrett D'Amore /* 98895c635efSGarrett D'Amore * Unlike other data pointers, these are "housed" by the HEAD 98995c635efSGarrett D'Amore * element, which contains the goods. 99095c635efSGarrett D'Amore */ 99195c635efSGarrett D'Amore 99295c635efSGarrett D'Amore if (MDOC_HEAD != mdoc->last->type) { 99395c635efSGarrett D'Amore if (ENDBODY_NOT != mdoc->last->end) { 99495c635efSGarrett D'Amore assert(mdoc->last->pending); 99595c635efSGarrett D'Amore np = mdoc->last->pending->parent->head; 99695c635efSGarrett D'Amore } else if (MDOC_BLOCK != mdoc->last->type) { 99795c635efSGarrett D'Amore np = mdoc->last->parent->head; 99895c635efSGarrett D'Amore } else 99995c635efSGarrett D'Amore np = mdoc->last->head; 100095c635efSGarrett D'Amore 100195c635efSGarrett D'Amore assert(np); 100295c635efSGarrett D'Amore assert(MDOC_HEAD == np->type); 100395c635efSGarrett D'Amore assert(MDOC_Bf == np->tok); 100495c635efSGarrett D'Amore return(1); 100595c635efSGarrett D'Amore } 100695c635efSGarrett D'Amore 100795c635efSGarrett D'Amore np = mdoc->last; 100895c635efSGarrett D'Amore assert(MDOC_BLOCK == np->parent->type); 100995c635efSGarrett D'Amore assert(MDOC_Bf == np->parent->tok); 101095c635efSGarrett D'Amore 101195c635efSGarrett D'Amore /* 101295c635efSGarrett D'Amore * Cannot have both argument and parameter. 101395c635efSGarrett D'Amore * If neither is specified, let it through with a warning. 101495c635efSGarrett D'Amore */ 101595c635efSGarrett D'Amore 101695c635efSGarrett D'Amore if (np->parent->args && np->child) { 101795c635efSGarrett D'Amore mdoc_nmsg(mdoc, np, MANDOCERR_SYNTARGVCOUNT); 101895c635efSGarrett D'Amore return(0); 101995c635efSGarrett D'Amore } else if (NULL == np->parent->args && NULL == np->child) { 102095c635efSGarrett D'Amore mdoc_nmsg(mdoc, np, MANDOCERR_FONTTYPE); 102195c635efSGarrett D'Amore return(1); 102295c635efSGarrett D'Amore } 102395c635efSGarrett D'Amore 102495c635efSGarrett D'Amore /* Extract argument into data. */ 102595c635efSGarrett D'Amore 102695c635efSGarrett D'Amore if (np->parent->args) { 102795c635efSGarrett D'Amore arg = np->parent->args->argv[0].arg; 102895c635efSGarrett D'Amore if (MDOC_Emphasis == arg) 102995c635efSGarrett D'Amore np->norm->Bf.font = FONT_Em; 103095c635efSGarrett D'Amore else if (MDOC_Literal == arg) 103195c635efSGarrett D'Amore np->norm->Bf.font = FONT_Li; 103295c635efSGarrett D'Amore else if (MDOC_Symbolic == arg) 103395c635efSGarrett D'Amore np->norm->Bf.font = FONT_Sy; 103495c635efSGarrett D'Amore else 103595c635efSGarrett D'Amore abort(); 103695c635efSGarrett D'Amore return(1); 103795c635efSGarrett D'Amore } 103895c635efSGarrett D'Amore 103995c635efSGarrett D'Amore /* Extract parameter into data. */ 104095c635efSGarrett D'Amore 104195c635efSGarrett D'Amore if (0 == strcmp(np->child->string, "Em")) 104295c635efSGarrett D'Amore np->norm->Bf.font = FONT_Em; 104395c635efSGarrett D'Amore else if (0 == strcmp(np->child->string, "Li")) 104495c635efSGarrett D'Amore np->norm->Bf.font = FONT_Li; 104595c635efSGarrett D'Amore else if (0 == strcmp(np->child->string, "Sy")) 104695c635efSGarrett D'Amore np->norm->Bf.font = FONT_Sy; 104795c635efSGarrett D'Amore else 104895c635efSGarrett D'Amore mdoc_nmsg(mdoc, np, MANDOCERR_FONTTYPE); 104995c635efSGarrett D'Amore 105095c635efSGarrett D'Amore return(1); 105195c635efSGarrett D'Amore } 105295c635efSGarrett D'Amore 105395c635efSGarrett D'Amore static int 105495c635efSGarrett D'Amore post_lb(POST_ARGS) 105595c635efSGarrett D'Amore { 105695c635efSGarrett D'Amore const char *p; 105795c635efSGarrett D'Amore char *buf; 105895c635efSGarrett D'Amore size_t sz; 105995c635efSGarrett D'Amore 106095c635efSGarrett D'Amore check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 1); 106195c635efSGarrett D'Amore 106295c635efSGarrett D'Amore assert(mdoc->last->child); 106395c635efSGarrett D'Amore assert(MDOC_TEXT == mdoc->last->child->type); 106495c635efSGarrett D'Amore 106595c635efSGarrett D'Amore p = mdoc_a2lib(mdoc->last->child->string); 106695c635efSGarrett D'Amore 106795c635efSGarrett D'Amore /* If lookup ok, replace with table value. */ 106895c635efSGarrett D'Amore 106995c635efSGarrett D'Amore if (p) { 107095c635efSGarrett D'Amore free(mdoc->last->child->string); 107195c635efSGarrett D'Amore mdoc->last->child->string = mandoc_strdup(p); 107295c635efSGarrett D'Amore return(1); 107395c635efSGarrett D'Amore } 107495c635efSGarrett D'Amore 107595c635efSGarrett D'Amore /* If not, use "library ``xxxx''. */ 107695c635efSGarrett D'Amore 107795c635efSGarrett D'Amore sz = strlen(mdoc->last->child->string) + 107895c635efSGarrett D'Amore 2 + strlen("\\(lqlibrary\\(rq"); 107995c635efSGarrett D'Amore buf = mandoc_malloc(sz); 108095c635efSGarrett D'Amore snprintf(buf, sz, "library \\(lq%s\\(rq", 108195c635efSGarrett D'Amore mdoc->last->child->string); 108295c635efSGarrett D'Amore free(mdoc->last->child->string); 108395c635efSGarrett D'Amore mdoc->last->child->string = buf; 108495c635efSGarrett D'Amore return(1); 108595c635efSGarrett D'Amore } 108695c635efSGarrett D'Amore 108795c635efSGarrett D'Amore static int 108895c635efSGarrett D'Amore post_eoln(POST_ARGS) 108995c635efSGarrett D'Amore { 109095c635efSGarrett D'Amore 109195c635efSGarrett D'Amore if (mdoc->last->child) 109295c635efSGarrett D'Amore mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_ARGSLOST); 109395c635efSGarrett D'Amore return(1); 109495c635efSGarrett D'Amore } 109595c635efSGarrett D'Amore 109695c635efSGarrett D'Amore 109795c635efSGarrett D'Amore static int 109895c635efSGarrett D'Amore post_vt(POST_ARGS) 109995c635efSGarrett D'Amore { 110095c635efSGarrett D'Amore const struct mdoc_node *n; 110195c635efSGarrett D'Amore 110295c635efSGarrett D'Amore /* 110395c635efSGarrett D'Amore * The Vt macro comes in both ELEM and BLOCK form, both of which 110495c635efSGarrett D'Amore * have different syntaxes (yet more context-sensitive 110595c635efSGarrett D'Amore * behaviour). ELEM types must have a child, which is already 110695c635efSGarrett D'Amore * guaranteed by the in_line parsing routine; BLOCK types, 110795c635efSGarrett D'Amore * specifically the BODY, should only have TEXT children. 110895c635efSGarrett D'Amore */ 110995c635efSGarrett D'Amore 111095c635efSGarrett D'Amore if (MDOC_BODY != mdoc->last->type) 111195c635efSGarrett D'Amore return(1); 111295c635efSGarrett D'Amore 111395c635efSGarrett D'Amore for (n = mdoc->last->child; n; n = n->next) 111495c635efSGarrett D'Amore if (MDOC_TEXT != n->type) 111595c635efSGarrett D'Amore mdoc_nmsg(mdoc, n, MANDOCERR_CHILD); 111695c635efSGarrett D'Amore 111795c635efSGarrett D'Amore return(1); 111895c635efSGarrett D'Amore } 111995c635efSGarrett D'Amore 112095c635efSGarrett D'Amore 112195c635efSGarrett D'Amore static int 112295c635efSGarrett D'Amore post_nm(POST_ARGS) 112395c635efSGarrett D'Amore { 112495c635efSGarrett D'Amore char buf[BUFSIZ]; 112595c635efSGarrett D'Amore int c; 112695c635efSGarrett D'Amore 1127*698f87a4SGarrett D'Amore if (NULL != mdoc->meta.name) 112895c635efSGarrett D'Amore return(1); 112995c635efSGarrett D'Amore 1130*698f87a4SGarrett D'Amore /* Try to use our children for setting the meta name. */ 113195c635efSGarrett D'Amore 1132*698f87a4SGarrett D'Amore if (NULL != mdoc->last->child) { 1133*698f87a4SGarrett D'Amore buf[0] = '\0'; 1134*698f87a4SGarrett D'Amore c = concat(buf, mdoc->last->child, BUFSIZ); 1135*698f87a4SGarrett D'Amore } else 1136*698f87a4SGarrett D'Amore c = 0; 1137*698f87a4SGarrett D'Amore 1138*698f87a4SGarrett D'Amore switch (c) { 1139*698f87a4SGarrett D'Amore case (-1): 114095c635efSGarrett D'Amore mdoc_nmsg(mdoc, mdoc->last->child, MANDOCERR_MEM); 114195c635efSGarrett D'Amore return(0); 1142*698f87a4SGarrett D'Amore case (0): 1143*698f87a4SGarrett D'Amore mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NONAME); 1144*698f87a4SGarrett D'Amore mdoc->meta.name = mandoc_strdup("UNKNOWN"); 1145*698f87a4SGarrett D'Amore break; 1146*698f87a4SGarrett D'Amore default: 1147*698f87a4SGarrett D'Amore mdoc->meta.name = mandoc_strdup(buf); 1148*698f87a4SGarrett D'Amore break; 114995c635efSGarrett D'Amore } 115095c635efSGarrett D'Amore return(1); 115195c635efSGarrett D'Amore } 115295c635efSGarrett D'Amore 115395c635efSGarrett D'Amore static int 115495c635efSGarrett D'Amore post_literal(POST_ARGS) 115595c635efSGarrett D'Amore { 115695c635efSGarrett D'Amore 115795c635efSGarrett D'Amore /* 115895c635efSGarrett D'Amore * The `Dl' (note "el" not "one") and `Bd' macros unset the 115995c635efSGarrett D'Amore * MDOC_LITERAL flag as they leave. Note that `Bd' only sets 116095c635efSGarrett D'Amore * this in literal mode, but it doesn't hurt to just switch it 116195c635efSGarrett D'Amore * off in general since displays can't be nested. 116295c635efSGarrett D'Amore */ 116395c635efSGarrett D'Amore 116495c635efSGarrett D'Amore if (MDOC_BODY == mdoc->last->type) 116595c635efSGarrett D'Amore mdoc->flags &= ~MDOC_LITERAL; 116695c635efSGarrett D'Amore 116795c635efSGarrett D'Amore return(1); 116895c635efSGarrett D'Amore } 116995c635efSGarrett D'Amore 117095c635efSGarrett D'Amore static int 117195c635efSGarrett D'Amore post_defaults(POST_ARGS) 117295c635efSGarrett D'Amore { 117395c635efSGarrett D'Amore struct mdoc_node *nn; 117495c635efSGarrett D'Amore 117595c635efSGarrett D'Amore /* 117695c635efSGarrett D'Amore * The `Ar' defaults to "file ..." if no value is provided as an 117795c635efSGarrett D'Amore * argument; the `Mt' and `Pa' macros use "~"; the `Li' just 117895c635efSGarrett D'Amore * gets an empty string. 117995c635efSGarrett D'Amore */ 118095c635efSGarrett D'Amore 118195c635efSGarrett D'Amore if (mdoc->last->child) 118295c635efSGarrett D'Amore return(1); 118395c635efSGarrett D'Amore 118495c635efSGarrett D'Amore nn = mdoc->last; 118595c635efSGarrett D'Amore mdoc->next = MDOC_NEXT_CHILD; 118695c635efSGarrett D'Amore 118795c635efSGarrett D'Amore switch (nn->tok) { 118895c635efSGarrett D'Amore case (MDOC_Ar): 118995c635efSGarrett D'Amore if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "file")) 119095c635efSGarrett D'Amore return(0); 119195c635efSGarrett D'Amore if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "...")) 119295c635efSGarrett D'Amore return(0); 119395c635efSGarrett D'Amore break; 119495c635efSGarrett D'Amore case (MDOC_At): 119595c635efSGarrett D'Amore if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "AT&T")) 119695c635efSGarrett D'Amore return(0); 119795c635efSGarrett D'Amore if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "UNIX")) 119895c635efSGarrett D'Amore return(0); 119995c635efSGarrett D'Amore break; 120095c635efSGarrett D'Amore case (MDOC_Li): 120195c635efSGarrett D'Amore if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "")) 120295c635efSGarrett D'Amore return(0); 120395c635efSGarrett D'Amore break; 120495c635efSGarrett D'Amore case (MDOC_Pa): 120595c635efSGarrett D'Amore /* FALLTHROUGH */ 120695c635efSGarrett D'Amore case (MDOC_Mt): 120795c635efSGarrett D'Amore if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "~")) 120895c635efSGarrett D'Amore return(0); 120995c635efSGarrett D'Amore break; 121095c635efSGarrett D'Amore default: 121195c635efSGarrett D'Amore abort(); 121295c635efSGarrett D'Amore /* NOTREACHED */ 121395c635efSGarrett D'Amore } 121495c635efSGarrett D'Amore 121595c635efSGarrett D'Amore mdoc->last = nn; 121695c635efSGarrett D'Amore return(1); 121795c635efSGarrett D'Amore } 121895c635efSGarrett D'Amore 121995c635efSGarrett D'Amore static int 122095c635efSGarrett D'Amore post_at(POST_ARGS) 122195c635efSGarrett D'Amore { 122295c635efSGarrett D'Amore const char *p, *q; 122395c635efSGarrett D'Amore char *buf; 122495c635efSGarrett D'Amore size_t sz; 122595c635efSGarrett D'Amore 122695c635efSGarrett D'Amore /* 122795c635efSGarrett D'Amore * If we have a child, look it up in the standard keys. If a 122895c635efSGarrett D'Amore * key exist, use that instead of the child; if it doesn't, 122995c635efSGarrett D'Amore * prefix "AT&T UNIX " to the existing data. 123095c635efSGarrett D'Amore */ 123195c635efSGarrett D'Amore 123295c635efSGarrett D'Amore if (NULL == mdoc->last->child) 123395c635efSGarrett D'Amore return(1); 123495c635efSGarrett D'Amore 123595c635efSGarrett D'Amore assert(MDOC_TEXT == mdoc->last->child->type); 123695c635efSGarrett D'Amore p = mdoc_a2att(mdoc->last->child->string); 123795c635efSGarrett D'Amore 123895c635efSGarrett D'Amore if (p) { 123995c635efSGarrett D'Amore free(mdoc->last->child->string); 124095c635efSGarrett D'Amore mdoc->last->child->string = mandoc_strdup(p); 124195c635efSGarrett D'Amore } else { 124295c635efSGarrett D'Amore mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADATT); 124395c635efSGarrett D'Amore p = "AT&T UNIX "; 124495c635efSGarrett D'Amore q = mdoc->last->child->string; 124595c635efSGarrett D'Amore sz = strlen(p) + strlen(q) + 1; 124695c635efSGarrett D'Amore buf = mandoc_malloc(sz); 124795c635efSGarrett D'Amore strlcpy(buf, p, sz); 124895c635efSGarrett D'Amore strlcat(buf, q, sz); 124995c635efSGarrett D'Amore free(mdoc->last->child->string); 125095c635efSGarrett D'Amore mdoc->last->child->string = buf; 125195c635efSGarrett D'Amore } 125295c635efSGarrett D'Amore 125395c635efSGarrett D'Amore return(1); 125495c635efSGarrett D'Amore } 125595c635efSGarrett D'Amore 125695c635efSGarrett D'Amore static int 125795c635efSGarrett D'Amore post_an(POST_ARGS) 125895c635efSGarrett D'Amore { 125995c635efSGarrett D'Amore struct mdoc_node *np; 126095c635efSGarrett D'Amore 126195c635efSGarrett D'Amore np = mdoc->last; 126295c635efSGarrett D'Amore if (AUTH__NONE == np->norm->An.auth) { 126395c635efSGarrett D'Amore if (0 == np->child) 126495c635efSGarrett D'Amore check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_GT, 0); 126595c635efSGarrett D'Amore } else if (np->child) 126695c635efSGarrett D'Amore check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 0); 126795c635efSGarrett D'Amore 126895c635efSGarrett D'Amore return(1); 126995c635efSGarrett D'Amore } 127095c635efSGarrett D'Amore 127195c635efSGarrett D'Amore 127295c635efSGarrett D'Amore static int 127395c635efSGarrett D'Amore post_it(POST_ARGS) 127495c635efSGarrett D'Amore { 127595c635efSGarrett D'Amore int i, cols; 127695c635efSGarrett D'Amore enum mdoc_list lt; 127795c635efSGarrett D'Amore struct mdoc_node *n, *c; 127895c635efSGarrett D'Amore enum mandocerr er; 127995c635efSGarrett D'Amore 128095c635efSGarrett D'Amore if (MDOC_BLOCK != mdoc->last->type) 128195c635efSGarrett D'Amore return(1); 128295c635efSGarrett D'Amore 128395c635efSGarrett D'Amore n = mdoc->last->parent->parent; 128495c635efSGarrett D'Amore lt = n->norm->Bl.type; 128595c635efSGarrett D'Amore 128695c635efSGarrett D'Amore if (LIST__NONE == lt) { 128795c635efSGarrett D'Amore mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_LISTTYPE); 128895c635efSGarrett D'Amore return(1); 128995c635efSGarrett D'Amore } 129095c635efSGarrett D'Amore 129195c635efSGarrett D'Amore switch (lt) { 129295c635efSGarrett D'Amore case (LIST_tag): 129395c635efSGarrett D'Amore if (mdoc->last->head->child) 129495c635efSGarrett D'Amore break; 129595c635efSGarrett D'Amore /* FIXME: give this a dummy value. */ 129695c635efSGarrett D'Amore mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOARGS); 129795c635efSGarrett D'Amore break; 129895c635efSGarrett D'Amore case (LIST_hang): 129995c635efSGarrett D'Amore /* FALLTHROUGH */ 130095c635efSGarrett D'Amore case (LIST_ohang): 130195c635efSGarrett D'Amore /* FALLTHROUGH */ 130295c635efSGarrett D'Amore case (LIST_inset): 130395c635efSGarrett D'Amore /* FALLTHROUGH */ 130495c635efSGarrett D'Amore case (LIST_diag): 130595c635efSGarrett D'Amore if (NULL == mdoc->last->head->child) 130695c635efSGarrett D'Amore mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOARGS); 130795c635efSGarrett D'Amore break; 130895c635efSGarrett D'Amore case (LIST_bullet): 130995c635efSGarrett D'Amore /* FALLTHROUGH */ 131095c635efSGarrett D'Amore case (LIST_dash): 131195c635efSGarrett D'Amore /* FALLTHROUGH */ 131295c635efSGarrett D'Amore case (LIST_enum): 131395c635efSGarrett D'Amore /* FALLTHROUGH */ 131495c635efSGarrett D'Amore case (LIST_hyphen): 131595c635efSGarrett D'Amore if (NULL == mdoc->last->body->child) 131695c635efSGarrett D'Amore mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOBODY); 131795c635efSGarrett D'Amore /* FALLTHROUGH */ 131895c635efSGarrett D'Amore case (LIST_item): 131995c635efSGarrett D'Amore if (mdoc->last->head->child) 132095c635efSGarrett D'Amore mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_ARGSLOST); 132195c635efSGarrett D'Amore break; 132295c635efSGarrett D'Amore case (LIST_column): 132395c635efSGarrett D'Amore cols = (int)n->norm->Bl.ncols; 132495c635efSGarrett D'Amore 132595c635efSGarrett D'Amore assert(NULL == mdoc->last->head->child); 132695c635efSGarrett D'Amore 132795c635efSGarrett D'Amore if (NULL == mdoc->last->body->child) 132895c635efSGarrett D'Amore mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOBODY); 132995c635efSGarrett D'Amore 133095c635efSGarrett D'Amore for (i = 0, c = mdoc->last->child; c; c = c->next) 133195c635efSGarrett D'Amore if (MDOC_BODY == c->type) 133295c635efSGarrett D'Amore i++; 133395c635efSGarrett D'Amore 133495c635efSGarrett D'Amore if (i < cols) 133595c635efSGarrett D'Amore er = MANDOCERR_ARGCOUNT; 133695c635efSGarrett D'Amore else if (i == cols || i == cols + 1) 133795c635efSGarrett D'Amore break; 133895c635efSGarrett D'Amore else 133995c635efSGarrett D'Amore er = MANDOCERR_SYNTARGCOUNT; 134095c635efSGarrett D'Amore 134195c635efSGarrett D'Amore mandoc_vmsg(er, mdoc->parse, mdoc->last->line, 134295c635efSGarrett D'Amore mdoc->last->pos, 134395c635efSGarrett D'Amore "columns == %d (have %d)", cols, i); 134495c635efSGarrett D'Amore return(MANDOCERR_ARGCOUNT == er); 134595c635efSGarrett D'Amore default: 134695c635efSGarrett D'Amore break; 134795c635efSGarrett D'Amore } 134895c635efSGarrett D'Amore 134995c635efSGarrett D'Amore return(1); 135095c635efSGarrett D'Amore } 135195c635efSGarrett D'Amore 135295c635efSGarrett D'Amore static int 135395c635efSGarrett D'Amore post_bl_block(POST_ARGS) 135495c635efSGarrett D'Amore { 1355*698f87a4SGarrett D'Amore struct mdoc_node *n, *ni, *nc; 135695c635efSGarrett D'Amore 135795c635efSGarrett D'Amore /* 135895c635efSGarrett D'Amore * These are fairly complicated, so we've broken them into two 135995c635efSGarrett D'Amore * functions. post_bl_block_tag() is called when a -tag is 136095c635efSGarrett D'Amore * specified, but no -width (it must be guessed). The second 136195c635efSGarrett D'Amore * when a -width is specified (macro indicators must be 136295c635efSGarrett D'Amore * rewritten into real lengths). 136395c635efSGarrett D'Amore */ 136495c635efSGarrett D'Amore 136595c635efSGarrett D'Amore n = mdoc->last; 136695c635efSGarrett D'Amore 136795c635efSGarrett D'Amore if (LIST_tag == n->norm->Bl.type && 136895c635efSGarrett D'Amore NULL == n->norm->Bl.width) { 136995c635efSGarrett D'Amore if ( ! post_bl_block_tag(mdoc)) 137095c635efSGarrett D'Amore return(0); 1371*698f87a4SGarrett D'Amore assert(n->norm->Bl.width); 137295c635efSGarrett D'Amore } else if (NULL != n->norm->Bl.width) { 137395c635efSGarrett D'Amore if ( ! post_bl_block_width(mdoc)) 137495c635efSGarrett D'Amore return(0); 1375*698f87a4SGarrett D'Amore assert(n->norm->Bl.width); 1376*698f87a4SGarrett D'Amore } 137795c635efSGarrett D'Amore 1378*698f87a4SGarrett D'Amore for (ni = n->body->child; ni; ni = ni->next) { 1379*698f87a4SGarrett D'Amore if (NULL == ni->body) 1380*698f87a4SGarrett D'Amore continue; 1381*698f87a4SGarrett D'Amore nc = ni->body->last; 1382*698f87a4SGarrett D'Amore while (NULL != nc) { 1383*698f87a4SGarrett D'Amore switch (nc->tok) { 1384*698f87a4SGarrett D'Amore case (MDOC_Pp): 1385*698f87a4SGarrett D'Amore /* FALLTHROUGH */ 1386*698f87a4SGarrett D'Amore case (MDOC_Lp): 1387*698f87a4SGarrett D'Amore /* FALLTHROUGH */ 1388*698f87a4SGarrett D'Amore case (MDOC_br): 1389*698f87a4SGarrett D'Amore break; 1390*698f87a4SGarrett D'Amore default: 1391*698f87a4SGarrett D'Amore nc = NULL; 1392*698f87a4SGarrett D'Amore continue; 1393*698f87a4SGarrett D'Amore } 1394*698f87a4SGarrett D'Amore if (NULL == ni->next) { 1395*698f87a4SGarrett D'Amore mdoc_nmsg(mdoc, nc, MANDOCERR_MOVEPAR); 1396*698f87a4SGarrett D'Amore if ( ! mdoc_node_relink(mdoc, nc)) 1397*698f87a4SGarrett D'Amore return(0); 1398*698f87a4SGarrett D'Amore } else if (0 == n->norm->Bl.comp && 1399*698f87a4SGarrett D'Amore LIST_column != n->norm->Bl.type) { 1400*698f87a4SGarrett D'Amore mdoc_nmsg(mdoc, nc, MANDOCERR_IGNPAR); 1401*698f87a4SGarrett D'Amore mdoc_node_delete(mdoc, nc); 1402*698f87a4SGarrett D'Amore } else 1403*698f87a4SGarrett D'Amore break; 1404*698f87a4SGarrett D'Amore nc = ni->body->last; 1405*698f87a4SGarrett D'Amore } 1406*698f87a4SGarrett D'Amore } 140795c635efSGarrett D'Amore return(1); 140895c635efSGarrett D'Amore } 140995c635efSGarrett D'Amore 141095c635efSGarrett D'Amore static int 141195c635efSGarrett D'Amore post_bl_block_width(POST_ARGS) 141295c635efSGarrett D'Amore { 141395c635efSGarrett D'Amore size_t width; 141495c635efSGarrett D'Amore int i; 141595c635efSGarrett D'Amore enum mdoct tok; 141695c635efSGarrett D'Amore struct mdoc_node *n; 141795c635efSGarrett D'Amore char buf[NUMSIZ]; 141895c635efSGarrett D'Amore 141995c635efSGarrett D'Amore n = mdoc->last; 142095c635efSGarrett D'Amore 142195c635efSGarrett D'Amore /* 142295c635efSGarrett D'Amore * Calculate the real width of a list from the -width string, 142395c635efSGarrett D'Amore * which may contain a macro (with a known default width), a 142495c635efSGarrett D'Amore * literal string, or a scaling width. 142595c635efSGarrett D'Amore * 142695c635efSGarrett D'Amore * If the value to -width is a macro, then we re-write it to be 142795c635efSGarrett D'Amore * the macro's width as set in share/tmac/mdoc/doc-common. 142895c635efSGarrett D'Amore */ 142995c635efSGarrett D'Amore 143095c635efSGarrett D'Amore if (0 == strcmp(n->norm->Bl.width, "Ds")) 143195c635efSGarrett D'Amore width = 6; 143295c635efSGarrett D'Amore else if (MDOC_MAX == (tok = mdoc_hash_find(n->norm->Bl.width))) 143395c635efSGarrett D'Amore return(1); 143495c635efSGarrett D'Amore else if (0 == (width = macro2len(tok))) { 143595c635efSGarrett D'Amore mdoc_nmsg(mdoc, n, MANDOCERR_BADWIDTH); 143695c635efSGarrett D'Amore return(1); 143795c635efSGarrett D'Amore } 143895c635efSGarrett D'Amore 143995c635efSGarrett D'Amore /* The value already exists: free and reallocate it. */ 144095c635efSGarrett D'Amore 144195c635efSGarrett D'Amore assert(n->args); 144295c635efSGarrett D'Amore 144395c635efSGarrett D'Amore for (i = 0; i < (int)n->args->argc; i++) 144495c635efSGarrett D'Amore if (MDOC_Width == n->args->argv[i].arg) 144595c635efSGarrett D'Amore break; 144695c635efSGarrett D'Amore 144795c635efSGarrett D'Amore assert(i < (int)n->args->argc); 144895c635efSGarrett D'Amore 144995c635efSGarrett D'Amore snprintf(buf, NUMSIZ, "%un", (unsigned int)width); 145095c635efSGarrett D'Amore free(n->args->argv[i].value[0]); 145195c635efSGarrett D'Amore n->args->argv[i].value[0] = mandoc_strdup(buf); 145295c635efSGarrett D'Amore 145395c635efSGarrett D'Amore /* Set our width! */ 145495c635efSGarrett D'Amore n->norm->Bl.width = n->args->argv[i].value[0]; 145595c635efSGarrett D'Amore return(1); 145695c635efSGarrett D'Amore } 145795c635efSGarrett D'Amore 145895c635efSGarrett D'Amore static int 145995c635efSGarrett D'Amore post_bl_block_tag(POST_ARGS) 146095c635efSGarrett D'Amore { 146195c635efSGarrett D'Amore struct mdoc_node *n, *nn; 146295c635efSGarrett D'Amore size_t sz, ssz; 146395c635efSGarrett D'Amore int i; 146495c635efSGarrett D'Amore char buf[NUMSIZ]; 146595c635efSGarrett D'Amore 146695c635efSGarrett D'Amore /* 146795c635efSGarrett D'Amore * Calculate the -width for a `Bl -tag' list if it hasn't been 146895c635efSGarrett D'Amore * provided. Uses the first head macro. NOTE AGAIN: this is 146995c635efSGarrett D'Amore * ONLY if the -width argument has NOT been provided. See 147095c635efSGarrett D'Amore * post_bl_block_width() for converting the -width string. 147195c635efSGarrett D'Amore */ 147295c635efSGarrett D'Amore 147395c635efSGarrett D'Amore sz = 10; 147495c635efSGarrett D'Amore n = mdoc->last; 147595c635efSGarrett D'Amore 147695c635efSGarrett D'Amore for (nn = n->body->child; nn; nn = nn->next) { 147795c635efSGarrett D'Amore if (MDOC_It != nn->tok) 147895c635efSGarrett D'Amore continue; 147995c635efSGarrett D'Amore 148095c635efSGarrett D'Amore assert(MDOC_BLOCK == nn->type); 148195c635efSGarrett D'Amore nn = nn->head->child; 148295c635efSGarrett D'Amore 148395c635efSGarrett D'Amore if (nn == NULL) 148495c635efSGarrett D'Amore break; 148595c635efSGarrett D'Amore 148695c635efSGarrett D'Amore if (MDOC_TEXT == nn->type) { 148795c635efSGarrett D'Amore sz = strlen(nn->string) + 1; 148895c635efSGarrett D'Amore break; 148995c635efSGarrett D'Amore } 149095c635efSGarrett D'Amore 149195c635efSGarrett D'Amore if (0 != (ssz = macro2len(nn->tok))) 149295c635efSGarrett D'Amore sz = ssz; 149395c635efSGarrett D'Amore 149495c635efSGarrett D'Amore break; 149595c635efSGarrett D'Amore } 149695c635efSGarrett D'Amore 149795c635efSGarrett D'Amore /* Defaults to ten ens. */ 149895c635efSGarrett D'Amore 149995c635efSGarrett D'Amore snprintf(buf, NUMSIZ, "%un", (unsigned int)sz); 150095c635efSGarrett D'Amore 150195c635efSGarrett D'Amore /* 150295c635efSGarrett D'Amore * We have to dynamically add this to the macro's argument list. 150395c635efSGarrett D'Amore * We're guaranteed that a MDOC_Width doesn't already exist. 150495c635efSGarrett D'Amore */ 150595c635efSGarrett D'Amore 150695c635efSGarrett D'Amore assert(n->args); 150795c635efSGarrett D'Amore i = (int)(n->args->argc)++; 150895c635efSGarrett D'Amore 150995c635efSGarrett D'Amore n->args->argv = mandoc_realloc(n->args->argv, 151095c635efSGarrett D'Amore n->args->argc * sizeof(struct mdoc_argv)); 151195c635efSGarrett D'Amore 151295c635efSGarrett D'Amore n->args->argv[i].arg = MDOC_Width; 151395c635efSGarrett D'Amore n->args->argv[i].line = n->line; 151495c635efSGarrett D'Amore n->args->argv[i].pos = n->pos; 151595c635efSGarrett D'Amore n->args->argv[i].sz = 1; 151695c635efSGarrett D'Amore n->args->argv[i].value = mandoc_malloc(sizeof(char *)); 151795c635efSGarrett D'Amore n->args->argv[i].value[0] = mandoc_strdup(buf); 151895c635efSGarrett D'Amore 151995c635efSGarrett D'Amore /* Set our width! */ 152095c635efSGarrett D'Amore n->norm->Bl.width = n->args->argv[i].value[0]; 152195c635efSGarrett D'Amore return(1); 152295c635efSGarrett D'Amore } 152395c635efSGarrett D'Amore 152495c635efSGarrett D'Amore 152595c635efSGarrett D'Amore static int 152695c635efSGarrett D'Amore post_bl_head(POST_ARGS) 152795c635efSGarrett D'Amore { 152895c635efSGarrett D'Amore struct mdoc_node *np, *nn, *nnp; 152995c635efSGarrett D'Amore int i, j; 153095c635efSGarrett D'Amore 153195c635efSGarrett D'Amore if (LIST_column != mdoc->last->norm->Bl.type) 153295c635efSGarrett D'Amore /* FIXME: this should be ERROR class... */ 153395c635efSGarrett D'Amore return(hwarn_eq0(mdoc)); 153495c635efSGarrett D'Amore 153595c635efSGarrett D'Amore /* 153695c635efSGarrett D'Amore * Convert old-style lists, where the column width specifiers 153795c635efSGarrett D'Amore * trail as macro parameters, to the new-style ("normal-form") 153895c635efSGarrett D'Amore * lists where they're argument values following -column. 153995c635efSGarrett D'Amore */ 154095c635efSGarrett D'Amore 154195c635efSGarrett D'Amore /* First, disallow both types and allow normal-form. */ 154295c635efSGarrett D'Amore 154395c635efSGarrett D'Amore /* 154495c635efSGarrett D'Amore * TODO: technically, we can accept both and just merge the two 154595c635efSGarrett D'Amore * lists, but I'll leave that for another day. 154695c635efSGarrett D'Amore */ 154795c635efSGarrett D'Amore 154895c635efSGarrett D'Amore if (mdoc->last->norm->Bl.ncols && mdoc->last->nchild) { 154995c635efSGarrett D'Amore mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_COLUMNS); 155095c635efSGarrett D'Amore return(0); 155195c635efSGarrett D'Amore } else if (NULL == mdoc->last->child) 155295c635efSGarrett D'Amore return(1); 155395c635efSGarrett D'Amore 155495c635efSGarrett D'Amore np = mdoc->last->parent; 155595c635efSGarrett D'Amore assert(np->args); 155695c635efSGarrett D'Amore 155795c635efSGarrett D'Amore for (j = 0; j < (int)np->args->argc; j++) 155895c635efSGarrett D'Amore if (MDOC_Column == np->args->argv[j].arg) 155995c635efSGarrett D'Amore break; 156095c635efSGarrett D'Amore 156195c635efSGarrett D'Amore assert(j < (int)np->args->argc); 156295c635efSGarrett D'Amore assert(0 == np->args->argv[j].sz); 156395c635efSGarrett D'Amore 156495c635efSGarrett D'Amore /* 156595c635efSGarrett D'Amore * Accommodate for new-style groff column syntax. Shuffle the 156695c635efSGarrett D'Amore * child nodes, all of which must be TEXT, as arguments for the 156795c635efSGarrett D'Amore * column field. Then, delete the head children. 156895c635efSGarrett D'Amore */ 156995c635efSGarrett D'Amore 157095c635efSGarrett D'Amore np->args->argv[j].sz = (size_t)mdoc->last->nchild; 157195c635efSGarrett D'Amore np->args->argv[j].value = mandoc_malloc 157295c635efSGarrett D'Amore ((size_t)mdoc->last->nchild * sizeof(char *)); 157395c635efSGarrett D'Amore 157495c635efSGarrett D'Amore mdoc->last->norm->Bl.ncols = np->args->argv[j].sz; 157595c635efSGarrett D'Amore mdoc->last->norm->Bl.cols = (void *)np->args->argv[j].value; 157695c635efSGarrett D'Amore 157795c635efSGarrett D'Amore for (i = 0, nn = mdoc->last->child; nn; i++) { 157895c635efSGarrett D'Amore np->args->argv[j].value[i] = nn->string; 157995c635efSGarrett D'Amore nn->string = NULL; 158095c635efSGarrett D'Amore nnp = nn; 158195c635efSGarrett D'Amore nn = nn->next; 158295c635efSGarrett D'Amore mdoc_node_delete(NULL, nnp); 158395c635efSGarrett D'Amore } 158495c635efSGarrett D'Amore 158595c635efSGarrett D'Amore mdoc->last->nchild = 0; 158695c635efSGarrett D'Amore mdoc->last->child = NULL; 158795c635efSGarrett D'Amore 158895c635efSGarrett D'Amore return(1); 158995c635efSGarrett D'Amore } 159095c635efSGarrett D'Amore 159195c635efSGarrett D'Amore static int 159295c635efSGarrett D'Amore post_bl(POST_ARGS) 159395c635efSGarrett D'Amore { 1594*698f87a4SGarrett D'Amore struct mdoc_node *nparent, *nprev; /* of the Bl block */ 1595*698f87a4SGarrett D'Amore struct mdoc_node *nblock, *nbody; /* of the Bl */ 1596*698f87a4SGarrett D'Amore struct mdoc_node *nchild, *nnext; /* of the Bl body */ 159795c635efSGarrett D'Amore 1598*698f87a4SGarrett D'Amore nbody = mdoc->last; 1599*698f87a4SGarrett D'Amore switch (nbody->type) { 1600*698f87a4SGarrett D'Amore case (MDOC_BLOCK): 160195c635efSGarrett D'Amore return(post_bl_block(mdoc)); 1602*698f87a4SGarrett D'Amore case (MDOC_HEAD): 1603*698f87a4SGarrett D'Amore return(post_bl_head(mdoc)); 1604*698f87a4SGarrett D'Amore case (MDOC_BODY): 1605*698f87a4SGarrett D'Amore break; 1606*698f87a4SGarrett D'Amore default: 160795c635efSGarrett D'Amore return(1); 1608*698f87a4SGarrett D'Amore } 160995c635efSGarrett D'Amore 1610*698f87a4SGarrett D'Amore nchild = nbody->child; 1611*698f87a4SGarrett D'Amore while (NULL != nchild) { 1612*698f87a4SGarrett D'Amore if (MDOC_It == nchild->tok || MDOC_Sm == nchild->tok) { 1613*698f87a4SGarrett D'Amore nchild = nchild->next; 161495c635efSGarrett D'Amore continue; 161595c635efSGarrett D'Amore } 161695c635efSGarrett D'Amore 1617*698f87a4SGarrett D'Amore mdoc_nmsg(mdoc, nchild, MANDOCERR_CHILD); 1618*698f87a4SGarrett D'Amore 1619*698f87a4SGarrett D'Amore /* 1620*698f87a4SGarrett D'Amore * Move the node out of the Bl block. 1621*698f87a4SGarrett D'Amore * First, collect all required node pointers. 1622*698f87a4SGarrett D'Amore */ 1623*698f87a4SGarrett D'Amore 1624*698f87a4SGarrett D'Amore nblock = nbody->parent; 1625*698f87a4SGarrett D'Amore nprev = nblock->prev; 1626*698f87a4SGarrett D'Amore nparent = nblock->parent; 1627*698f87a4SGarrett D'Amore nnext = nchild->next; 1628*698f87a4SGarrett D'Amore 1629*698f87a4SGarrett D'Amore /* 1630*698f87a4SGarrett D'Amore * Unlink this child. 1631*698f87a4SGarrett D'Amore */ 1632*698f87a4SGarrett D'Amore 1633*698f87a4SGarrett D'Amore assert(NULL == nchild->prev); 1634*698f87a4SGarrett D'Amore if (0 == --nbody->nchild) { 1635*698f87a4SGarrett D'Amore nbody->child = NULL; 1636*698f87a4SGarrett D'Amore nbody->last = NULL; 1637*698f87a4SGarrett D'Amore assert(NULL == nnext); 1638*698f87a4SGarrett D'Amore } else { 1639*698f87a4SGarrett D'Amore nbody->child = nnext; 1640*698f87a4SGarrett D'Amore nnext->prev = NULL; 1641*698f87a4SGarrett D'Amore } 1642*698f87a4SGarrett D'Amore 1643*698f87a4SGarrett D'Amore /* 1644*698f87a4SGarrett D'Amore * Relink this child. 1645*698f87a4SGarrett D'Amore */ 1646*698f87a4SGarrett D'Amore 1647*698f87a4SGarrett D'Amore nchild->parent = nparent; 1648*698f87a4SGarrett D'Amore nchild->prev = nprev; 1649*698f87a4SGarrett D'Amore nchild->next = nblock; 1650*698f87a4SGarrett D'Amore 1651*698f87a4SGarrett D'Amore nblock->prev = nchild; 1652*698f87a4SGarrett D'Amore nparent->nchild++; 1653*698f87a4SGarrett D'Amore if (NULL == nprev) 1654*698f87a4SGarrett D'Amore nparent->child = nchild; 1655*698f87a4SGarrett D'Amore else 1656*698f87a4SGarrett D'Amore nprev->next = nchild; 1657*698f87a4SGarrett D'Amore 1658*698f87a4SGarrett D'Amore nchild = nnext; 165995c635efSGarrett D'Amore } 166095c635efSGarrett D'Amore 166195c635efSGarrett D'Amore return(1); 166295c635efSGarrett D'Amore } 166395c635efSGarrett D'Amore 166495c635efSGarrett D'Amore static int 166595c635efSGarrett D'Amore ebool(struct mdoc *mdoc) 166695c635efSGarrett D'Amore { 166795c635efSGarrett D'Amore 166895c635efSGarrett D'Amore if (NULL == mdoc->last->child) { 166995c635efSGarrett D'Amore mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_MACROEMPTY); 167095c635efSGarrett D'Amore mdoc_node_delete(mdoc, mdoc->last); 167195c635efSGarrett D'Amore return(1); 167295c635efSGarrett D'Amore } 167395c635efSGarrett D'Amore check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 1); 167495c635efSGarrett D'Amore 167595c635efSGarrett D'Amore assert(MDOC_TEXT == mdoc->last->child->type); 167695c635efSGarrett D'Amore 1677*698f87a4SGarrett D'Amore if (0 == strcmp(mdoc->last->child->string, "on")) { 1678*698f87a4SGarrett D'Amore if (MDOC_Sm == mdoc->last->tok) 1679*698f87a4SGarrett D'Amore mdoc->flags &= ~MDOC_SMOFF; 168095c635efSGarrett D'Amore return(1); 1681*698f87a4SGarrett D'Amore } 1682*698f87a4SGarrett D'Amore if (0 == strcmp(mdoc->last->child->string, "off")) { 1683*698f87a4SGarrett D'Amore if (MDOC_Sm == mdoc->last->tok) 1684*698f87a4SGarrett D'Amore mdoc->flags |= MDOC_SMOFF; 168595c635efSGarrett D'Amore return(1); 1686*698f87a4SGarrett D'Amore } 168795c635efSGarrett D'Amore 168895c635efSGarrett D'Amore mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADBOOL); 168995c635efSGarrett D'Amore return(1); 169095c635efSGarrett D'Amore } 169195c635efSGarrett D'Amore 169295c635efSGarrett D'Amore static int 169395c635efSGarrett D'Amore post_root(POST_ARGS) 169495c635efSGarrett D'Amore { 169595c635efSGarrett D'Amore int erc; 169695c635efSGarrett D'Amore struct mdoc_node *n; 169795c635efSGarrett D'Amore 169895c635efSGarrett D'Amore erc = 0; 169995c635efSGarrett D'Amore 170095c635efSGarrett D'Amore /* Check that we have a finished prologue. */ 170195c635efSGarrett D'Amore 170295c635efSGarrett D'Amore if ( ! (MDOC_PBODY & mdoc->flags)) { 170395c635efSGarrett D'Amore erc++; 170495c635efSGarrett D'Amore mdoc_nmsg(mdoc, mdoc->first, MANDOCERR_NODOCPROLOG); 170595c635efSGarrett D'Amore } 170695c635efSGarrett D'Amore 170795c635efSGarrett D'Amore n = mdoc->first; 170895c635efSGarrett D'Amore assert(n); 170995c635efSGarrett D'Amore 171095c635efSGarrett D'Amore /* Check that we begin with a proper `Sh'. */ 171195c635efSGarrett D'Amore 171295c635efSGarrett D'Amore if (NULL == n->child) { 171395c635efSGarrett D'Amore erc++; 171495c635efSGarrett D'Amore mdoc_nmsg(mdoc, n, MANDOCERR_NODOCBODY); 171595c635efSGarrett D'Amore } else if (MDOC_BLOCK != n->child->type || 171695c635efSGarrett D'Amore MDOC_Sh != n->child->tok) { 171795c635efSGarrett D'Amore erc++; 171895c635efSGarrett D'Amore /* Can this be lifted? See rxdebug.1 for example. */ 171995c635efSGarrett D'Amore mdoc_nmsg(mdoc, n, MANDOCERR_NODOCBODY); 172095c635efSGarrett D'Amore } 172195c635efSGarrett D'Amore 172295c635efSGarrett D'Amore return(erc ? 0 : 1); 172395c635efSGarrett D'Amore } 172495c635efSGarrett D'Amore 172595c635efSGarrett D'Amore static int 172695c635efSGarrett D'Amore post_st(POST_ARGS) 172795c635efSGarrett D'Amore { 172895c635efSGarrett D'Amore struct mdoc_node *ch; 172995c635efSGarrett D'Amore const char *p; 173095c635efSGarrett D'Amore 173195c635efSGarrett D'Amore if (NULL == (ch = mdoc->last->child)) { 173295c635efSGarrett D'Amore mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_MACROEMPTY); 173395c635efSGarrett D'Amore mdoc_node_delete(mdoc, mdoc->last); 173495c635efSGarrett D'Amore return(1); 173595c635efSGarrett D'Amore } 173695c635efSGarrett D'Amore 173795c635efSGarrett D'Amore assert(MDOC_TEXT == ch->type); 173895c635efSGarrett D'Amore 173995c635efSGarrett D'Amore if (NULL == (p = mdoc_a2st(ch->string))) { 174095c635efSGarrett D'Amore mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADSTANDARD); 174195c635efSGarrett D'Amore mdoc_node_delete(mdoc, mdoc->last); 174295c635efSGarrett D'Amore } else { 174395c635efSGarrett D'Amore free(ch->string); 174495c635efSGarrett D'Amore ch->string = mandoc_strdup(p); 174595c635efSGarrett D'Amore } 174695c635efSGarrett D'Amore 174795c635efSGarrett D'Amore return(1); 174895c635efSGarrett D'Amore } 174995c635efSGarrett D'Amore 175095c635efSGarrett D'Amore static int 175195c635efSGarrett D'Amore post_rs(POST_ARGS) 175295c635efSGarrett D'Amore { 175395c635efSGarrett D'Amore struct mdoc_node *nn, *next, *prev; 175495c635efSGarrett D'Amore int i, j; 175595c635efSGarrett D'Amore 175695c635efSGarrett D'Amore switch (mdoc->last->type) { 175795c635efSGarrett D'Amore case (MDOC_HEAD): 175895c635efSGarrett D'Amore check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_EQ, 0); 175995c635efSGarrett D'Amore return(1); 176095c635efSGarrett D'Amore case (MDOC_BODY): 176195c635efSGarrett D'Amore if (mdoc->last->child) 176295c635efSGarrett D'Amore break; 176395c635efSGarrett D'Amore check_count(mdoc, MDOC_BODY, CHECK_WARN, CHECK_GT, 0); 176495c635efSGarrett D'Amore return(1); 176595c635efSGarrett D'Amore default: 176695c635efSGarrett D'Amore return(1); 176795c635efSGarrett D'Amore } 176895c635efSGarrett D'Amore 176995c635efSGarrett D'Amore /* 177095c635efSGarrett D'Amore * Make sure only certain types of nodes are allowed within the 177195c635efSGarrett D'Amore * the `Rs' body. Delete offending nodes and raise a warning. 177295c635efSGarrett D'Amore * Do this before re-ordering for the sake of clarity. 177395c635efSGarrett D'Amore */ 177495c635efSGarrett D'Amore 177595c635efSGarrett D'Amore next = NULL; 177695c635efSGarrett D'Amore for (nn = mdoc->last->child; nn; nn = next) { 177795c635efSGarrett D'Amore for (i = 0; i < RSORD_MAX; i++) 177895c635efSGarrett D'Amore if (nn->tok == rsord[i]) 177995c635efSGarrett D'Amore break; 178095c635efSGarrett D'Amore 178195c635efSGarrett D'Amore if (i < RSORD_MAX) { 178295c635efSGarrett D'Amore if (MDOC__J == rsord[i] || MDOC__B == rsord[i]) 178395c635efSGarrett D'Amore mdoc->last->norm->Rs.quote_T++; 178495c635efSGarrett D'Amore next = nn->next; 178595c635efSGarrett D'Amore continue; 178695c635efSGarrett D'Amore } 178795c635efSGarrett D'Amore 178895c635efSGarrett D'Amore next = nn->next; 178995c635efSGarrett D'Amore mdoc_nmsg(mdoc, nn, MANDOCERR_CHILD); 179095c635efSGarrett D'Amore mdoc_node_delete(mdoc, nn); 179195c635efSGarrett D'Amore } 179295c635efSGarrett D'Amore 179395c635efSGarrett D'Amore /* 179495c635efSGarrett D'Amore * Nothing to sort if only invalid nodes were found 179595c635efSGarrett D'Amore * inside the `Rs' body. 179695c635efSGarrett D'Amore */ 179795c635efSGarrett D'Amore 179895c635efSGarrett D'Amore if (NULL == mdoc->last->child) 179995c635efSGarrett D'Amore return(1); 180095c635efSGarrett D'Amore 180195c635efSGarrett D'Amore /* 180295c635efSGarrett D'Amore * The full `Rs' block needs special handling to order the 180395c635efSGarrett D'Amore * sub-elements according to `rsord'. Pick through each element 180495c635efSGarrett D'Amore * and correctly order it. This is a insertion sort. 180595c635efSGarrett D'Amore */ 180695c635efSGarrett D'Amore 180795c635efSGarrett D'Amore next = NULL; 180895c635efSGarrett D'Amore for (nn = mdoc->last->child->next; nn; nn = next) { 180995c635efSGarrett D'Amore /* Determine order of `nn'. */ 181095c635efSGarrett D'Amore for (i = 0; i < RSORD_MAX; i++) 181195c635efSGarrett D'Amore if (rsord[i] == nn->tok) 181295c635efSGarrett D'Amore break; 181395c635efSGarrett D'Amore 181495c635efSGarrett D'Amore /* 181595c635efSGarrett D'Amore * Remove `nn' from the chain. This somewhat 181695c635efSGarrett D'Amore * repeats mdoc_node_unlink(), but since we're 181795c635efSGarrett D'Amore * just re-ordering, there's no need for the 181895c635efSGarrett D'Amore * full unlink process. 181995c635efSGarrett D'Amore */ 182095c635efSGarrett D'Amore 182195c635efSGarrett D'Amore if (NULL != (next = nn->next)) 182295c635efSGarrett D'Amore next->prev = nn->prev; 182395c635efSGarrett D'Amore 182495c635efSGarrett D'Amore if (NULL != (prev = nn->prev)) 182595c635efSGarrett D'Amore prev->next = nn->next; 182695c635efSGarrett D'Amore 182795c635efSGarrett D'Amore nn->prev = nn->next = NULL; 182895c635efSGarrett D'Amore 182995c635efSGarrett D'Amore /* 183095c635efSGarrett D'Amore * Scan back until we reach a node that's 183195c635efSGarrett D'Amore * ordered before `nn'. 183295c635efSGarrett D'Amore */ 183395c635efSGarrett D'Amore 183495c635efSGarrett D'Amore for ( ; prev ; prev = prev->prev) { 183595c635efSGarrett D'Amore /* Determine order of `prev'. */ 183695c635efSGarrett D'Amore for (j = 0; j < RSORD_MAX; j++) 183795c635efSGarrett D'Amore if (rsord[j] == prev->tok) 183895c635efSGarrett D'Amore break; 183995c635efSGarrett D'Amore 184095c635efSGarrett D'Amore if (j <= i) 184195c635efSGarrett D'Amore break; 184295c635efSGarrett D'Amore } 184395c635efSGarrett D'Amore 184495c635efSGarrett D'Amore /* 184595c635efSGarrett D'Amore * Set `nn' back into its correct place in front 184695c635efSGarrett D'Amore * of the `prev' node. 184795c635efSGarrett D'Amore */ 184895c635efSGarrett D'Amore 184995c635efSGarrett D'Amore nn->prev = prev; 185095c635efSGarrett D'Amore 185195c635efSGarrett D'Amore if (prev) { 185295c635efSGarrett D'Amore if (prev->next) 185395c635efSGarrett D'Amore prev->next->prev = nn; 185495c635efSGarrett D'Amore nn->next = prev->next; 185595c635efSGarrett D'Amore prev->next = nn; 185695c635efSGarrett D'Amore } else { 185795c635efSGarrett D'Amore mdoc->last->child->prev = nn; 185895c635efSGarrett D'Amore nn->next = mdoc->last->child; 185995c635efSGarrett D'Amore mdoc->last->child = nn; 186095c635efSGarrett D'Amore } 186195c635efSGarrett D'Amore } 186295c635efSGarrett D'Amore 186395c635efSGarrett D'Amore return(1); 186495c635efSGarrett D'Amore } 186595c635efSGarrett D'Amore 1866*698f87a4SGarrett D'Amore /* 1867*698f87a4SGarrett D'Amore * For some arguments of some macros, 1868*698f87a4SGarrett D'Amore * convert all breakable hyphens into ASCII_HYPH. 1869*698f87a4SGarrett D'Amore */ 1870*698f87a4SGarrett D'Amore static int 1871*698f87a4SGarrett D'Amore post_hyph(POST_ARGS) 1872*698f87a4SGarrett D'Amore { 1873*698f87a4SGarrett D'Amore struct mdoc_node *n, *nch; 1874*698f87a4SGarrett D'Amore char *cp; 1875*698f87a4SGarrett D'Amore 1876*698f87a4SGarrett D'Amore n = mdoc->last; 1877*698f87a4SGarrett D'Amore switch (n->type) { 1878*698f87a4SGarrett D'Amore case (MDOC_HEAD): 1879*698f87a4SGarrett D'Amore if (MDOC_Sh == n->tok || MDOC_Ss == n->tok) 1880*698f87a4SGarrett D'Amore break; 1881*698f87a4SGarrett D'Amore return(1); 1882*698f87a4SGarrett D'Amore case (MDOC_BODY): 1883*698f87a4SGarrett D'Amore if (MDOC_D1 == n->tok || MDOC_Nd == n->tok) 1884*698f87a4SGarrett D'Amore break; 1885*698f87a4SGarrett D'Amore return(1); 1886*698f87a4SGarrett D'Amore case (MDOC_ELEM): 1887*698f87a4SGarrett D'Amore break; 1888*698f87a4SGarrett D'Amore default: 1889*698f87a4SGarrett D'Amore return(1); 1890*698f87a4SGarrett D'Amore } 1891*698f87a4SGarrett D'Amore 1892*698f87a4SGarrett D'Amore for (nch = n->child; nch; nch = nch->next) { 1893*698f87a4SGarrett D'Amore if (MDOC_TEXT != nch->type) 1894*698f87a4SGarrett D'Amore continue; 1895*698f87a4SGarrett D'Amore cp = nch->string; 1896*698f87a4SGarrett D'Amore if (3 > strnlen(cp, 3)) 1897*698f87a4SGarrett D'Amore continue; 1898*698f87a4SGarrett D'Amore while ('\0' != *(++cp)) 1899*698f87a4SGarrett D'Amore if ('-' == *cp && 1900*698f87a4SGarrett D'Amore isalpha((unsigned char)cp[-1]) && 1901*698f87a4SGarrett D'Amore isalpha((unsigned char)cp[1])) 1902*698f87a4SGarrett D'Amore *cp = ASCII_HYPH; 1903*698f87a4SGarrett D'Amore } 1904*698f87a4SGarrett D'Amore return(1); 1905*698f87a4SGarrett D'Amore } 1906*698f87a4SGarrett D'Amore 190795c635efSGarrett D'Amore static int 190895c635efSGarrett D'Amore post_ns(POST_ARGS) 190995c635efSGarrett D'Amore { 191095c635efSGarrett D'Amore 191195c635efSGarrett D'Amore if (MDOC_LINE & mdoc->last->flags) 191295c635efSGarrett D'Amore mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_IGNNS); 191395c635efSGarrett D'Amore return(1); 191495c635efSGarrett D'Amore } 191595c635efSGarrett D'Amore 191695c635efSGarrett D'Amore static int 191795c635efSGarrett D'Amore post_sh(POST_ARGS) 191895c635efSGarrett D'Amore { 191995c635efSGarrett D'Amore 192095c635efSGarrett D'Amore if (MDOC_HEAD == mdoc->last->type) 192195c635efSGarrett D'Amore return(post_sh_head(mdoc)); 192295c635efSGarrett D'Amore if (MDOC_BODY == mdoc->last->type) 192395c635efSGarrett D'Amore return(post_sh_body(mdoc)); 192495c635efSGarrett D'Amore 192595c635efSGarrett D'Amore return(1); 192695c635efSGarrett D'Amore } 192795c635efSGarrett D'Amore 192895c635efSGarrett D'Amore static int 192995c635efSGarrett D'Amore post_sh_body(POST_ARGS) 193095c635efSGarrett D'Amore { 193195c635efSGarrett D'Amore struct mdoc_node *n; 193295c635efSGarrett D'Amore 193395c635efSGarrett D'Amore if (SEC_NAME != mdoc->lastsec) 193495c635efSGarrett D'Amore return(1); 193595c635efSGarrett D'Amore 193695c635efSGarrett D'Amore /* 193795c635efSGarrett D'Amore * Warn if the NAME section doesn't contain the `Nm' and `Nd' 193895c635efSGarrett D'Amore * macros (can have multiple `Nm' and one `Nd'). Note that the 193995c635efSGarrett D'Amore * children of the BODY declaration can also be "text". 194095c635efSGarrett D'Amore */ 194195c635efSGarrett D'Amore 194295c635efSGarrett D'Amore if (NULL == (n = mdoc->last->child)) { 194395c635efSGarrett D'Amore mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADNAMESEC); 194495c635efSGarrett D'Amore return(1); 194595c635efSGarrett D'Amore } 194695c635efSGarrett D'Amore 194795c635efSGarrett D'Amore for ( ; n && n->next; n = n->next) { 194895c635efSGarrett D'Amore if (MDOC_ELEM == n->type && MDOC_Nm == n->tok) 194995c635efSGarrett D'Amore continue; 195095c635efSGarrett D'Amore if (MDOC_TEXT == n->type) 195195c635efSGarrett D'Amore continue; 195295c635efSGarrett D'Amore mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADNAMESEC); 195395c635efSGarrett D'Amore } 195495c635efSGarrett D'Amore 195595c635efSGarrett D'Amore assert(n); 195695c635efSGarrett D'Amore if (MDOC_BLOCK == n->type && MDOC_Nd == n->tok) 195795c635efSGarrett D'Amore return(1); 195895c635efSGarrett D'Amore 195995c635efSGarrett D'Amore mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADNAMESEC); 196095c635efSGarrett D'Amore return(1); 196195c635efSGarrett D'Amore } 196295c635efSGarrett D'Amore 196395c635efSGarrett D'Amore static int 196495c635efSGarrett D'Amore post_sh_head(POST_ARGS) 196595c635efSGarrett D'Amore { 196695c635efSGarrett D'Amore char buf[BUFSIZ]; 196795c635efSGarrett D'Amore struct mdoc_node *n; 196895c635efSGarrett D'Amore enum mdoc_sec sec; 196995c635efSGarrett D'Amore int c; 197095c635efSGarrett D'Amore 197195c635efSGarrett D'Amore /* 197295c635efSGarrett D'Amore * Process a new section. Sections are either "named" or 197395c635efSGarrett D'Amore * "custom". Custom sections are user-defined, while named ones 197495c635efSGarrett D'Amore * follow a conventional order and may only appear in certain 197595c635efSGarrett D'Amore * manual sections. 197695c635efSGarrett D'Amore */ 197795c635efSGarrett D'Amore 197895c635efSGarrett D'Amore sec = SEC_CUSTOM; 197995c635efSGarrett D'Amore buf[0] = '\0'; 198095c635efSGarrett D'Amore if (-1 == (c = concat(buf, mdoc->last->child, BUFSIZ))) { 198195c635efSGarrett D'Amore mdoc_nmsg(mdoc, mdoc->last->child, MANDOCERR_MEM); 198295c635efSGarrett D'Amore return(0); 198395c635efSGarrett D'Amore } else if (1 == c) 198495c635efSGarrett D'Amore sec = a2sec(buf); 198595c635efSGarrett D'Amore 198695c635efSGarrett D'Amore /* The NAME should be first. */ 198795c635efSGarrett D'Amore 198895c635efSGarrett D'Amore if (SEC_NAME != sec && SEC_NONE == mdoc->lastnamed) 198995c635efSGarrett D'Amore mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NAMESECFIRST); 199095c635efSGarrett D'Amore 199195c635efSGarrett D'Amore /* The SYNOPSIS gets special attention in other areas. */ 199295c635efSGarrett D'Amore 1993*698f87a4SGarrett D'Amore if (SEC_SYNOPSIS == sec) { 1994*698f87a4SGarrett D'Amore roff_setreg(mdoc->roff, "nS", 1, '='); 199595c635efSGarrett D'Amore mdoc->flags |= MDOC_SYNOPSIS; 1996*698f87a4SGarrett D'Amore } else { 1997*698f87a4SGarrett D'Amore roff_setreg(mdoc->roff, "nS", 0, '='); 199895c635efSGarrett D'Amore mdoc->flags &= ~MDOC_SYNOPSIS; 1999*698f87a4SGarrett D'Amore } 200095c635efSGarrett D'Amore 200195c635efSGarrett D'Amore /* Mark our last section. */ 200295c635efSGarrett D'Amore 200395c635efSGarrett D'Amore mdoc->lastsec = sec; 200495c635efSGarrett D'Amore 200595c635efSGarrett D'Amore /* 200695c635efSGarrett D'Amore * Set the section attribute for the current HEAD, for its 200795c635efSGarrett D'Amore * parent BLOCK, and for the HEAD children; the latter can 200895c635efSGarrett D'Amore * only be TEXT nodes, so no recursion is needed. 200995c635efSGarrett D'Amore * For other blocks and elements, including .Sh BODY, this is 201095c635efSGarrett D'Amore * done when allocating the node data structures, but for .Sh 201195c635efSGarrett D'Amore * BLOCK and HEAD, the section is still unknown at that time. 201295c635efSGarrett D'Amore */ 201395c635efSGarrett D'Amore 201495c635efSGarrett D'Amore mdoc->last->parent->sec = sec; 201595c635efSGarrett D'Amore mdoc->last->sec = sec; 201695c635efSGarrett D'Amore for (n = mdoc->last->child; n; n = n->next) 201795c635efSGarrett D'Amore n->sec = sec; 201895c635efSGarrett D'Amore 201995c635efSGarrett D'Amore /* We don't care about custom sections after this. */ 202095c635efSGarrett D'Amore 202195c635efSGarrett D'Amore if (SEC_CUSTOM == sec) 202295c635efSGarrett D'Amore return(1); 202395c635efSGarrett D'Amore 202495c635efSGarrett D'Amore /* 202595c635efSGarrett D'Amore * Check whether our non-custom section is being repeated or is 202695c635efSGarrett D'Amore * out of order. 202795c635efSGarrett D'Amore */ 202895c635efSGarrett D'Amore 202995c635efSGarrett D'Amore if (sec == mdoc->lastnamed) 203095c635efSGarrett D'Amore mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_SECREP); 203195c635efSGarrett D'Amore 203295c635efSGarrett D'Amore if (sec < mdoc->lastnamed) 203395c635efSGarrett D'Amore mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_SECOOO); 203495c635efSGarrett D'Amore 203595c635efSGarrett D'Amore /* Mark the last named section. */ 203695c635efSGarrett D'Amore 203795c635efSGarrett D'Amore mdoc->lastnamed = sec; 203895c635efSGarrett D'Amore 203995c635efSGarrett D'Amore /* Check particular section/manual conventions. */ 204095c635efSGarrett D'Amore 204195c635efSGarrett D'Amore assert(mdoc->meta.msec); 204295c635efSGarrett D'Amore 204395c635efSGarrett D'Amore switch (sec) { 204495c635efSGarrett D'Amore case (SEC_RETURN_VALUES): 204595c635efSGarrett D'Amore /* FALLTHROUGH */ 204695c635efSGarrett D'Amore case (SEC_ERRORS): 204795c635efSGarrett D'Amore /* FALLTHROUGH */ 204895c635efSGarrett D'Amore case (SEC_LIBRARY): 204995c635efSGarrett D'Amore if (*mdoc->meta.msec == '2') 205095c635efSGarrett D'Amore break; 205195c635efSGarrett D'Amore if (*mdoc->meta.msec == '3') 205295c635efSGarrett D'Amore break; 205395c635efSGarrett D'Amore if (*mdoc->meta.msec == '9') 205495c635efSGarrett D'Amore break; 2055*698f87a4SGarrett D'Amore mandoc_msg(MANDOCERR_SECMSEC, mdoc->parse, 2056*698f87a4SGarrett D'Amore mdoc->last->line, mdoc->last->pos, buf); 205795c635efSGarrett D'Amore break; 205895c635efSGarrett D'Amore default: 205995c635efSGarrett D'Amore break; 206095c635efSGarrett D'Amore } 206195c635efSGarrett D'Amore 206295c635efSGarrett D'Amore return(1); 206395c635efSGarrett D'Amore } 206495c635efSGarrett D'Amore 206595c635efSGarrett D'Amore static int 206695c635efSGarrett D'Amore post_ignpar(POST_ARGS) 206795c635efSGarrett D'Amore { 206895c635efSGarrett D'Amore struct mdoc_node *np; 206995c635efSGarrett D'Amore 207095c635efSGarrett D'Amore if (MDOC_BODY != mdoc->last->type) 207195c635efSGarrett D'Amore return(1); 207295c635efSGarrett D'Amore 207395c635efSGarrett D'Amore if (NULL != (np = mdoc->last->child)) 207495c635efSGarrett D'Amore if (MDOC_Pp == np->tok || MDOC_Lp == np->tok) { 207595c635efSGarrett D'Amore mdoc_nmsg(mdoc, np, MANDOCERR_IGNPAR); 207695c635efSGarrett D'Amore mdoc_node_delete(mdoc, np); 207795c635efSGarrett D'Amore } 207895c635efSGarrett D'Amore 207995c635efSGarrett D'Amore if (NULL != (np = mdoc->last->last)) 208095c635efSGarrett D'Amore if (MDOC_Pp == np->tok || MDOC_Lp == np->tok) { 208195c635efSGarrett D'Amore mdoc_nmsg(mdoc, np, MANDOCERR_IGNPAR); 208295c635efSGarrett D'Amore mdoc_node_delete(mdoc, np); 208395c635efSGarrett D'Amore } 208495c635efSGarrett D'Amore 208595c635efSGarrett D'Amore return(1); 208695c635efSGarrett D'Amore } 208795c635efSGarrett D'Amore 208895c635efSGarrett D'Amore static int 208995c635efSGarrett D'Amore pre_par(PRE_ARGS) 209095c635efSGarrett D'Amore { 209195c635efSGarrett D'Amore 209295c635efSGarrett D'Amore if (NULL == mdoc->last) 209395c635efSGarrett D'Amore return(1); 209495c635efSGarrett D'Amore if (MDOC_ELEM != n->type && MDOC_BLOCK != n->type) 209595c635efSGarrett D'Amore return(1); 209695c635efSGarrett D'Amore 209795c635efSGarrett D'Amore /* 209895c635efSGarrett D'Amore * Don't allow prior `Lp' or `Pp' prior to a paragraph-type 209995c635efSGarrett D'Amore * block: `Lp', `Pp', or non-compact `Bd' or `Bl'. 210095c635efSGarrett D'Amore */ 210195c635efSGarrett D'Amore 2102*698f87a4SGarrett D'Amore if (MDOC_Pp != mdoc->last->tok && 2103*698f87a4SGarrett D'Amore MDOC_Lp != mdoc->last->tok && 2104*698f87a4SGarrett D'Amore MDOC_br != mdoc->last->tok) 210595c635efSGarrett D'Amore return(1); 210695c635efSGarrett D'Amore if (MDOC_Bl == n->tok && n->norm->Bl.comp) 210795c635efSGarrett D'Amore return(1); 210895c635efSGarrett D'Amore if (MDOC_Bd == n->tok && n->norm->Bd.comp) 210995c635efSGarrett D'Amore return(1); 211095c635efSGarrett D'Amore if (MDOC_It == n->tok && n->parent->norm->Bl.comp) 211195c635efSGarrett D'Amore return(1); 211295c635efSGarrett D'Amore 211395c635efSGarrett D'Amore mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_IGNPAR); 211495c635efSGarrett D'Amore mdoc_node_delete(mdoc, mdoc->last); 211595c635efSGarrett D'Amore return(1); 211695c635efSGarrett D'Amore } 211795c635efSGarrett D'Amore 2118*698f87a4SGarrett D'Amore static int 2119*698f87a4SGarrett D'Amore post_par(POST_ARGS) 2120*698f87a4SGarrett D'Amore { 2121*698f87a4SGarrett D'Amore 2122*698f87a4SGarrett D'Amore if (MDOC_ELEM != mdoc->last->type && 2123*698f87a4SGarrett D'Amore MDOC_BLOCK != mdoc->last->type) 2124*698f87a4SGarrett D'Amore return(1); 2125*698f87a4SGarrett D'Amore 2126*698f87a4SGarrett D'Amore if (NULL == mdoc->last->prev) { 2127*698f87a4SGarrett D'Amore if (MDOC_Sh != mdoc->last->parent->tok && 2128*698f87a4SGarrett D'Amore MDOC_Ss != mdoc->last->parent->tok) 2129*698f87a4SGarrett D'Amore return(1); 2130*698f87a4SGarrett D'Amore } else { 2131*698f87a4SGarrett D'Amore if (MDOC_Pp != mdoc->last->prev->tok && 2132*698f87a4SGarrett D'Amore MDOC_Lp != mdoc->last->prev->tok && 2133*698f87a4SGarrett D'Amore (MDOC_br != mdoc->last->tok || 2134*698f87a4SGarrett D'Amore (MDOC_sp != mdoc->last->prev->tok && 2135*698f87a4SGarrett D'Amore MDOC_br != mdoc->last->prev->tok))) 2136*698f87a4SGarrett D'Amore return(1); 2137*698f87a4SGarrett D'Amore } 2138*698f87a4SGarrett D'Amore 2139*698f87a4SGarrett D'Amore mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_IGNPAR); 2140*698f87a4SGarrett D'Amore mdoc_node_delete(mdoc, mdoc->last); 2141*698f87a4SGarrett D'Amore return(1); 2142*698f87a4SGarrett D'Amore } 2143*698f87a4SGarrett D'Amore 214495c635efSGarrett D'Amore static int 214595c635efSGarrett D'Amore pre_literal(PRE_ARGS) 214695c635efSGarrett D'Amore { 214795c635efSGarrett D'Amore 214895c635efSGarrett D'Amore if (MDOC_BODY != n->type) 214995c635efSGarrett D'Amore return(1); 215095c635efSGarrett D'Amore 215195c635efSGarrett D'Amore /* 215295c635efSGarrett D'Amore * The `Dl' (note "el" not "one") and `Bd -literal' and `Bd 215395c635efSGarrett D'Amore * -unfilled' macros set MDOC_LITERAL on entrance to the body. 215495c635efSGarrett D'Amore */ 215595c635efSGarrett D'Amore 215695c635efSGarrett D'Amore switch (n->tok) { 215795c635efSGarrett D'Amore case (MDOC_Dl): 215895c635efSGarrett D'Amore mdoc->flags |= MDOC_LITERAL; 215995c635efSGarrett D'Amore break; 216095c635efSGarrett D'Amore case (MDOC_Bd): 216195c635efSGarrett D'Amore if (DISP_literal == n->norm->Bd.type) 216295c635efSGarrett D'Amore mdoc->flags |= MDOC_LITERAL; 216395c635efSGarrett D'Amore if (DISP_unfilled == n->norm->Bd.type) 216495c635efSGarrett D'Amore mdoc->flags |= MDOC_LITERAL; 216595c635efSGarrett D'Amore break; 216695c635efSGarrett D'Amore default: 216795c635efSGarrett D'Amore abort(); 216895c635efSGarrett D'Amore /* NOTREACHED */ 216995c635efSGarrett D'Amore } 217095c635efSGarrett D'Amore 217195c635efSGarrett D'Amore return(1); 217295c635efSGarrett D'Amore } 217395c635efSGarrett D'Amore 217495c635efSGarrett D'Amore static int 217595c635efSGarrett D'Amore post_dd(POST_ARGS) 217695c635efSGarrett D'Amore { 217795c635efSGarrett D'Amore char buf[DATESIZE]; 217895c635efSGarrett D'Amore struct mdoc_node *n; 217995c635efSGarrett D'Amore int c; 218095c635efSGarrett D'Amore 218195c635efSGarrett D'Amore if (mdoc->meta.date) 218295c635efSGarrett D'Amore free(mdoc->meta.date); 218395c635efSGarrett D'Amore 218495c635efSGarrett D'Amore n = mdoc->last; 218595c635efSGarrett D'Amore if (NULL == n->child || '\0' == n->child->string[0]) { 218695c635efSGarrett D'Amore mdoc->meta.date = mandoc_normdate 218795c635efSGarrett D'Amore (mdoc->parse, NULL, n->line, n->pos); 218895c635efSGarrett D'Amore return(1); 218995c635efSGarrett D'Amore } 219095c635efSGarrett D'Amore 219195c635efSGarrett D'Amore buf[0] = '\0'; 219295c635efSGarrett D'Amore if (-1 == (c = concat(buf, n->child, DATESIZE))) { 219395c635efSGarrett D'Amore mdoc_nmsg(mdoc, n->child, MANDOCERR_MEM); 219495c635efSGarrett D'Amore return(0); 219595c635efSGarrett D'Amore } 219695c635efSGarrett D'Amore 219795c635efSGarrett D'Amore assert(c); 219895c635efSGarrett D'Amore mdoc->meta.date = mandoc_normdate 219995c635efSGarrett D'Amore (mdoc->parse, buf, n->line, n->pos); 220095c635efSGarrett D'Amore 220195c635efSGarrett D'Amore return(1); 220295c635efSGarrett D'Amore } 220395c635efSGarrett D'Amore 220495c635efSGarrett D'Amore static int 220595c635efSGarrett D'Amore post_dt(POST_ARGS) 220695c635efSGarrett D'Amore { 220795c635efSGarrett D'Amore struct mdoc_node *nn, *n; 220895c635efSGarrett D'Amore const char *cp; 220995c635efSGarrett D'Amore char *p; 221095c635efSGarrett D'Amore 221195c635efSGarrett D'Amore n = mdoc->last; 221295c635efSGarrett D'Amore 221395c635efSGarrett D'Amore if (mdoc->meta.title) 221495c635efSGarrett D'Amore free(mdoc->meta.title); 221595c635efSGarrett D'Amore if (mdoc->meta.vol) 221695c635efSGarrett D'Amore free(mdoc->meta.vol); 221795c635efSGarrett D'Amore if (mdoc->meta.arch) 221895c635efSGarrett D'Amore free(mdoc->meta.arch); 221995c635efSGarrett D'Amore 222095c635efSGarrett D'Amore mdoc->meta.title = mdoc->meta.vol = mdoc->meta.arch = NULL; 222195c635efSGarrett D'Amore 222295c635efSGarrett D'Amore /* First make all characters uppercase. */ 222395c635efSGarrett D'Amore 222495c635efSGarrett D'Amore if (NULL != (nn = n->child)) 222595c635efSGarrett D'Amore for (p = nn->string; *p; p++) { 222695c635efSGarrett D'Amore if (toupper((unsigned char)*p) == *p) 222795c635efSGarrett D'Amore continue; 222895c635efSGarrett D'Amore 222995c635efSGarrett D'Amore /* 223095c635efSGarrett D'Amore * FIXME: don't be lazy: have this make all 223195c635efSGarrett D'Amore * characters be uppercase and just warn once. 223295c635efSGarrett D'Amore */ 223395c635efSGarrett D'Amore mdoc_nmsg(mdoc, nn, MANDOCERR_UPPERCASE); 223495c635efSGarrett D'Amore break; 223595c635efSGarrett D'Amore } 223695c635efSGarrett D'Amore 223795c635efSGarrett D'Amore /* Handles: `.Dt' 223895c635efSGarrett D'Amore * --> title = unknown, volume = local, msec = 0, arch = NULL 223995c635efSGarrett D'Amore */ 224095c635efSGarrett D'Amore 224195c635efSGarrett D'Amore if (NULL == (nn = n->child)) { 224295c635efSGarrett D'Amore /* XXX: make these macro values. */ 224395c635efSGarrett D'Amore /* FIXME: warn about missing values. */ 224495c635efSGarrett D'Amore mdoc->meta.title = mandoc_strdup("UNKNOWN"); 224595c635efSGarrett D'Amore mdoc->meta.vol = mandoc_strdup("LOCAL"); 224695c635efSGarrett D'Amore mdoc->meta.msec = mandoc_strdup("1"); 224795c635efSGarrett D'Amore return(1); 224895c635efSGarrett D'Amore } 224995c635efSGarrett D'Amore 225095c635efSGarrett D'Amore /* Handles: `.Dt TITLE' 225195c635efSGarrett D'Amore * --> title = TITLE, volume = local, msec = 0, arch = NULL 225295c635efSGarrett D'Amore */ 225395c635efSGarrett D'Amore 225495c635efSGarrett D'Amore mdoc->meta.title = mandoc_strdup 225595c635efSGarrett D'Amore ('\0' == nn->string[0] ? "UNKNOWN" : nn->string); 225695c635efSGarrett D'Amore 225795c635efSGarrett D'Amore if (NULL == (nn = nn->next)) { 225895c635efSGarrett D'Amore /* FIXME: warn about missing msec. */ 225995c635efSGarrett D'Amore /* XXX: make this a macro value. */ 226095c635efSGarrett D'Amore mdoc->meta.vol = mandoc_strdup("LOCAL"); 226195c635efSGarrett D'Amore mdoc->meta.msec = mandoc_strdup("1"); 226295c635efSGarrett D'Amore return(1); 226395c635efSGarrett D'Amore } 226495c635efSGarrett D'Amore 226595c635efSGarrett D'Amore /* Handles: `.Dt TITLE SEC' 226695c635efSGarrett D'Amore * --> title = TITLE, volume = SEC is msec ? 226795c635efSGarrett D'Amore * format(msec) : SEC, 226895c635efSGarrett D'Amore * msec = SEC is msec ? atoi(msec) : 0, 226995c635efSGarrett D'Amore * arch = NULL 227095c635efSGarrett D'Amore */ 227195c635efSGarrett D'Amore 227295c635efSGarrett D'Amore cp = mandoc_a2msec(nn->string); 227395c635efSGarrett D'Amore if (cp) { 227495c635efSGarrett D'Amore mdoc->meta.vol = mandoc_strdup(cp); 227595c635efSGarrett D'Amore mdoc->meta.msec = mandoc_strdup(nn->string); 227695c635efSGarrett D'Amore } else { 227795c635efSGarrett D'Amore mdoc_nmsg(mdoc, n, MANDOCERR_BADMSEC); 227895c635efSGarrett D'Amore mdoc->meta.vol = mandoc_strdup(nn->string); 227995c635efSGarrett D'Amore mdoc->meta.msec = mandoc_strdup(nn->string); 228095c635efSGarrett D'Amore } 228195c635efSGarrett D'Amore 228295c635efSGarrett D'Amore if (NULL == (nn = nn->next)) 228395c635efSGarrett D'Amore return(1); 228495c635efSGarrett D'Amore 228595c635efSGarrett D'Amore /* Handles: `.Dt TITLE SEC VOL' 228695c635efSGarrett D'Amore * --> title = TITLE, volume = VOL is vol ? 228795c635efSGarrett D'Amore * format(VOL) : 228895c635efSGarrett D'Amore * VOL is arch ? format(arch) : 228995c635efSGarrett D'Amore * VOL 229095c635efSGarrett D'Amore */ 229195c635efSGarrett D'Amore 229295c635efSGarrett D'Amore cp = mdoc_a2vol(nn->string); 229395c635efSGarrett D'Amore if (cp) { 229495c635efSGarrett D'Amore free(mdoc->meta.vol); 229595c635efSGarrett D'Amore mdoc->meta.vol = mandoc_strdup(cp); 229695c635efSGarrett D'Amore } else { 229795c635efSGarrett D'Amore cp = mdoc_a2arch(nn->string); 229895c635efSGarrett D'Amore if (NULL == cp) { 2299*698f87a4SGarrett D'Amore mdoc_nmsg(mdoc, nn, MANDOCERR_BADVOLARCH); 230095c635efSGarrett D'Amore free(mdoc->meta.vol); 230195c635efSGarrett D'Amore mdoc->meta.vol = mandoc_strdup(nn->string); 230295c635efSGarrett D'Amore } else 230395c635efSGarrett D'Amore mdoc->meta.arch = mandoc_strdup(cp); 230495c635efSGarrett D'Amore } 230595c635efSGarrett D'Amore 230695c635efSGarrett D'Amore /* Ignore any subsequent parameters... */ 230795c635efSGarrett D'Amore /* FIXME: warn about subsequent parameters. */ 230895c635efSGarrett D'Amore 230995c635efSGarrett D'Amore return(1); 231095c635efSGarrett D'Amore } 231195c635efSGarrett D'Amore 231295c635efSGarrett D'Amore static int 231395c635efSGarrett D'Amore post_prol(POST_ARGS) 231495c635efSGarrett D'Amore { 231595c635efSGarrett D'Amore /* 231695c635efSGarrett D'Amore * Remove prologue macros from the document after they're 231795c635efSGarrett D'Amore * processed. The final document uses mdoc_meta for these 231895c635efSGarrett D'Amore * values and discards the originals. 231995c635efSGarrett D'Amore */ 232095c635efSGarrett D'Amore 232195c635efSGarrett D'Amore mdoc_node_delete(mdoc, mdoc->last); 232295c635efSGarrett D'Amore if (mdoc->meta.title && mdoc->meta.date && mdoc->meta.os) 232395c635efSGarrett D'Amore mdoc->flags |= MDOC_PBODY; 232495c635efSGarrett D'Amore 232595c635efSGarrett D'Amore return(1); 232695c635efSGarrett D'Amore } 232795c635efSGarrett D'Amore 232895c635efSGarrett D'Amore static int 232995c635efSGarrett D'Amore post_bx(POST_ARGS) 233095c635efSGarrett D'Amore { 233195c635efSGarrett D'Amore struct mdoc_node *n; 233295c635efSGarrett D'Amore 233395c635efSGarrett D'Amore /* 233495c635efSGarrett D'Amore * Make `Bx's second argument always start with an uppercase 233595c635efSGarrett D'Amore * letter. Groff checks if it's an "accepted" term, but we just 233695c635efSGarrett D'Amore * uppercase blindly. 233795c635efSGarrett D'Amore */ 233895c635efSGarrett D'Amore 233995c635efSGarrett D'Amore n = mdoc->last->child; 234095c635efSGarrett D'Amore if (n && NULL != (n = n->next)) 234195c635efSGarrett D'Amore *n->string = (char)toupper 234295c635efSGarrett D'Amore ((unsigned char)*n->string); 234395c635efSGarrett D'Amore 234495c635efSGarrett D'Amore return(1); 234595c635efSGarrett D'Amore } 234695c635efSGarrett D'Amore 234795c635efSGarrett D'Amore static int 234895c635efSGarrett D'Amore post_os(POST_ARGS) 234995c635efSGarrett D'Amore { 235095c635efSGarrett D'Amore struct mdoc_node *n; 235195c635efSGarrett D'Amore char buf[BUFSIZ]; 235295c635efSGarrett D'Amore int c; 235395c635efSGarrett D'Amore #ifndef OSNAME 235495c635efSGarrett D'Amore struct utsname utsname; 235595c635efSGarrett D'Amore #endif 235695c635efSGarrett D'Amore 235795c635efSGarrett D'Amore n = mdoc->last; 235895c635efSGarrett D'Amore 235995c635efSGarrett D'Amore /* 2360*698f87a4SGarrett D'Amore * Set the operating system by way of the `Os' macro. 2361*698f87a4SGarrett D'Amore * The order of precedence is: 2362*698f87a4SGarrett D'Amore * 1. the argument of the `Os' macro, unless empty 2363*698f87a4SGarrett D'Amore * 2. the -Ios=foo command line argument, if provided 2364*698f87a4SGarrett D'Amore * 3. -DOSNAME="\"foo\"", if provided during compilation 2365*698f87a4SGarrett D'Amore * 4. "sysname release" from uname(3) 236695c635efSGarrett D'Amore */ 236795c635efSGarrett D'Amore 2368*698f87a4SGarrett D'Amore free(mdoc->meta.os); 236995c635efSGarrett D'Amore 237095c635efSGarrett D'Amore buf[0] = '\0'; 237195c635efSGarrett D'Amore if (-1 == (c = concat(buf, n->child, BUFSIZ))) { 237295c635efSGarrett D'Amore mdoc_nmsg(mdoc, n->child, MANDOCERR_MEM); 237395c635efSGarrett D'Amore return(0); 237495c635efSGarrett D'Amore } 237595c635efSGarrett D'Amore 237695c635efSGarrett D'Amore assert(c); 237795c635efSGarrett D'Amore 237895c635efSGarrett D'Amore if ('\0' == buf[0]) { 2379*698f87a4SGarrett D'Amore if (mdoc->defos) { 2380*698f87a4SGarrett D'Amore mdoc->meta.os = mandoc_strdup(mdoc->defos); 2381*698f87a4SGarrett D'Amore return(1); 2382*698f87a4SGarrett D'Amore } 238395c635efSGarrett D'Amore #ifdef OSNAME 238495c635efSGarrett D'Amore if (strlcat(buf, OSNAME, BUFSIZ) >= BUFSIZ) { 238595c635efSGarrett D'Amore mdoc_nmsg(mdoc, n, MANDOCERR_MEM); 238695c635efSGarrett D'Amore return(0); 238795c635efSGarrett D'Amore } 238895c635efSGarrett D'Amore #else /*!OSNAME */ 238995c635efSGarrett D'Amore if (-1 == uname(&utsname)) { 239095c635efSGarrett D'Amore mdoc_nmsg(mdoc, n, MANDOCERR_UNAME); 239195c635efSGarrett D'Amore mdoc->meta.os = mandoc_strdup("UNKNOWN"); 239295c635efSGarrett D'Amore return(post_prol(mdoc)); 239395c635efSGarrett D'Amore } 239495c635efSGarrett D'Amore 239595c635efSGarrett D'Amore if (strlcat(buf, utsname.sysname, BUFSIZ) >= BUFSIZ) { 239695c635efSGarrett D'Amore mdoc_nmsg(mdoc, n, MANDOCERR_MEM); 239795c635efSGarrett D'Amore return(0); 239895c635efSGarrett D'Amore } 239995c635efSGarrett D'Amore if (strlcat(buf, " ", BUFSIZ) >= BUFSIZ) { 240095c635efSGarrett D'Amore mdoc_nmsg(mdoc, n, MANDOCERR_MEM); 240195c635efSGarrett D'Amore return(0); 240295c635efSGarrett D'Amore } 240395c635efSGarrett D'Amore if (strlcat(buf, utsname.release, BUFSIZ) >= BUFSIZ) { 240495c635efSGarrett D'Amore mdoc_nmsg(mdoc, n, MANDOCERR_MEM); 240595c635efSGarrett D'Amore return(0); 240695c635efSGarrett D'Amore } 240795c635efSGarrett D'Amore #endif /*!OSNAME*/ 240895c635efSGarrett D'Amore } 240995c635efSGarrett D'Amore 241095c635efSGarrett D'Amore mdoc->meta.os = mandoc_strdup(buf); 241195c635efSGarrett D'Amore return(1); 241295c635efSGarrett D'Amore } 241395c635efSGarrett D'Amore 241495c635efSGarrett D'Amore static int 241595c635efSGarrett D'Amore post_std(POST_ARGS) 241695c635efSGarrett D'Amore { 241795c635efSGarrett D'Amore struct mdoc_node *nn, *n; 241895c635efSGarrett D'Amore 241995c635efSGarrett D'Amore n = mdoc->last; 242095c635efSGarrett D'Amore 242195c635efSGarrett D'Amore /* 242295c635efSGarrett D'Amore * Macros accepting `-std' as an argument have the name of the 242395c635efSGarrett D'Amore * current document (`Nm') filled in as the argument if it's not 242495c635efSGarrett D'Amore * provided. 242595c635efSGarrett D'Amore */ 242695c635efSGarrett D'Amore 242795c635efSGarrett D'Amore if (n->child) 242895c635efSGarrett D'Amore return(1); 242995c635efSGarrett D'Amore 243095c635efSGarrett D'Amore if (NULL == mdoc->meta.name) 243195c635efSGarrett D'Amore return(1); 243295c635efSGarrett D'Amore 243395c635efSGarrett D'Amore nn = n; 243495c635efSGarrett D'Amore mdoc->next = MDOC_NEXT_CHILD; 243595c635efSGarrett D'Amore 243695c635efSGarrett D'Amore if ( ! mdoc_word_alloc(mdoc, n->line, n->pos, mdoc->meta.name)) 243795c635efSGarrett D'Amore return(0); 243895c635efSGarrett D'Amore 243995c635efSGarrett D'Amore mdoc->last = nn; 244095c635efSGarrett D'Amore return(1); 244195c635efSGarrett D'Amore } 244295c635efSGarrett D'Amore 244395c635efSGarrett D'Amore /* 244495c635efSGarrett D'Amore * Concatenate a node, stopping at the first non-text. 244595c635efSGarrett D'Amore * Concatenation is separated by a single whitespace. 244695c635efSGarrett D'Amore * Returns -1 on fatal (string overrun) error, 0 if child nodes were 244795c635efSGarrett D'Amore * encountered, 1 otherwise. 244895c635efSGarrett D'Amore */ 244995c635efSGarrett D'Amore static int 245095c635efSGarrett D'Amore concat(char *p, const struct mdoc_node *n, size_t sz) 245195c635efSGarrett D'Amore { 245295c635efSGarrett D'Amore 245395c635efSGarrett D'Amore for ( ; NULL != n; n = n->next) { 245495c635efSGarrett D'Amore if (MDOC_TEXT != n->type) 245595c635efSGarrett D'Amore return(0); 245695c635efSGarrett D'Amore if ('\0' != p[0] && strlcat(p, " ", sz) >= sz) 245795c635efSGarrett D'Amore return(-1); 245895c635efSGarrett D'Amore if (strlcat(p, n->string, sz) >= sz) 245995c635efSGarrett D'Amore return(-1); 246095c635efSGarrett D'Amore concat(p, n->child, sz); 246195c635efSGarrett D'Amore } 246295c635efSGarrett D'Amore 246395c635efSGarrett D'Amore return(1); 246495c635efSGarrett D'Amore } 246595c635efSGarrett D'Amore 246695c635efSGarrett D'Amore static enum mdoc_sec 246795c635efSGarrett D'Amore a2sec(const char *p) 246895c635efSGarrett D'Amore { 246995c635efSGarrett D'Amore int i; 247095c635efSGarrett D'Amore 247195c635efSGarrett D'Amore for (i = 0; i < (int)SEC__MAX; i++) 247295c635efSGarrett D'Amore if (secnames[i] && 0 == strcmp(p, secnames[i])) 247395c635efSGarrett D'Amore return((enum mdoc_sec)i); 247495c635efSGarrett D'Amore 247595c635efSGarrett D'Amore return(SEC_CUSTOM); 247695c635efSGarrett D'Amore } 247795c635efSGarrett D'Amore 247895c635efSGarrett D'Amore static size_t 247995c635efSGarrett D'Amore macro2len(enum mdoct macro) 248095c635efSGarrett D'Amore { 248195c635efSGarrett D'Amore 248295c635efSGarrett D'Amore switch (macro) { 248395c635efSGarrett D'Amore case(MDOC_Ad): 248495c635efSGarrett D'Amore return(12); 248595c635efSGarrett D'Amore case(MDOC_Ao): 248695c635efSGarrett D'Amore return(12); 248795c635efSGarrett D'Amore case(MDOC_An): 248895c635efSGarrett D'Amore return(12); 248995c635efSGarrett D'Amore case(MDOC_Aq): 249095c635efSGarrett D'Amore return(12); 249195c635efSGarrett D'Amore case(MDOC_Ar): 249295c635efSGarrett D'Amore return(12); 249395c635efSGarrett D'Amore case(MDOC_Bo): 249495c635efSGarrett D'Amore return(12); 249595c635efSGarrett D'Amore case(MDOC_Bq): 249695c635efSGarrett D'Amore return(12); 249795c635efSGarrett D'Amore case(MDOC_Cd): 249895c635efSGarrett D'Amore return(12); 249995c635efSGarrett D'Amore case(MDOC_Cm): 250095c635efSGarrett D'Amore return(10); 250195c635efSGarrett D'Amore case(MDOC_Do): 250295c635efSGarrett D'Amore return(10); 250395c635efSGarrett D'Amore case(MDOC_Dq): 250495c635efSGarrett D'Amore return(12); 250595c635efSGarrett D'Amore case(MDOC_Dv): 250695c635efSGarrett D'Amore return(12); 250795c635efSGarrett D'Amore case(MDOC_Eo): 250895c635efSGarrett D'Amore return(12); 250995c635efSGarrett D'Amore case(MDOC_Em): 251095c635efSGarrett D'Amore return(10); 251195c635efSGarrett D'Amore case(MDOC_Er): 251295c635efSGarrett D'Amore return(17); 251395c635efSGarrett D'Amore case(MDOC_Ev): 251495c635efSGarrett D'Amore return(15); 251595c635efSGarrett D'Amore case(MDOC_Fa): 251695c635efSGarrett D'Amore return(12); 251795c635efSGarrett D'Amore case(MDOC_Fl): 251895c635efSGarrett D'Amore return(10); 251995c635efSGarrett D'Amore case(MDOC_Fo): 252095c635efSGarrett D'Amore return(16); 252195c635efSGarrett D'Amore case(MDOC_Fn): 252295c635efSGarrett D'Amore return(16); 252395c635efSGarrett D'Amore case(MDOC_Ic): 252495c635efSGarrett D'Amore return(10); 252595c635efSGarrett D'Amore case(MDOC_Li): 252695c635efSGarrett D'Amore return(16); 252795c635efSGarrett D'Amore case(MDOC_Ms): 252895c635efSGarrett D'Amore return(6); 252995c635efSGarrett D'Amore case(MDOC_Nm): 253095c635efSGarrett D'Amore return(10); 253195c635efSGarrett D'Amore case(MDOC_No): 253295c635efSGarrett D'Amore return(12); 253395c635efSGarrett D'Amore case(MDOC_Oo): 253495c635efSGarrett D'Amore return(10); 253595c635efSGarrett D'Amore case(MDOC_Op): 253695c635efSGarrett D'Amore return(14); 253795c635efSGarrett D'Amore case(MDOC_Pa): 253895c635efSGarrett D'Amore return(32); 253995c635efSGarrett D'Amore case(MDOC_Pf): 254095c635efSGarrett D'Amore return(12); 254195c635efSGarrett D'Amore case(MDOC_Po): 254295c635efSGarrett D'Amore return(12); 254395c635efSGarrett D'Amore case(MDOC_Pq): 254495c635efSGarrett D'Amore return(12); 254595c635efSGarrett D'Amore case(MDOC_Ql): 254695c635efSGarrett D'Amore return(16); 254795c635efSGarrett D'Amore case(MDOC_Qo): 254895c635efSGarrett D'Amore return(12); 254995c635efSGarrett D'Amore case(MDOC_So): 255095c635efSGarrett D'Amore return(12); 255195c635efSGarrett D'Amore case(MDOC_Sq): 255295c635efSGarrett D'Amore return(12); 255395c635efSGarrett D'Amore case(MDOC_Sy): 255495c635efSGarrett D'Amore return(6); 255595c635efSGarrett D'Amore case(MDOC_Sx): 255695c635efSGarrett D'Amore return(16); 255795c635efSGarrett D'Amore case(MDOC_Tn): 255895c635efSGarrett D'Amore return(10); 255995c635efSGarrett D'Amore case(MDOC_Va): 256095c635efSGarrett D'Amore return(12); 256195c635efSGarrett D'Amore case(MDOC_Vt): 256295c635efSGarrett D'Amore return(12); 256395c635efSGarrett D'Amore case(MDOC_Xr): 256495c635efSGarrett D'Amore return(10); 256595c635efSGarrett D'Amore default: 256695c635efSGarrett D'Amore break; 256795c635efSGarrett D'Amore }; 256895c635efSGarrett D'Amore return(0); 256995c635efSGarrett D'Amore } 2570