1*698f87a4SGarrett D'Amore /* $Id: man_validate.c,v 1.86 2013/10/17 20:54:58 schwarze Exp $ */ 295c635efSGarrett D'Amore /* 395c635efSGarrett D'Amore * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> 4*698f87a4SGarrett D'Amore * Copyright (c) 2010, 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 2295c635efSGarrett D'Amore #include <sys/types.h> 2395c635efSGarrett D'Amore 2495c635efSGarrett D'Amore #include <assert.h> 2595c635efSGarrett D'Amore #include <ctype.h> 2695c635efSGarrett D'Amore #include <errno.h> 2795c635efSGarrett D'Amore #include <limits.h> 2895c635efSGarrett D'Amore #include <stdarg.h> 2995c635efSGarrett D'Amore #include <stdlib.h> 3095c635efSGarrett D'Amore #include <string.h> 3195c635efSGarrett D'Amore #include <time.h> 3295c635efSGarrett D'Amore 3395c635efSGarrett D'Amore #include "man.h" 3495c635efSGarrett D'Amore #include "mandoc.h" 3595c635efSGarrett D'Amore #include "libman.h" 3695c635efSGarrett D'Amore #include "libmandoc.h" 3795c635efSGarrett D'Amore 38*698f87a4SGarrett D'Amore #define CHKARGS struct man *man, struct man_node *n 3995c635efSGarrett D'Amore 4095c635efSGarrett D'Amore typedef int (*v_check)(CHKARGS); 4195c635efSGarrett D'Amore 4295c635efSGarrett D'Amore struct man_valid { 4395c635efSGarrett D'Amore v_check *pres; 4495c635efSGarrett D'Amore v_check *posts; 4595c635efSGarrett D'Amore }; 4695c635efSGarrett D'Amore 4795c635efSGarrett D'Amore static int check_eq0(CHKARGS); 4895c635efSGarrett D'Amore static int check_eq2(CHKARGS); 4995c635efSGarrett D'Amore static int check_le1(CHKARGS); 5095c635efSGarrett D'Amore static int check_ge2(CHKARGS); 5195c635efSGarrett D'Amore static int check_le5(CHKARGS); 52*698f87a4SGarrett D'Amore static int check_head1(CHKARGS); 5395c635efSGarrett D'Amore static int check_par(CHKARGS); 5495c635efSGarrett D'Amore static int check_part(CHKARGS); 5595c635efSGarrett D'Amore static int check_root(CHKARGS); 5695c635efSGarrett D'Amore static void check_text(CHKARGS); 5795c635efSGarrett D'Amore 5895c635efSGarrett D'Amore static int post_AT(CHKARGS); 59*698f87a4SGarrett D'Amore static int post_IP(CHKARGS); 6095c635efSGarrett D'Amore static int post_vs(CHKARGS); 6195c635efSGarrett D'Amore static int post_fi(CHKARGS); 6295c635efSGarrett D'Amore static int post_ft(CHKARGS); 6395c635efSGarrett D'Amore static int post_nf(CHKARGS); 6495c635efSGarrett D'Amore static int post_sec(CHKARGS); 6595c635efSGarrett D'Amore static int post_TH(CHKARGS); 6695c635efSGarrett D'Amore static int post_UC(CHKARGS); 6795c635efSGarrett D'Amore static int pre_sec(CHKARGS); 6895c635efSGarrett D'Amore 6995c635efSGarrett D'Amore static v_check posts_at[] = { post_AT, NULL }; 7095c635efSGarrett D'Amore static v_check posts_br[] = { post_vs, check_eq0, NULL }; 7195c635efSGarrett D'Amore static v_check posts_eq0[] = { check_eq0, NULL }; 7295c635efSGarrett D'Amore static v_check posts_eq2[] = { check_eq2, NULL }; 7395c635efSGarrett D'Amore static v_check posts_fi[] = { check_eq0, post_fi, NULL }; 7495c635efSGarrett D'Amore static v_check posts_ft[] = { post_ft, NULL }; 75*698f87a4SGarrett D'Amore static v_check posts_ip[] = { post_IP, NULL }; 76*698f87a4SGarrett D'Amore static v_check posts_le1[] = { check_le1, NULL }; 7795c635efSGarrett D'Amore static v_check posts_nf[] = { check_eq0, post_nf, NULL }; 7895c635efSGarrett D'Amore static v_check posts_par[] = { check_par, NULL }; 7995c635efSGarrett D'Amore static v_check posts_part[] = { check_part, NULL }; 8095c635efSGarrett D'Amore static v_check posts_sec[] = { post_sec, NULL }; 8195c635efSGarrett D'Amore static v_check posts_sp[] = { post_vs, check_le1, NULL }; 8295c635efSGarrett D'Amore static v_check posts_th[] = { check_ge2, check_le5, post_TH, NULL }; 8395c635efSGarrett D'Amore static v_check posts_uc[] = { post_UC, NULL }; 84*698f87a4SGarrett D'Amore static v_check posts_ur[] = { check_head1, check_part, NULL }; 8595c635efSGarrett D'Amore static v_check pres_sec[] = { pre_sec, NULL }; 8695c635efSGarrett D'Amore 8795c635efSGarrett D'Amore static const struct man_valid man_valids[MAN_MAX] = { 8895c635efSGarrett D'Amore { NULL, posts_br }, /* br */ 8995c635efSGarrett D'Amore { NULL, posts_th }, /* TH */ 9095c635efSGarrett D'Amore { pres_sec, posts_sec }, /* SH */ 9195c635efSGarrett D'Amore { pres_sec, posts_sec }, /* SS */ 9295c635efSGarrett D'Amore { NULL, NULL }, /* TP */ 9395c635efSGarrett D'Amore { NULL, posts_par }, /* LP */ 9495c635efSGarrett D'Amore { NULL, posts_par }, /* PP */ 9595c635efSGarrett D'Amore { NULL, posts_par }, /* P */ 96*698f87a4SGarrett D'Amore { NULL, posts_ip }, /* IP */ 9795c635efSGarrett D'Amore { NULL, NULL }, /* HP */ 9895c635efSGarrett D'Amore { NULL, NULL }, /* SM */ 9995c635efSGarrett D'Amore { NULL, NULL }, /* SB */ 10095c635efSGarrett D'Amore { NULL, NULL }, /* BI */ 10195c635efSGarrett D'Amore { NULL, NULL }, /* IB */ 10295c635efSGarrett D'Amore { NULL, NULL }, /* BR */ 10395c635efSGarrett D'Amore { NULL, NULL }, /* RB */ 10495c635efSGarrett D'Amore { NULL, NULL }, /* R */ 10595c635efSGarrett D'Amore { NULL, NULL }, /* B */ 10695c635efSGarrett D'Amore { NULL, NULL }, /* I */ 10795c635efSGarrett D'Amore { NULL, NULL }, /* IR */ 10895c635efSGarrett D'Amore { NULL, NULL }, /* RI */ 10995c635efSGarrett D'Amore { NULL, posts_eq0 }, /* na */ 11095c635efSGarrett D'Amore { NULL, posts_sp }, /* sp */ 11195c635efSGarrett D'Amore { NULL, posts_nf }, /* nf */ 11295c635efSGarrett D'Amore { NULL, posts_fi }, /* fi */ 11395c635efSGarrett D'Amore { NULL, NULL }, /* RE */ 11495c635efSGarrett D'Amore { NULL, posts_part }, /* RS */ 11595c635efSGarrett D'Amore { NULL, NULL }, /* DT */ 11695c635efSGarrett D'Amore { NULL, posts_uc }, /* UC */ 117*698f87a4SGarrett D'Amore { NULL, posts_le1 }, /* PD */ 11895c635efSGarrett D'Amore { NULL, posts_at }, /* AT */ 11995c635efSGarrett D'Amore { NULL, NULL }, /* in */ 12095c635efSGarrett D'Amore { NULL, posts_ft }, /* ft */ 12195c635efSGarrett D'Amore { NULL, posts_eq2 }, /* OP */ 122*698f87a4SGarrett D'Amore { NULL, posts_nf }, /* EX */ 123*698f87a4SGarrett D'Amore { NULL, posts_fi }, /* EE */ 124*698f87a4SGarrett D'Amore { NULL, posts_ur }, /* UR */ 125*698f87a4SGarrett D'Amore { NULL, NULL }, /* UE */ 12695c635efSGarrett D'Amore }; 12795c635efSGarrett D'Amore 12895c635efSGarrett D'Amore 12995c635efSGarrett D'Amore int 130*698f87a4SGarrett D'Amore man_valid_pre(struct man *man, struct man_node *n) 13195c635efSGarrett D'Amore { 13295c635efSGarrett D'Amore v_check *cp; 13395c635efSGarrett D'Amore 13495c635efSGarrett D'Amore switch (n->type) { 13595c635efSGarrett D'Amore case (MAN_TEXT): 13695c635efSGarrett D'Amore /* FALLTHROUGH */ 13795c635efSGarrett D'Amore case (MAN_ROOT): 13895c635efSGarrett D'Amore /* FALLTHROUGH */ 13995c635efSGarrett D'Amore case (MAN_EQN): 14095c635efSGarrett D'Amore /* FALLTHROUGH */ 14195c635efSGarrett D'Amore case (MAN_TBL): 14295c635efSGarrett D'Amore return(1); 14395c635efSGarrett D'Amore default: 14495c635efSGarrett D'Amore break; 14595c635efSGarrett D'Amore } 14695c635efSGarrett D'Amore 14795c635efSGarrett D'Amore if (NULL == (cp = man_valids[n->tok].pres)) 14895c635efSGarrett D'Amore return(1); 14995c635efSGarrett D'Amore for ( ; *cp; cp++) 150*698f87a4SGarrett D'Amore if ( ! (*cp)(man, n)) 15195c635efSGarrett D'Amore return(0); 15295c635efSGarrett D'Amore return(1); 15395c635efSGarrett D'Amore } 15495c635efSGarrett D'Amore 15595c635efSGarrett D'Amore 15695c635efSGarrett D'Amore int 157*698f87a4SGarrett D'Amore man_valid_post(struct man *man) 15895c635efSGarrett D'Amore { 15995c635efSGarrett D'Amore v_check *cp; 16095c635efSGarrett D'Amore 161*698f87a4SGarrett D'Amore if (MAN_VALID & man->last->flags) 16295c635efSGarrett D'Amore return(1); 163*698f87a4SGarrett D'Amore man->last->flags |= MAN_VALID; 16495c635efSGarrett D'Amore 165*698f87a4SGarrett D'Amore switch (man->last->type) { 16695c635efSGarrett D'Amore case (MAN_TEXT): 167*698f87a4SGarrett D'Amore check_text(man, man->last); 16895c635efSGarrett D'Amore return(1); 16995c635efSGarrett D'Amore case (MAN_ROOT): 170*698f87a4SGarrett D'Amore return(check_root(man, man->last)); 17195c635efSGarrett D'Amore case (MAN_EQN): 17295c635efSGarrett D'Amore /* FALLTHROUGH */ 17395c635efSGarrett D'Amore case (MAN_TBL): 17495c635efSGarrett D'Amore return(1); 17595c635efSGarrett D'Amore default: 17695c635efSGarrett D'Amore break; 17795c635efSGarrett D'Amore } 17895c635efSGarrett D'Amore 179*698f87a4SGarrett D'Amore if (NULL == (cp = man_valids[man->last->tok].posts)) 18095c635efSGarrett D'Amore return(1); 18195c635efSGarrett D'Amore for ( ; *cp; cp++) 182*698f87a4SGarrett D'Amore if ( ! (*cp)(man, man->last)) 18395c635efSGarrett D'Amore return(0); 18495c635efSGarrett D'Amore 18595c635efSGarrett D'Amore return(1); 18695c635efSGarrett D'Amore } 18795c635efSGarrett D'Amore 18895c635efSGarrett D'Amore 18995c635efSGarrett D'Amore static int 19095c635efSGarrett D'Amore check_root(CHKARGS) 19195c635efSGarrett D'Amore { 19295c635efSGarrett D'Amore 193*698f87a4SGarrett D'Amore if (MAN_BLINE & man->flags) 194*698f87a4SGarrett D'Amore man_nmsg(man, n, MANDOCERR_SCOPEEXIT); 195*698f87a4SGarrett D'Amore else if (MAN_ELINE & man->flags) 196*698f87a4SGarrett D'Amore man_nmsg(man, n, MANDOCERR_SCOPEEXIT); 19795c635efSGarrett D'Amore 198*698f87a4SGarrett D'Amore man->flags &= ~MAN_BLINE; 199*698f87a4SGarrett D'Amore man->flags &= ~MAN_ELINE; 20095c635efSGarrett D'Amore 201*698f87a4SGarrett D'Amore if (NULL == man->first->child) { 202*698f87a4SGarrett D'Amore man_nmsg(man, n, MANDOCERR_NODOCBODY); 20395c635efSGarrett D'Amore return(0); 204*698f87a4SGarrett D'Amore } else if (NULL == man->meta.title) { 205*698f87a4SGarrett D'Amore man_nmsg(man, n, MANDOCERR_NOTITLE); 20695c635efSGarrett D'Amore 20795c635efSGarrett D'Amore /* 20895c635efSGarrett D'Amore * If a title hasn't been set, do so now (by 20995c635efSGarrett D'Amore * implication, date and section also aren't set). 21095c635efSGarrett D'Amore */ 21195c635efSGarrett D'Amore 212*698f87a4SGarrett D'Amore man->meta.title = mandoc_strdup("unknown"); 213*698f87a4SGarrett D'Amore man->meta.msec = mandoc_strdup("1"); 214*698f87a4SGarrett D'Amore man->meta.date = mandoc_normdate 215*698f87a4SGarrett D'Amore (man->parse, NULL, n->line, n->pos); 21695c635efSGarrett D'Amore } 21795c635efSGarrett D'Amore 21895c635efSGarrett D'Amore return(1); 21995c635efSGarrett D'Amore } 22095c635efSGarrett D'Amore 22195c635efSGarrett D'Amore static void 22295c635efSGarrett D'Amore check_text(CHKARGS) 22395c635efSGarrett D'Amore { 22495c635efSGarrett D'Amore char *cp, *p; 22595c635efSGarrett D'Amore 226*698f87a4SGarrett D'Amore if (MAN_LITERAL & man->flags) 22795c635efSGarrett D'Amore return; 22895c635efSGarrett D'Amore 22995c635efSGarrett D'Amore cp = n->string; 23095c635efSGarrett D'Amore for (p = cp; NULL != (p = strchr(p, '\t')); p++) 231*698f87a4SGarrett D'Amore man_pmsg(man, n->line, (int)(p - cp), MANDOCERR_BADTAB); 23295c635efSGarrett D'Amore } 23395c635efSGarrett D'Amore 23495c635efSGarrett D'Amore #define INEQ_DEFINE(x, ineq, name) \ 23595c635efSGarrett D'Amore static int \ 23695c635efSGarrett D'Amore check_##name(CHKARGS) \ 23795c635efSGarrett D'Amore { \ 23895c635efSGarrett D'Amore if (n->nchild ineq (x)) \ 23995c635efSGarrett D'Amore return(1); \ 240*698f87a4SGarrett D'Amore mandoc_vmsg(MANDOCERR_ARGCOUNT, man->parse, n->line, n->pos, \ 24195c635efSGarrett D'Amore "line arguments %s %d (have %d)", \ 24295c635efSGarrett D'Amore #ineq, (x), n->nchild); \ 24395c635efSGarrett D'Amore return(1); \ 24495c635efSGarrett D'Amore } 24595c635efSGarrett D'Amore 24695c635efSGarrett D'Amore INEQ_DEFINE(0, ==, eq0) 24795c635efSGarrett D'Amore INEQ_DEFINE(2, ==, eq2) 24895c635efSGarrett D'Amore INEQ_DEFINE(1, <=, le1) 24995c635efSGarrett D'Amore INEQ_DEFINE(2, >=, ge2) 25095c635efSGarrett D'Amore INEQ_DEFINE(5, <=, le5) 25195c635efSGarrett D'Amore 25295c635efSGarrett D'Amore static int 253*698f87a4SGarrett D'Amore check_head1(CHKARGS) 254*698f87a4SGarrett D'Amore { 255*698f87a4SGarrett D'Amore 256*698f87a4SGarrett D'Amore if (MAN_HEAD == n->type && 1 != n->nchild) 257*698f87a4SGarrett D'Amore mandoc_vmsg(MANDOCERR_ARGCOUNT, man->parse, n->line, 258*698f87a4SGarrett D'Amore n->pos, "line arguments eq 1 (have %d)", n->nchild); 259*698f87a4SGarrett D'Amore 260*698f87a4SGarrett D'Amore return(1); 261*698f87a4SGarrett D'Amore } 262*698f87a4SGarrett D'Amore 263*698f87a4SGarrett D'Amore static int 26495c635efSGarrett D'Amore post_ft(CHKARGS) 26595c635efSGarrett D'Amore { 26695c635efSGarrett D'Amore char *cp; 26795c635efSGarrett D'Amore int ok; 26895c635efSGarrett D'Amore 26995c635efSGarrett D'Amore if (0 == n->nchild) 27095c635efSGarrett D'Amore return(1); 27195c635efSGarrett D'Amore 27295c635efSGarrett D'Amore ok = 0; 27395c635efSGarrett D'Amore cp = n->child->string; 27495c635efSGarrett D'Amore switch (*cp) { 27595c635efSGarrett D'Amore case ('1'): 27695c635efSGarrett D'Amore /* FALLTHROUGH */ 27795c635efSGarrett D'Amore case ('2'): 27895c635efSGarrett D'Amore /* FALLTHROUGH */ 27995c635efSGarrett D'Amore case ('3'): 28095c635efSGarrett D'Amore /* FALLTHROUGH */ 28195c635efSGarrett D'Amore case ('4'): 28295c635efSGarrett D'Amore /* FALLTHROUGH */ 28395c635efSGarrett D'Amore case ('I'): 28495c635efSGarrett D'Amore /* FALLTHROUGH */ 28595c635efSGarrett D'Amore case ('P'): 28695c635efSGarrett D'Amore /* FALLTHROUGH */ 28795c635efSGarrett D'Amore case ('R'): 28895c635efSGarrett D'Amore if ('\0' == cp[1]) 28995c635efSGarrett D'Amore ok = 1; 29095c635efSGarrett D'Amore break; 29195c635efSGarrett D'Amore case ('B'): 29295c635efSGarrett D'Amore if ('\0' == cp[1] || ('I' == cp[1] && '\0' == cp[2])) 29395c635efSGarrett D'Amore ok = 1; 29495c635efSGarrett D'Amore break; 29595c635efSGarrett D'Amore case ('C'): 29695c635efSGarrett D'Amore if ('W' == cp[1] && '\0' == cp[2]) 29795c635efSGarrett D'Amore ok = 1; 29895c635efSGarrett D'Amore break; 29995c635efSGarrett D'Amore default: 30095c635efSGarrett D'Amore break; 30195c635efSGarrett D'Amore } 30295c635efSGarrett D'Amore 30395c635efSGarrett D'Amore if (0 == ok) { 30495c635efSGarrett D'Amore mandoc_vmsg 305*698f87a4SGarrett D'Amore (MANDOCERR_BADFONT, man->parse, 30695c635efSGarrett D'Amore n->line, n->pos, "%s", cp); 30795c635efSGarrett D'Amore *cp = '\0'; 30895c635efSGarrett D'Amore } 30995c635efSGarrett D'Amore 31095c635efSGarrett D'Amore if (1 < n->nchild) 31195c635efSGarrett D'Amore mandoc_vmsg 312*698f87a4SGarrett D'Amore (MANDOCERR_ARGCOUNT, man->parse, n->line, 31395c635efSGarrett D'Amore n->pos, "want one child (have %d)", 31495c635efSGarrett D'Amore n->nchild); 31595c635efSGarrett D'Amore 31695c635efSGarrett D'Amore return(1); 31795c635efSGarrett D'Amore } 31895c635efSGarrett D'Amore 31995c635efSGarrett D'Amore static int 32095c635efSGarrett D'Amore pre_sec(CHKARGS) 32195c635efSGarrett D'Amore { 32295c635efSGarrett D'Amore 32395c635efSGarrett D'Amore if (MAN_BLOCK == n->type) 324*698f87a4SGarrett D'Amore man->flags &= ~MAN_LITERAL; 32595c635efSGarrett D'Amore return(1); 32695c635efSGarrett D'Amore } 32795c635efSGarrett D'Amore 32895c635efSGarrett D'Amore static int 32995c635efSGarrett D'Amore post_sec(CHKARGS) 33095c635efSGarrett D'Amore { 33195c635efSGarrett D'Amore 33295c635efSGarrett D'Amore if ( ! (MAN_HEAD == n->type && 0 == n->nchild)) 33395c635efSGarrett D'Amore return(1); 33495c635efSGarrett D'Amore 335*698f87a4SGarrett D'Amore man_nmsg(man, n, MANDOCERR_SYNTARGCOUNT); 33695c635efSGarrett D'Amore return(0); 33795c635efSGarrett D'Amore } 33895c635efSGarrett D'Amore 33995c635efSGarrett D'Amore static int 34095c635efSGarrett D'Amore check_part(CHKARGS) 34195c635efSGarrett D'Amore { 34295c635efSGarrett D'Amore 34395c635efSGarrett D'Amore if (MAN_BODY == n->type && 0 == n->nchild) 344*698f87a4SGarrett D'Amore mandoc_msg(MANDOCERR_ARGCWARN, man->parse, n->line, 34595c635efSGarrett D'Amore n->pos, "want children (have none)"); 34695c635efSGarrett D'Amore 34795c635efSGarrett D'Amore return(1); 34895c635efSGarrett D'Amore } 34995c635efSGarrett D'Amore 35095c635efSGarrett D'Amore 35195c635efSGarrett D'Amore static int 35295c635efSGarrett D'Amore check_par(CHKARGS) 35395c635efSGarrett D'Amore { 35495c635efSGarrett D'Amore 35595c635efSGarrett D'Amore switch (n->type) { 35695c635efSGarrett D'Amore case (MAN_BLOCK): 35795c635efSGarrett D'Amore if (0 == n->body->nchild) 358*698f87a4SGarrett D'Amore man_node_delete(man, n); 35995c635efSGarrett D'Amore break; 36095c635efSGarrett D'Amore case (MAN_BODY): 36195c635efSGarrett D'Amore if (0 == n->nchild) 362*698f87a4SGarrett D'Amore man_nmsg(man, n, MANDOCERR_IGNPAR); 36395c635efSGarrett D'Amore break; 36495c635efSGarrett D'Amore case (MAN_HEAD): 36595c635efSGarrett D'Amore if (n->nchild) 366*698f87a4SGarrett D'Amore man_nmsg(man, n, MANDOCERR_ARGSLOST); 36795c635efSGarrett D'Amore break; 36895c635efSGarrett D'Amore default: 36995c635efSGarrett D'Amore break; 37095c635efSGarrett D'Amore } 37195c635efSGarrett D'Amore 37295c635efSGarrett D'Amore return(1); 37395c635efSGarrett D'Amore } 37495c635efSGarrett D'Amore 375*698f87a4SGarrett D'Amore static int 376*698f87a4SGarrett D'Amore post_IP(CHKARGS) 377*698f87a4SGarrett D'Amore { 378*698f87a4SGarrett D'Amore 379*698f87a4SGarrett D'Amore switch (n->type) { 380*698f87a4SGarrett D'Amore case (MAN_BLOCK): 381*698f87a4SGarrett D'Amore if (0 == n->head->nchild && 0 == n->body->nchild) 382*698f87a4SGarrett D'Amore man_node_delete(man, n); 383*698f87a4SGarrett D'Amore break; 384*698f87a4SGarrett D'Amore case (MAN_BODY): 385*698f87a4SGarrett D'Amore if (0 == n->parent->head->nchild && 0 == n->nchild) 386*698f87a4SGarrett D'Amore man_nmsg(man, n, MANDOCERR_IGNPAR); 387*698f87a4SGarrett D'Amore break; 388*698f87a4SGarrett D'Amore default: 389*698f87a4SGarrett D'Amore break; 390*698f87a4SGarrett D'Amore } 391*698f87a4SGarrett D'Amore return(1); 392*698f87a4SGarrett D'Amore } 39395c635efSGarrett D'Amore 39495c635efSGarrett D'Amore static int 39595c635efSGarrett D'Amore post_TH(CHKARGS) 39695c635efSGarrett D'Amore { 39795c635efSGarrett D'Amore const char *p; 39895c635efSGarrett D'Amore int line, pos; 39995c635efSGarrett D'Amore 400*698f87a4SGarrett D'Amore free(man->meta.title); 401*698f87a4SGarrett D'Amore free(man->meta.vol); 402*698f87a4SGarrett D'Amore free(man->meta.source); 403*698f87a4SGarrett D'Amore free(man->meta.msec); 404*698f87a4SGarrett D'Amore free(man->meta.date); 40595c635efSGarrett D'Amore 40695c635efSGarrett D'Amore line = n->line; 40795c635efSGarrett D'Amore pos = n->pos; 408*698f87a4SGarrett D'Amore man->meta.title = man->meta.vol = man->meta.date = 409*698f87a4SGarrett D'Amore man->meta.msec = man->meta.source = NULL; 41095c635efSGarrett D'Amore 41195c635efSGarrett D'Amore /* ->TITLE<- MSEC DATE SOURCE VOL */ 41295c635efSGarrett D'Amore 41395c635efSGarrett D'Amore n = n->child; 41495c635efSGarrett D'Amore if (n && n->string) { 41595c635efSGarrett D'Amore for (p = n->string; '\0' != *p; p++) { 41695c635efSGarrett D'Amore /* Only warn about this once... */ 41795c635efSGarrett D'Amore if (isalpha((unsigned char)*p) && 41895c635efSGarrett D'Amore ! isupper((unsigned char)*p)) { 419*698f87a4SGarrett D'Amore man_nmsg(man, n, MANDOCERR_UPPERCASE); 42095c635efSGarrett D'Amore break; 42195c635efSGarrett D'Amore } 42295c635efSGarrett D'Amore } 423*698f87a4SGarrett D'Amore man->meta.title = mandoc_strdup(n->string); 42495c635efSGarrett D'Amore } else 425*698f87a4SGarrett D'Amore man->meta.title = mandoc_strdup(""); 42695c635efSGarrett D'Amore 42795c635efSGarrett D'Amore /* TITLE ->MSEC<- DATE SOURCE VOL */ 42895c635efSGarrett D'Amore 42995c635efSGarrett D'Amore if (n) 43095c635efSGarrett D'Amore n = n->next; 43195c635efSGarrett D'Amore if (n && n->string) 432*698f87a4SGarrett D'Amore man->meta.msec = mandoc_strdup(n->string); 43395c635efSGarrett D'Amore else 434*698f87a4SGarrett D'Amore man->meta.msec = mandoc_strdup(""); 43595c635efSGarrett D'Amore 43695c635efSGarrett D'Amore /* TITLE MSEC ->DATE<- SOURCE VOL */ 43795c635efSGarrett D'Amore 43895c635efSGarrett D'Amore if (n) 43995c635efSGarrett D'Amore n = n->next; 44095c635efSGarrett D'Amore if (n && n->string && '\0' != n->string[0]) { 44195c635efSGarrett D'Amore pos = n->pos; 442*698f87a4SGarrett D'Amore man->meta.date = mandoc_normdate 443*698f87a4SGarrett D'Amore (man->parse, n->string, line, pos); 44495c635efSGarrett D'Amore } else 445*698f87a4SGarrett D'Amore man->meta.date = mandoc_strdup(""); 44695c635efSGarrett D'Amore 44795c635efSGarrett D'Amore /* TITLE MSEC DATE ->SOURCE<- VOL */ 44895c635efSGarrett D'Amore 44995c635efSGarrett D'Amore if (n && (n = n->next)) 450*698f87a4SGarrett D'Amore man->meta.source = mandoc_strdup(n->string); 45195c635efSGarrett D'Amore 45295c635efSGarrett D'Amore /* TITLE MSEC DATE SOURCE ->VOL<- */ 45395c635efSGarrett D'Amore /* If missing, use the default VOL name for MSEC. */ 45495c635efSGarrett D'Amore 45595c635efSGarrett D'Amore if (n && (n = n->next)) 456*698f87a4SGarrett D'Amore man->meta.vol = mandoc_strdup(n->string); 457*698f87a4SGarrett D'Amore else if ('\0' != man->meta.msec[0] && 458*698f87a4SGarrett D'Amore (NULL != (p = mandoc_a2msec(man->meta.msec)))) 459*698f87a4SGarrett D'Amore man->meta.vol = mandoc_strdup(p); 46095c635efSGarrett D'Amore 46195c635efSGarrett D'Amore /* 46295c635efSGarrett D'Amore * Remove the `TH' node after we've processed it for our 46395c635efSGarrett D'Amore * meta-data. 46495c635efSGarrett D'Amore */ 465*698f87a4SGarrett D'Amore man_node_delete(man, man->last); 46695c635efSGarrett D'Amore return(1); 46795c635efSGarrett D'Amore } 46895c635efSGarrett D'Amore 46995c635efSGarrett D'Amore static int 47095c635efSGarrett D'Amore post_nf(CHKARGS) 47195c635efSGarrett D'Amore { 47295c635efSGarrett D'Amore 473*698f87a4SGarrett D'Amore if (MAN_LITERAL & man->flags) 474*698f87a4SGarrett D'Amore man_nmsg(man, n, MANDOCERR_SCOPEREP); 47595c635efSGarrett D'Amore 476*698f87a4SGarrett D'Amore man->flags |= MAN_LITERAL; 47795c635efSGarrett D'Amore return(1); 47895c635efSGarrett D'Amore } 47995c635efSGarrett D'Amore 48095c635efSGarrett D'Amore static int 48195c635efSGarrett D'Amore post_fi(CHKARGS) 48295c635efSGarrett D'Amore { 48395c635efSGarrett D'Amore 484*698f87a4SGarrett D'Amore if ( ! (MAN_LITERAL & man->flags)) 485*698f87a4SGarrett D'Amore man_nmsg(man, n, MANDOCERR_WNOSCOPE); 48695c635efSGarrett D'Amore 487*698f87a4SGarrett D'Amore man->flags &= ~MAN_LITERAL; 48895c635efSGarrett D'Amore return(1); 48995c635efSGarrett D'Amore } 49095c635efSGarrett D'Amore 49195c635efSGarrett D'Amore static int 49295c635efSGarrett D'Amore post_UC(CHKARGS) 49395c635efSGarrett D'Amore { 49495c635efSGarrett D'Amore static const char * const bsd_versions[] = { 49595c635efSGarrett D'Amore "3rd Berkeley Distribution", 49695c635efSGarrett D'Amore "4th Berkeley Distribution", 49795c635efSGarrett D'Amore "4.2 Berkeley Distribution", 49895c635efSGarrett D'Amore "4.3 Berkeley Distribution", 49995c635efSGarrett D'Amore "4.4 Berkeley Distribution", 50095c635efSGarrett D'Amore }; 50195c635efSGarrett D'Amore 50295c635efSGarrett D'Amore const char *p, *s; 50395c635efSGarrett D'Amore 50495c635efSGarrett D'Amore n = n->child; 50595c635efSGarrett D'Amore 50695c635efSGarrett D'Amore if (NULL == n || MAN_TEXT != n->type) 50795c635efSGarrett D'Amore p = bsd_versions[0]; 50895c635efSGarrett D'Amore else { 50995c635efSGarrett D'Amore s = n->string; 51095c635efSGarrett D'Amore if (0 == strcmp(s, "3")) 51195c635efSGarrett D'Amore p = bsd_versions[0]; 51295c635efSGarrett D'Amore else if (0 == strcmp(s, "4")) 51395c635efSGarrett D'Amore p = bsd_versions[1]; 51495c635efSGarrett D'Amore else if (0 == strcmp(s, "5")) 51595c635efSGarrett D'Amore p = bsd_versions[2]; 51695c635efSGarrett D'Amore else if (0 == strcmp(s, "6")) 51795c635efSGarrett D'Amore p = bsd_versions[3]; 51895c635efSGarrett D'Amore else if (0 == strcmp(s, "7")) 51995c635efSGarrett D'Amore p = bsd_versions[4]; 52095c635efSGarrett D'Amore else 52195c635efSGarrett D'Amore p = bsd_versions[0]; 52295c635efSGarrett D'Amore } 52395c635efSGarrett D'Amore 524*698f87a4SGarrett D'Amore free(man->meta.source); 525*698f87a4SGarrett D'Amore man->meta.source = mandoc_strdup(p); 52695c635efSGarrett D'Amore return(1); 52795c635efSGarrett D'Amore } 52895c635efSGarrett D'Amore 52995c635efSGarrett D'Amore static int 53095c635efSGarrett D'Amore post_AT(CHKARGS) 53195c635efSGarrett D'Amore { 53295c635efSGarrett D'Amore static const char * const unix_versions[] = { 53395c635efSGarrett D'Amore "7th Edition", 53495c635efSGarrett D'Amore "System III", 53595c635efSGarrett D'Amore "System V", 53695c635efSGarrett D'Amore "System V Release 2", 53795c635efSGarrett D'Amore }; 53895c635efSGarrett D'Amore 53995c635efSGarrett D'Amore const char *p, *s; 54095c635efSGarrett D'Amore struct man_node *nn; 54195c635efSGarrett D'Amore 54295c635efSGarrett D'Amore n = n->child; 54395c635efSGarrett D'Amore 54495c635efSGarrett D'Amore if (NULL == n || MAN_TEXT != n->type) 54595c635efSGarrett D'Amore p = unix_versions[0]; 54695c635efSGarrett D'Amore else { 54795c635efSGarrett D'Amore s = n->string; 54895c635efSGarrett D'Amore if (0 == strcmp(s, "3")) 54995c635efSGarrett D'Amore p = unix_versions[0]; 55095c635efSGarrett D'Amore else if (0 == strcmp(s, "4")) 55195c635efSGarrett D'Amore p = unix_versions[1]; 55295c635efSGarrett D'Amore else if (0 == strcmp(s, "5")) { 55395c635efSGarrett D'Amore nn = n->next; 55495c635efSGarrett D'Amore if (nn && MAN_TEXT == nn->type && nn->string[0]) 55595c635efSGarrett D'Amore p = unix_versions[3]; 55695c635efSGarrett D'Amore else 55795c635efSGarrett D'Amore p = unix_versions[2]; 55895c635efSGarrett D'Amore } else 55995c635efSGarrett D'Amore p = unix_versions[0]; 56095c635efSGarrett D'Amore } 56195c635efSGarrett D'Amore 562*698f87a4SGarrett D'Amore free(man->meta.source); 563*698f87a4SGarrett D'Amore man->meta.source = mandoc_strdup(p); 56495c635efSGarrett D'Amore return(1); 56595c635efSGarrett D'Amore } 56695c635efSGarrett D'Amore 56795c635efSGarrett D'Amore static int 56895c635efSGarrett D'Amore post_vs(CHKARGS) 56995c635efSGarrett D'Amore { 57095c635efSGarrett D'Amore 571*698f87a4SGarrett D'Amore if (NULL != n->prev) 572*698f87a4SGarrett D'Amore return(1); 573*698f87a4SGarrett D'Amore 574*698f87a4SGarrett D'Amore switch (n->parent->tok) { 575*698f87a4SGarrett D'Amore case (MAN_SH): 576*698f87a4SGarrett D'Amore /* FALLTHROUGH */ 577*698f87a4SGarrett D'Amore case (MAN_SS): 578*698f87a4SGarrett D'Amore man_nmsg(man, n, MANDOCERR_IGNPAR); 579*698f87a4SGarrett D'Amore /* FALLTHROUGH */ 580*698f87a4SGarrett D'Amore case (MAN_MAX): 58195c635efSGarrett D'Amore /* 582*698f87a4SGarrett D'Amore * Don't warn about this because it occurs in pod2man 583*698f87a4SGarrett D'Amore * and would cause considerable (unfixable) warnage. 58495c635efSGarrett D'Amore */ 585*698f87a4SGarrett D'Amore man_node_delete(man, n); 586*698f87a4SGarrett D'Amore break; 587*698f87a4SGarrett D'Amore default: 588*698f87a4SGarrett D'Amore break; 589*698f87a4SGarrett D'Amore } 59095c635efSGarrett D'Amore 59195c635efSGarrett D'Amore return(1); 59295c635efSGarrett D'Amore } 593