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