1*95c635efSGarrett D'Amore /* $Id: man_validate.c,v 1.80 2012/01/03 15:16:24 kristaps Exp $ */ 2*95c635efSGarrett D'Amore /* 3*95c635efSGarrett D'Amore * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> 4*95c635efSGarrett D'Amore * Copyright (c) 2010 Ingo Schwarze <schwarze@openbsd.org> 5*95c635efSGarrett D'Amore * 6*95c635efSGarrett D'Amore * Permission to use, copy, modify, and distribute this software for any 7*95c635efSGarrett D'Amore * purpose with or without fee is hereby granted, provided that the above 8*95c635efSGarrett D'Amore * copyright notice and this permission notice appear in all copies. 9*95c635efSGarrett D'Amore * 10*95c635efSGarrett D'Amore * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11*95c635efSGarrett D'Amore * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12*95c635efSGarrett D'Amore * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13*95c635efSGarrett D'Amore * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14*95c635efSGarrett D'Amore * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15*95c635efSGarrett D'Amore * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16*95c635efSGarrett D'Amore * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17*95c635efSGarrett D'Amore */ 18*95c635efSGarrett D'Amore #ifdef HAVE_CONFIG_H 19*95c635efSGarrett D'Amore #include "config.h" 20*95c635efSGarrett D'Amore #endif 21*95c635efSGarrett D'Amore 22*95c635efSGarrett D'Amore #include <sys/types.h> 23*95c635efSGarrett D'Amore 24*95c635efSGarrett D'Amore #include <assert.h> 25*95c635efSGarrett D'Amore #include <ctype.h> 26*95c635efSGarrett D'Amore #include <errno.h> 27*95c635efSGarrett D'Amore #include <limits.h> 28*95c635efSGarrett D'Amore #include <stdarg.h> 29*95c635efSGarrett D'Amore #include <stdlib.h> 30*95c635efSGarrett D'Amore #include <string.h> 31*95c635efSGarrett D'Amore #include <time.h> 32*95c635efSGarrett D'Amore 33*95c635efSGarrett D'Amore #include "man.h" 34*95c635efSGarrett D'Amore #include "mandoc.h" 35*95c635efSGarrett D'Amore #include "libman.h" 36*95c635efSGarrett D'Amore #include "libmandoc.h" 37*95c635efSGarrett D'Amore 38*95c635efSGarrett D'Amore #define CHKARGS struct man *m, struct man_node *n 39*95c635efSGarrett D'Amore 40*95c635efSGarrett D'Amore typedef int (*v_check)(CHKARGS); 41*95c635efSGarrett D'Amore 42*95c635efSGarrett D'Amore struct man_valid { 43*95c635efSGarrett D'Amore v_check *pres; 44*95c635efSGarrett D'Amore v_check *posts; 45*95c635efSGarrett D'Amore }; 46*95c635efSGarrett D'Amore 47*95c635efSGarrett D'Amore static int check_eq0(CHKARGS); 48*95c635efSGarrett D'Amore static int check_eq2(CHKARGS); 49*95c635efSGarrett D'Amore static int check_le1(CHKARGS); 50*95c635efSGarrett D'Amore static int check_ge2(CHKARGS); 51*95c635efSGarrett D'Amore static int check_le5(CHKARGS); 52*95c635efSGarrett D'Amore static int check_par(CHKARGS); 53*95c635efSGarrett D'Amore static int check_part(CHKARGS); 54*95c635efSGarrett D'Amore static int check_root(CHKARGS); 55*95c635efSGarrett D'Amore static void check_text(CHKARGS); 56*95c635efSGarrett D'Amore 57*95c635efSGarrett D'Amore static int post_AT(CHKARGS); 58*95c635efSGarrett D'Amore static int post_vs(CHKARGS); 59*95c635efSGarrett D'Amore static int post_fi(CHKARGS); 60*95c635efSGarrett D'Amore static int post_ft(CHKARGS); 61*95c635efSGarrett D'Amore static int post_nf(CHKARGS); 62*95c635efSGarrett D'Amore static int post_sec(CHKARGS); 63*95c635efSGarrett D'Amore static int post_TH(CHKARGS); 64*95c635efSGarrett D'Amore static int post_UC(CHKARGS); 65*95c635efSGarrett D'Amore static int pre_sec(CHKARGS); 66*95c635efSGarrett D'Amore 67*95c635efSGarrett D'Amore static v_check posts_at[] = { post_AT, NULL }; 68*95c635efSGarrett D'Amore static v_check posts_br[] = { post_vs, check_eq0, NULL }; 69*95c635efSGarrett D'Amore static v_check posts_eq0[] = { check_eq0, NULL }; 70*95c635efSGarrett D'Amore static v_check posts_eq2[] = { check_eq2, NULL }; 71*95c635efSGarrett D'Amore static v_check posts_fi[] = { check_eq0, post_fi, NULL }; 72*95c635efSGarrett D'Amore static v_check posts_ft[] = { post_ft, NULL }; 73*95c635efSGarrett D'Amore static v_check posts_nf[] = { check_eq0, post_nf, NULL }; 74*95c635efSGarrett D'Amore static v_check posts_par[] = { check_par, NULL }; 75*95c635efSGarrett D'Amore static v_check posts_part[] = { check_part, NULL }; 76*95c635efSGarrett D'Amore static v_check posts_sec[] = { post_sec, NULL }; 77*95c635efSGarrett D'Amore static v_check posts_sp[] = { post_vs, check_le1, NULL }; 78*95c635efSGarrett D'Amore static v_check posts_th[] = { check_ge2, check_le5, post_TH, NULL }; 79*95c635efSGarrett D'Amore static v_check posts_uc[] = { post_UC, NULL }; 80*95c635efSGarrett D'Amore static v_check pres_sec[] = { pre_sec, NULL }; 81*95c635efSGarrett D'Amore 82*95c635efSGarrett D'Amore static const struct man_valid man_valids[MAN_MAX] = { 83*95c635efSGarrett D'Amore { NULL, posts_br }, /* br */ 84*95c635efSGarrett D'Amore { NULL, posts_th }, /* TH */ 85*95c635efSGarrett D'Amore { pres_sec, posts_sec }, /* SH */ 86*95c635efSGarrett D'Amore { pres_sec, posts_sec }, /* SS */ 87*95c635efSGarrett D'Amore { NULL, NULL }, /* TP */ 88*95c635efSGarrett D'Amore { NULL, posts_par }, /* LP */ 89*95c635efSGarrett D'Amore { NULL, posts_par }, /* PP */ 90*95c635efSGarrett D'Amore { NULL, posts_par }, /* P */ 91*95c635efSGarrett D'Amore { NULL, NULL }, /* IP */ 92*95c635efSGarrett D'Amore { NULL, NULL }, /* HP */ 93*95c635efSGarrett D'Amore { NULL, NULL }, /* SM */ 94*95c635efSGarrett D'Amore { NULL, NULL }, /* SB */ 95*95c635efSGarrett D'Amore { NULL, NULL }, /* BI */ 96*95c635efSGarrett D'Amore { NULL, NULL }, /* IB */ 97*95c635efSGarrett D'Amore { NULL, NULL }, /* BR */ 98*95c635efSGarrett D'Amore { NULL, NULL }, /* RB */ 99*95c635efSGarrett D'Amore { NULL, NULL }, /* R */ 100*95c635efSGarrett D'Amore { NULL, NULL }, /* B */ 101*95c635efSGarrett D'Amore { NULL, NULL }, /* I */ 102*95c635efSGarrett D'Amore { NULL, NULL }, /* IR */ 103*95c635efSGarrett D'Amore { NULL, NULL }, /* RI */ 104*95c635efSGarrett D'Amore { NULL, posts_eq0 }, /* na */ 105*95c635efSGarrett D'Amore { NULL, posts_sp }, /* sp */ 106*95c635efSGarrett D'Amore { NULL, posts_nf }, /* nf */ 107*95c635efSGarrett D'Amore { NULL, posts_fi }, /* fi */ 108*95c635efSGarrett D'Amore { NULL, NULL }, /* RE */ 109*95c635efSGarrett D'Amore { NULL, posts_part }, /* RS */ 110*95c635efSGarrett D'Amore { NULL, NULL }, /* DT */ 111*95c635efSGarrett D'Amore { NULL, posts_uc }, /* UC */ 112*95c635efSGarrett D'Amore { NULL, NULL }, /* PD */ 113*95c635efSGarrett D'Amore { NULL, posts_at }, /* AT */ 114*95c635efSGarrett D'Amore { NULL, NULL }, /* in */ 115*95c635efSGarrett D'Amore { NULL, posts_ft }, /* ft */ 116*95c635efSGarrett D'Amore { NULL, posts_eq2 }, /* OP */ 117*95c635efSGarrett D'Amore }; 118*95c635efSGarrett D'Amore 119*95c635efSGarrett D'Amore 120*95c635efSGarrett D'Amore int 121*95c635efSGarrett D'Amore man_valid_pre(struct man *m, struct man_node *n) 122*95c635efSGarrett D'Amore { 123*95c635efSGarrett D'Amore v_check *cp; 124*95c635efSGarrett D'Amore 125*95c635efSGarrett D'Amore switch (n->type) { 126*95c635efSGarrett D'Amore case (MAN_TEXT): 127*95c635efSGarrett D'Amore /* FALLTHROUGH */ 128*95c635efSGarrett D'Amore case (MAN_ROOT): 129*95c635efSGarrett D'Amore /* FALLTHROUGH */ 130*95c635efSGarrett D'Amore case (MAN_EQN): 131*95c635efSGarrett D'Amore /* FALLTHROUGH */ 132*95c635efSGarrett D'Amore case (MAN_TBL): 133*95c635efSGarrett D'Amore return(1); 134*95c635efSGarrett D'Amore default: 135*95c635efSGarrett D'Amore break; 136*95c635efSGarrett D'Amore } 137*95c635efSGarrett D'Amore 138*95c635efSGarrett D'Amore if (NULL == (cp = man_valids[n->tok].pres)) 139*95c635efSGarrett D'Amore return(1); 140*95c635efSGarrett D'Amore for ( ; *cp; cp++) 141*95c635efSGarrett D'Amore if ( ! (*cp)(m, n)) 142*95c635efSGarrett D'Amore return(0); 143*95c635efSGarrett D'Amore return(1); 144*95c635efSGarrett D'Amore } 145*95c635efSGarrett D'Amore 146*95c635efSGarrett D'Amore 147*95c635efSGarrett D'Amore int 148*95c635efSGarrett D'Amore man_valid_post(struct man *m) 149*95c635efSGarrett D'Amore { 150*95c635efSGarrett D'Amore v_check *cp; 151*95c635efSGarrett D'Amore 152*95c635efSGarrett D'Amore if (MAN_VALID & m->last->flags) 153*95c635efSGarrett D'Amore return(1); 154*95c635efSGarrett D'Amore m->last->flags |= MAN_VALID; 155*95c635efSGarrett D'Amore 156*95c635efSGarrett D'Amore switch (m->last->type) { 157*95c635efSGarrett D'Amore case (MAN_TEXT): 158*95c635efSGarrett D'Amore check_text(m, m->last); 159*95c635efSGarrett D'Amore return(1); 160*95c635efSGarrett D'Amore case (MAN_ROOT): 161*95c635efSGarrett D'Amore return(check_root(m, m->last)); 162*95c635efSGarrett D'Amore case (MAN_EQN): 163*95c635efSGarrett D'Amore /* FALLTHROUGH */ 164*95c635efSGarrett D'Amore case (MAN_TBL): 165*95c635efSGarrett D'Amore return(1); 166*95c635efSGarrett D'Amore default: 167*95c635efSGarrett D'Amore break; 168*95c635efSGarrett D'Amore } 169*95c635efSGarrett D'Amore 170*95c635efSGarrett D'Amore if (NULL == (cp = man_valids[m->last->tok].posts)) 171*95c635efSGarrett D'Amore return(1); 172*95c635efSGarrett D'Amore for ( ; *cp; cp++) 173*95c635efSGarrett D'Amore if ( ! (*cp)(m, m->last)) 174*95c635efSGarrett D'Amore return(0); 175*95c635efSGarrett D'Amore 176*95c635efSGarrett D'Amore return(1); 177*95c635efSGarrett D'Amore } 178*95c635efSGarrett D'Amore 179*95c635efSGarrett D'Amore 180*95c635efSGarrett D'Amore static int 181*95c635efSGarrett D'Amore check_root(CHKARGS) 182*95c635efSGarrett D'Amore { 183*95c635efSGarrett D'Amore 184*95c635efSGarrett D'Amore if (MAN_BLINE & m->flags) 185*95c635efSGarrett D'Amore man_nmsg(m, n, MANDOCERR_SCOPEEXIT); 186*95c635efSGarrett D'Amore else if (MAN_ELINE & m->flags) 187*95c635efSGarrett D'Amore man_nmsg(m, n, MANDOCERR_SCOPEEXIT); 188*95c635efSGarrett D'Amore 189*95c635efSGarrett D'Amore m->flags &= ~MAN_BLINE; 190*95c635efSGarrett D'Amore m->flags &= ~MAN_ELINE; 191*95c635efSGarrett D'Amore 192*95c635efSGarrett D'Amore if (NULL == m->first->child) { 193*95c635efSGarrett D'Amore man_nmsg(m, n, MANDOCERR_NODOCBODY); 194*95c635efSGarrett D'Amore return(0); 195*95c635efSGarrett D'Amore } else if (NULL == m->meta.title) { 196*95c635efSGarrett D'Amore man_nmsg(m, n, MANDOCERR_NOTITLE); 197*95c635efSGarrett D'Amore 198*95c635efSGarrett D'Amore /* 199*95c635efSGarrett D'Amore * If a title hasn't been set, do so now (by 200*95c635efSGarrett D'Amore * implication, date and section also aren't set). 201*95c635efSGarrett D'Amore */ 202*95c635efSGarrett D'Amore 203*95c635efSGarrett D'Amore m->meta.title = mandoc_strdup("unknown"); 204*95c635efSGarrett D'Amore m->meta.msec = mandoc_strdup("1"); 205*95c635efSGarrett D'Amore m->meta.date = mandoc_normdate 206*95c635efSGarrett D'Amore (m->parse, NULL, n->line, n->pos); 207*95c635efSGarrett D'Amore } 208*95c635efSGarrett D'Amore 209*95c635efSGarrett D'Amore return(1); 210*95c635efSGarrett D'Amore } 211*95c635efSGarrett D'Amore 212*95c635efSGarrett D'Amore static void 213*95c635efSGarrett D'Amore check_text(CHKARGS) 214*95c635efSGarrett D'Amore { 215*95c635efSGarrett D'Amore char *cp, *p; 216*95c635efSGarrett D'Amore 217*95c635efSGarrett D'Amore if (MAN_LITERAL & m->flags) 218*95c635efSGarrett D'Amore return; 219*95c635efSGarrett D'Amore 220*95c635efSGarrett D'Amore cp = n->string; 221*95c635efSGarrett D'Amore for (p = cp; NULL != (p = strchr(p, '\t')); p++) 222*95c635efSGarrett D'Amore man_pmsg(m, n->line, (int)(p - cp), MANDOCERR_BADTAB); 223*95c635efSGarrett D'Amore } 224*95c635efSGarrett D'Amore 225*95c635efSGarrett D'Amore #define INEQ_DEFINE(x, ineq, name) \ 226*95c635efSGarrett D'Amore static int \ 227*95c635efSGarrett D'Amore check_##name(CHKARGS) \ 228*95c635efSGarrett D'Amore { \ 229*95c635efSGarrett D'Amore if (n->nchild ineq (x)) \ 230*95c635efSGarrett D'Amore return(1); \ 231*95c635efSGarrett D'Amore mandoc_vmsg(MANDOCERR_ARGCOUNT, m->parse, n->line, n->pos, \ 232*95c635efSGarrett D'Amore "line arguments %s %d (have %d)", \ 233*95c635efSGarrett D'Amore #ineq, (x), n->nchild); \ 234*95c635efSGarrett D'Amore return(1); \ 235*95c635efSGarrett D'Amore } 236*95c635efSGarrett D'Amore 237*95c635efSGarrett D'Amore INEQ_DEFINE(0, ==, eq0) 238*95c635efSGarrett D'Amore INEQ_DEFINE(2, ==, eq2) 239*95c635efSGarrett D'Amore INEQ_DEFINE(1, <=, le1) 240*95c635efSGarrett D'Amore INEQ_DEFINE(2, >=, ge2) 241*95c635efSGarrett D'Amore INEQ_DEFINE(5, <=, le5) 242*95c635efSGarrett D'Amore 243*95c635efSGarrett D'Amore static int 244*95c635efSGarrett D'Amore post_ft(CHKARGS) 245*95c635efSGarrett D'Amore { 246*95c635efSGarrett D'Amore char *cp; 247*95c635efSGarrett D'Amore int ok; 248*95c635efSGarrett D'Amore 249*95c635efSGarrett D'Amore if (0 == n->nchild) 250*95c635efSGarrett D'Amore return(1); 251*95c635efSGarrett D'Amore 252*95c635efSGarrett D'Amore ok = 0; 253*95c635efSGarrett D'Amore cp = n->child->string; 254*95c635efSGarrett D'Amore switch (*cp) { 255*95c635efSGarrett D'Amore case ('1'): 256*95c635efSGarrett D'Amore /* FALLTHROUGH */ 257*95c635efSGarrett D'Amore case ('2'): 258*95c635efSGarrett D'Amore /* FALLTHROUGH */ 259*95c635efSGarrett D'Amore case ('3'): 260*95c635efSGarrett D'Amore /* FALLTHROUGH */ 261*95c635efSGarrett D'Amore case ('4'): 262*95c635efSGarrett D'Amore /* FALLTHROUGH */ 263*95c635efSGarrett D'Amore case ('I'): 264*95c635efSGarrett D'Amore /* FALLTHROUGH */ 265*95c635efSGarrett D'Amore case ('P'): 266*95c635efSGarrett D'Amore /* FALLTHROUGH */ 267*95c635efSGarrett D'Amore case ('R'): 268*95c635efSGarrett D'Amore if ('\0' == cp[1]) 269*95c635efSGarrett D'Amore ok = 1; 270*95c635efSGarrett D'Amore break; 271*95c635efSGarrett D'Amore case ('B'): 272*95c635efSGarrett D'Amore if ('\0' == cp[1] || ('I' == cp[1] && '\0' == cp[2])) 273*95c635efSGarrett D'Amore ok = 1; 274*95c635efSGarrett D'Amore break; 275*95c635efSGarrett D'Amore case ('C'): 276*95c635efSGarrett D'Amore if ('W' == cp[1] && '\0' == cp[2]) 277*95c635efSGarrett D'Amore ok = 1; 278*95c635efSGarrett D'Amore break; 279*95c635efSGarrett D'Amore default: 280*95c635efSGarrett D'Amore break; 281*95c635efSGarrett D'Amore } 282*95c635efSGarrett D'Amore 283*95c635efSGarrett D'Amore if (0 == ok) { 284*95c635efSGarrett D'Amore mandoc_vmsg 285*95c635efSGarrett D'Amore (MANDOCERR_BADFONT, m->parse, 286*95c635efSGarrett D'Amore n->line, n->pos, "%s", cp); 287*95c635efSGarrett D'Amore *cp = '\0'; 288*95c635efSGarrett D'Amore } 289*95c635efSGarrett D'Amore 290*95c635efSGarrett D'Amore if (1 < n->nchild) 291*95c635efSGarrett D'Amore mandoc_vmsg 292*95c635efSGarrett D'Amore (MANDOCERR_ARGCOUNT, m->parse, n->line, 293*95c635efSGarrett D'Amore n->pos, "want one child (have %d)", 294*95c635efSGarrett D'Amore n->nchild); 295*95c635efSGarrett D'Amore 296*95c635efSGarrett D'Amore return(1); 297*95c635efSGarrett D'Amore } 298*95c635efSGarrett D'Amore 299*95c635efSGarrett D'Amore static int 300*95c635efSGarrett D'Amore pre_sec(CHKARGS) 301*95c635efSGarrett D'Amore { 302*95c635efSGarrett D'Amore 303*95c635efSGarrett D'Amore if (MAN_BLOCK == n->type) 304*95c635efSGarrett D'Amore m->flags &= ~MAN_LITERAL; 305*95c635efSGarrett D'Amore return(1); 306*95c635efSGarrett D'Amore } 307*95c635efSGarrett D'Amore 308*95c635efSGarrett D'Amore static int 309*95c635efSGarrett D'Amore post_sec(CHKARGS) 310*95c635efSGarrett D'Amore { 311*95c635efSGarrett D'Amore 312*95c635efSGarrett D'Amore if ( ! (MAN_HEAD == n->type && 0 == n->nchild)) 313*95c635efSGarrett D'Amore return(1); 314*95c635efSGarrett D'Amore 315*95c635efSGarrett D'Amore man_nmsg(m, n, MANDOCERR_SYNTARGCOUNT); 316*95c635efSGarrett D'Amore return(0); 317*95c635efSGarrett D'Amore } 318*95c635efSGarrett D'Amore 319*95c635efSGarrett D'Amore static int 320*95c635efSGarrett D'Amore check_part(CHKARGS) 321*95c635efSGarrett D'Amore { 322*95c635efSGarrett D'Amore 323*95c635efSGarrett D'Amore if (MAN_BODY == n->type && 0 == n->nchild) 324*95c635efSGarrett D'Amore mandoc_msg(MANDOCERR_ARGCWARN, m->parse, n->line, 325*95c635efSGarrett D'Amore n->pos, "want children (have none)"); 326*95c635efSGarrett D'Amore 327*95c635efSGarrett D'Amore return(1); 328*95c635efSGarrett D'Amore } 329*95c635efSGarrett D'Amore 330*95c635efSGarrett D'Amore 331*95c635efSGarrett D'Amore static int 332*95c635efSGarrett D'Amore check_par(CHKARGS) 333*95c635efSGarrett D'Amore { 334*95c635efSGarrett D'Amore 335*95c635efSGarrett D'Amore switch (n->type) { 336*95c635efSGarrett D'Amore case (MAN_BLOCK): 337*95c635efSGarrett D'Amore if (0 == n->body->nchild) 338*95c635efSGarrett D'Amore man_node_delete(m, n); 339*95c635efSGarrett D'Amore break; 340*95c635efSGarrett D'Amore case (MAN_BODY): 341*95c635efSGarrett D'Amore if (0 == n->nchild) 342*95c635efSGarrett D'Amore man_nmsg(m, n, MANDOCERR_IGNPAR); 343*95c635efSGarrett D'Amore break; 344*95c635efSGarrett D'Amore case (MAN_HEAD): 345*95c635efSGarrett D'Amore if (n->nchild) 346*95c635efSGarrett D'Amore man_nmsg(m, n, MANDOCERR_ARGSLOST); 347*95c635efSGarrett D'Amore break; 348*95c635efSGarrett D'Amore default: 349*95c635efSGarrett D'Amore break; 350*95c635efSGarrett D'Amore } 351*95c635efSGarrett D'Amore 352*95c635efSGarrett D'Amore return(1); 353*95c635efSGarrett D'Amore } 354*95c635efSGarrett D'Amore 355*95c635efSGarrett D'Amore 356*95c635efSGarrett D'Amore static int 357*95c635efSGarrett D'Amore post_TH(CHKARGS) 358*95c635efSGarrett D'Amore { 359*95c635efSGarrett D'Amore const char *p; 360*95c635efSGarrett D'Amore int line, pos; 361*95c635efSGarrett D'Amore 362*95c635efSGarrett D'Amore if (m->meta.title) 363*95c635efSGarrett D'Amore free(m->meta.title); 364*95c635efSGarrett D'Amore if (m->meta.vol) 365*95c635efSGarrett D'Amore free(m->meta.vol); 366*95c635efSGarrett D'Amore if (m->meta.source) 367*95c635efSGarrett D'Amore free(m->meta.source); 368*95c635efSGarrett D'Amore if (m->meta.msec) 369*95c635efSGarrett D'Amore free(m->meta.msec); 370*95c635efSGarrett D'Amore if (m->meta.date) 371*95c635efSGarrett D'Amore free(m->meta.date); 372*95c635efSGarrett D'Amore 373*95c635efSGarrett D'Amore line = n->line; 374*95c635efSGarrett D'Amore pos = n->pos; 375*95c635efSGarrett D'Amore m->meta.title = m->meta.vol = m->meta.date = 376*95c635efSGarrett D'Amore m->meta.msec = m->meta.source = NULL; 377*95c635efSGarrett D'Amore 378*95c635efSGarrett D'Amore /* ->TITLE<- MSEC DATE SOURCE VOL */ 379*95c635efSGarrett D'Amore 380*95c635efSGarrett D'Amore n = n->child; 381*95c635efSGarrett D'Amore if (n && n->string) { 382*95c635efSGarrett D'Amore for (p = n->string; '\0' != *p; p++) { 383*95c635efSGarrett D'Amore /* Only warn about this once... */ 384*95c635efSGarrett D'Amore if (isalpha((unsigned char)*p) && 385*95c635efSGarrett D'Amore ! isupper((unsigned char)*p)) { 386*95c635efSGarrett D'Amore man_nmsg(m, n, MANDOCERR_UPPERCASE); 387*95c635efSGarrett D'Amore break; 388*95c635efSGarrett D'Amore } 389*95c635efSGarrett D'Amore } 390*95c635efSGarrett D'Amore m->meta.title = mandoc_strdup(n->string); 391*95c635efSGarrett D'Amore } else 392*95c635efSGarrett D'Amore m->meta.title = mandoc_strdup(""); 393*95c635efSGarrett D'Amore 394*95c635efSGarrett D'Amore /* TITLE ->MSEC<- DATE SOURCE VOL */ 395*95c635efSGarrett D'Amore 396*95c635efSGarrett D'Amore if (n) 397*95c635efSGarrett D'Amore n = n->next; 398*95c635efSGarrett D'Amore if (n && n->string) 399*95c635efSGarrett D'Amore m->meta.msec = mandoc_strdup(n->string); 400*95c635efSGarrett D'Amore else 401*95c635efSGarrett D'Amore m->meta.msec = mandoc_strdup(""); 402*95c635efSGarrett D'Amore 403*95c635efSGarrett D'Amore /* TITLE MSEC ->DATE<- SOURCE VOL */ 404*95c635efSGarrett D'Amore 405*95c635efSGarrett D'Amore if (n) 406*95c635efSGarrett D'Amore n = n->next; 407*95c635efSGarrett D'Amore if (n && n->string && '\0' != n->string[0]) { 408*95c635efSGarrett D'Amore pos = n->pos; 409*95c635efSGarrett D'Amore m->meta.date = mandoc_normdate 410*95c635efSGarrett D'Amore (m->parse, n->string, line, pos); 411*95c635efSGarrett D'Amore } else 412*95c635efSGarrett D'Amore m->meta.date = mandoc_strdup(""); 413*95c635efSGarrett D'Amore 414*95c635efSGarrett D'Amore /* TITLE MSEC DATE ->SOURCE<- VOL */ 415*95c635efSGarrett D'Amore 416*95c635efSGarrett D'Amore if (n && (n = n->next)) 417*95c635efSGarrett D'Amore m->meta.source = mandoc_strdup(n->string); 418*95c635efSGarrett D'Amore 419*95c635efSGarrett D'Amore /* TITLE MSEC DATE SOURCE ->VOL<- */ 420*95c635efSGarrett D'Amore /* If missing, use the default VOL name for MSEC. */ 421*95c635efSGarrett D'Amore 422*95c635efSGarrett D'Amore if (n && (n = n->next)) 423*95c635efSGarrett D'Amore m->meta.vol = mandoc_strdup(n->string); 424*95c635efSGarrett D'Amore else if ('\0' != m->meta.msec[0] && 425*95c635efSGarrett D'Amore (NULL != (p = mandoc_a2msec(m->meta.msec)))) 426*95c635efSGarrett D'Amore m->meta.vol = mandoc_strdup(p); 427*95c635efSGarrett D'Amore 428*95c635efSGarrett D'Amore /* 429*95c635efSGarrett D'Amore * Remove the `TH' node after we've processed it for our 430*95c635efSGarrett D'Amore * meta-data. 431*95c635efSGarrett D'Amore */ 432*95c635efSGarrett D'Amore man_node_delete(m, m->last); 433*95c635efSGarrett D'Amore return(1); 434*95c635efSGarrett D'Amore } 435*95c635efSGarrett D'Amore 436*95c635efSGarrett D'Amore static int 437*95c635efSGarrett D'Amore post_nf(CHKARGS) 438*95c635efSGarrett D'Amore { 439*95c635efSGarrett D'Amore 440*95c635efSGarrett D'Amore if (MAN_LITERAL & m->flags) 441*95c635efSGarrett D'Amore man_nmsg(m, n, MANDOCERR_SCOPEREP); 442*95c635efSGarrett D'Amore 443*95c635efSGarrett D'Amore m->flags |= MAN_LITERAL; 444*95c635efSGarrett D'Amore return(1); 445*95c635efSGarrett D'Amore } 446*95c635efSGarrett D'Amore 447*95c635efSGarrett D'Amore static int 448*95c635efSGarrett D'Amore post_fi(CHKARGS) 449*95c635efSGarrett D'Amore { 450*95c635efSGarrett D'Amore 451*95c635efSGarrett D'Amore if ( ! (MAN_LITERAL & m->flags)) 452*95c635efSGarrett D'Amore man_nmsg(m, n, MANDOCERR_WNOSCOPE); 453*95c635efSGarrett D'Amore 454*95c635efSGarrett D'Amore m->flags &= ~MAN_LITERAL; 455*95c635efSGarrett D'Amore return(1); 456*95c635efSGarrett D'Amore } 457*95c635efSGarrett D'Amore 458*95c635efSGarrett D'Amore static int 459*95c635efSGarrett D'Amore post_UC(CHKARGS) 460*95c635efSGarrett D'Amore { 461*95c635efSGarrett D'Amore static const char * const bsd_versions[] = { 462*95c635efSGarrett D'Amore "3rd Berkeley Distribution", 463*95c635efSGarrett D'Amore "4th Berkeley Distribution", 464*95c635efSGarrett D'Amore "4.2 Berkeley Distribution", 465*95c635efSGarrett D'Amore "4.3 Berkeley Distribution", 466*95c635efSGarrett D'Amore "4.4 Berkeley Distribution", 467*95c635efSGarrett D'Amore }; 468*95c635efSGarrett D'Amore 469*95c635efSGarrett D'Amore const char *p, *s; 470*95c635efSGarrett D'Amore 471*95c635efSGarrett D'Amore n = n->child; 472*95c635efSGarrett D'Amore 473*95c635efSGarrett D'Amore if (NULL == n || MAN_TEXT != n->type) 474*95c635efSGarrett D'Amore p = bsd_versions[0]; 475*95c635efSGarrett D'Amore else { 476*95c635efSGarrett D'Amore s = n->string; 477*95c635efSGarrett D'Amore if (0 == strcmp(s, "3")) 478*95c635efSGarrett D'Amore p = bsd_versions[0]; 479*95c635efSGarrett D'Amore else if (0 == strcmp(s, "4")) 480*95c635efSGarrett D'Amore p = bsd_versions[1]; 481*95c635efSGarrett D'Amore else if (0 == strcmp(s, "5")) 482*95c635efSGarrett D'Amore p = bsd_versions[2]; 483*95c635efSGarrett D'Amore else if (0 == strcmp(s, "6")) 484*95c635efSGarrett D'Amore p = bsd_versions[3]; 485*95c635efSGarrett D'Amore else if (0 == strcmp(s, "7")) 486*95c635efSGarrett D'Amore p = bsd_versions[4]; 487*95c635efSGarrett D'Amore else 488*95c635efSGarrett D'Amore p = bsd_versions[0]; 489*95c635efSGarrett D'Amore } 490*95c635efSGarrett D'Amore 491*95c635efSGarrett D'Amore if (m->meta.source) 492*95c635efSGarrett D'Amore free(m->meta.source); 493*95c635efSGarrett D'Amore 494*95c635efSGarrett D'Amore m->meta.source = mandoc_strdup(p); 495*95c635efSGarrett D'Amore return(1); 496*95c635efSGarrett D'Amore } 497*95c635efSGarrett D'Amore 498*95c635efSGarrett D'Amore static int 499*95c635efSGarrett D'Amore post_AT(CHKARGS) 500*95c635efSGarrett D'Amore { 501*95c635efSGarrett D'Amore static const char * const unix_versions[] = { 502*95c635efSGarrett D'Amore "7th Edition", 503*95c635efSGarrett D'Amore "System III", 504*95c635efSGarrett D'Amore "System V", 505*95c635efSGarrett D'Amore "System V Release 2", 506*95c635efSGarrett D'Amore }; 507*95c635efSGarrett D'Amore 508*95c635efSGarrett D'Amore const char *p, *s; 509*95c635efSGarrett D'Amore struct man_node *nn; 510*95c635efSGarrett D'Amore 511*95c635efSGarrett D'Amore n = n->child; 512*95c635efSGarrett D'Amore 513*95c635efSGarrett D'Amore if (NULL == n || MAN_TEXT != n->type) 514*95c635efSGarrett D'Amore p = unix_versions[0]; 515*95c635efSGarrett D'Amore else { 516*95c635efSGarrett D'Amore s = n->string; 517*95c635efSGarrett D'Amore if (0 == strcmp(s, "3")) 518*95c635efSGarrett D'Amore p = unix_versions[0]; 519*95c635efSGarrett D'Amore else if (0 == strcmp(s, "4")) 520*95c635efSGarrett D'Amore p = unix_versions[1]; 521*95c635efSGarrett D'Amore else if (0 == strcmp(s, "5")) { 522*95c635efSGarrett D'Amore nn = n->next; 523*95c635efSGarrett D'Amore if (nn && MAN_TEXT == nn->type && nn->string[0]) 524*95c635efSGarrett D'Amore p = unix_versions[3]; 525*95c635efSGarrett D'Amore else 526*95c635efSGarrett D'Amore p = unix_versions[2]; 527*95c635efSGarrett D'Amore } else 528*95c635efSGarrett D'Amore p = unix_versions[0]; 529*95c635efSGarrett D'Amore } 530*95c635efSGarrett D'Amore 531*95c635efSGarrett D'Amore if (m->meta.source) 532*95c635efSGarrett D'Amore free(m->meta.source); 533*95c635efSGarrett D'Amore 534*95c635efSGarrett D'Amore m->meta.source = mandoc_strdup(p); 535*95c635efSGarrett D'Amore return(1); 536*95c635efSGarrett D'Amore } 537*95c635efSGarrett D'Amore 538*95c635efSGarrett D'Amore static int 539*95c635efSGarrett D'Amore post_vs(CHKARGS) 540*95c635efSGarrett D'Amore { 541*95c635efSGarrett D'Amore 542*95c635efSGarrett D'Amore /* 543*95c635efSGarrett D'Amore * Don't warn about this because it occurs in pod2man and would 544*95c635efSGarrett D'Amore * cause considerable (unfixable) warnage. 545*95c635efSGarrett D'Amore */ 546*95c635efSGarrett D'Amore if (NULL == n->prev && MAN_ROOT == n->parent->type) 547*95c635efSGarrett D'Amore man_node_delete(m, n); 548*95c635efSGarrett D'Amore 549*95c635efSGarrett D'Amore return(1); 550*95c635efSGarrett D'Amore } 551