Home | History | Annotate | Line # | Download | only in dist
man.c revision 1.1.1.10
      1  1.1.1.10  joerg /*	$Vendor-Id: man.c,v 1.96 2011/01/03 11:31:26 kristaps Exp $ */
      2       1.1  joerg /*
      3   1.1.1.9  joerg  * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons <kristaps (at) bsd.lv>
      4       1.1  joerg  *
      5       1.1  joerg  * Permission to use, copy, modify, and distribute this software for any
      6       1.1  joerg  * purpose with or without fee is hereby granted, provided that the above
      7       1.1  joerg  * copyright notice and this permission notice appear in all copies.
      8       1.1  joerg  *
      9       1.1  joerg  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     10       1.1  joerg  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     11       1.1  joerg  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     12       1.1  joerg  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     13       1.1  joerg  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     14       1.1  joerg  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     15       1.1  joerg  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     16       1.1  joerg  */
     17   1.1.1.4  joerg #ifdef HAVE_CONFIG_H
     18   1.1.1.4  joerg #include "config.h"
     19   1.1.1.4  joerg #endif
     20   1.1.1.4  joerg 
     21       1.1  joerg #include <sys/types.h>
     22       1.1  joerg 
     23       1.1  joerg #include <assert.h>
     24       1.1  joerg #include <stdarg.h>
     25       1.1  joerg #include <stdlib.h>
     26       1.1  joerg #include <stdio.h>
     27       1.1  joerg #include <string.h>
     28       1.1  joerg 
     29   1.1.1.6  joerg #include "mandoc.h"
     30       1.1  joerg #include "libman.h"
     31   1.1.1.3  joerg #include "libmandoc.h"
     32       1.1  joerg 
     33       1.1  joerg const	char *const __man_macronames[MAN_MAX] = {
     34       1.1  joerg 	"br",		"TH",		"SH",		"SS",
     35       1.1  joerg 	"TP", 		"LP",		"PP",		"P",
     36       1.1  joerg 	"IP",		"HP",		"SM",		"SB",
     37       1.1  joerg 	"BI",		"IB",		"BR",		"RB",
     38       1.1  joerg 	"R",		"B",		"I",		"IR",
     39  1.1.1.10  joerg 	"RI",		"na",		"sp",		"nf",
     40  1.1.1.10  joerg 	"fi",		"RE",		"RS",		"DT",
     41  1.1.1.10  joerg 	"UC",		"PD",		"AT",		"in",
     42  1.1.1.10  joerg 	"ft"
     43       1.1  joerg 	};
     44       1.1  joerg 
     45       1.1  joerg const	char * const *man_macronames = __man_macronames;
     46       1.1  joerg 
     47       1.1  joerg static	struct man_node	*man_node_alloc(int, int,
     48   1.1.1.5  joerg 				enum man_type, enum mant);
     49       1.1  joerg static	int		 man_node_append(struct man *,
     50       1.1  joerg 				struct man_node *);
     51  1.1.1.10  joerg static	int		 man_span_alloc(struct man *,
     52  1.1.1.10  joerg 				const struct tbl_span *);
     53   1.1.1.5  joerg static	void		 man_node_free(struct man_node *);
     54   1.1.1.5  joerg static	void		 man_node_unlink(struct man *,
     55   1.1.1.5  joerg 				struct man_node *);
     56   1.1.1.6  joerg static	int		 man_ptext(struct man *, int, char *, int);
     57   1.1.1.6  joerg static	int		 man_pmacro(struct man *, int, char *, int);
     58       1.1  joerg static	void		 man_free1(struct man *);
     59   1.1.1.3  joerg static	void		 man_alloc1(struct man *);
     60  1.1.1.10  joerg static	int		 man_descope(struct man *, int, int);
     61       1.1  joerg 
     62       1.1  joerg 
     63       1.1  joerg const struct man_node *
     64       1.1  joerg man_node(const struct man *m)
     65       1.1  joerg {
     66       1.1  joerg 
     67  1.1.1.10  joerg 	assert( ! (MAN_HALT & m->flags));
     68  1.1.1.10  joerg 	return(m->first);
     69       1.1  joerg }
     70       1.1  joerg 
     71       1.1  joerg 
     72       1.1  joerg const struct man_meta *
     73       1.1  joerg man_meta(const struct man *m)
     74       1.1  joerg {
     75       1.1  joerg 
     76  1.1.1.10  joerg 	assert( ! (MAN_HALT & m->flags));
     77  1.1.1.10  joerg 	return(&m->meta);
     78       1.1  joerg }
     79       1.1  joerg 
     80       1.1  joerg 
     81   1.1.1.3  joerg void
     82       1.1  joerg man_reset(struct man *man)
     83       1.1  joerg {
     84       1.1  joerg 
     85       1.1  joerg 	man_free1(man);
     86   1.1.1.3  joerg 	man_alloc1(man);
     87       1.1  joerg }
     88       1.1  joerg 
     89       1.1  joerg 
     90       1.1  joerg void
     91       1.1  joerg man_free(struct man *man)
     92       1.1  joerg {
     93       1.1  joerg 
     94       1.1  joerg 	man_free1(man);
     95       1.1  joerg 	free(man);
     96       1.1  joerg }
     97       1.1  joerg 
     98       1.1  joerg 
     99       1.1  joerg struct man *
    100  1.1.1.10  joerg man_alloc(struct regset *regs, void *data, mandocmsg msg)
    101       1.1  joerg {
    102       1.1  joerg 	struct man	*p;
    103       1.1  joerg 
    104   1.1.1.3  joerg 	p = mandoc_calloc(1, sizeof(struct man));
    105       1.1  joerg 
    106       1.1  joerg 	man_hash_init();
    107       1.1  joerg 	p->data = data;
    108   1.1.1.6  joerg 	p->msg = msg;
    109   1.1.1.8  joerg 	p->regs = regs;
    110   1.1.1.3  joerg 
    111   1.1.1.3  joerg 	man_alloc1(p);
    112       1.1  joerg 	return(p);
    113       1.1  joerg }
    114       1.1  joerg 
    115       1.1  joerg 
    116       1.1  joerg int
    117       1.1  joerg man_endparse(struct man *m)
    118       1.1  joerg {
    119       1.1  joerg 
    120  1.1.1.10  joerg 	assert( ! (MAN_HALT & m->flags));
    121  1.1.1.10  joerg 	if (man_macroend(m))
    122       1.1  joerg 		return(1);
    123       1.1  joerg 	m->flags |= MAN_HALT;
    124       1.1  joerg 	return(0);
    125       1.1  joerg }
    126       1.1  joerg 
    127       1.1  joerg 
    128       1.1  joerg int
    129   1.1.1.6  joerg man_parseln(struct man *m, int ln, char *buf, int offs)
    130       1.1  joerg {
    131       1.1  joerg 
    132  1.1.1.10  joerg 	assert( ! (MAN_HALT & m->flags));
    133   1.1.1.6  joerg 	return(('.' == buf[offs] || '\'' == buf[offs]) ?
    134   1.1.1.6  joerg 			man_pmacro(m, ln, buf, offs) :
    135   1.1.1.6  joerg 			man_ptext(m, ln, buf, offs));
    136       1.1  joerg }
    137       1.1  joerg 
    138       1.1  joerg 
    139       1.1  joerg static void
    140       1.1  joerg man_free1(struct man *man)
    141       1.1  joerg {
    142       1.1  joerg 
    143       1.1  joerg 	if (man->first)
    144   1.1.1.5  joerg 		man_node_delete(man, man->first);
    145       1.1  joerg 	if (man->meta.title)
    146       1.1  joerg 		free(man->meta.title);
    147       1.1  joerg 	if (man->meta.source)
    148       1.1  joerg 		free(man->meta.source);
    149   1.1.1.6  joerg 	if (man->meta.rawdate)
    150   1.1.1.6  joerg 		free(man->meta.rawdate);
    151       1.1  joerg 	if (man->meta.vol)
    152       1.1  joerg 		free(man->meta.vol);
    153   1.1.1.6  joerg 	if (man->meta.msec)
    154   1.1.1.6  joerg 		free(man->meta.msec);
    155       1.1  joerg }
    156       1.1  joerg 
    157       1.1  joerg 
    158   1.1.1.3  joerg static void
    159       1.1  joerg man_alloc1(struct man *m)
    160       1.1  joerg {
    161       1.1  joerg 
    162   1.1.1.3  joerg 	memset(&m->meta, 0, sizeof(struct man_meta));
    163       1.1  joerg 	m->flags = 0;
    164   1.1.1.3  joerg 	m->last = mandoc_calloc(1, sizeof(struct man_node));
    165       1.1  joerg 	m->first = m->last;
    166       1.1  joerg 	m->last->type = MAN_ROOT;
    167   1.1.1.5  joerg 	m->last->tok = MAN_MAX;
    168       1.1  joerg 	m->next = MAN_NEXT_CHILD;
    169       1.1  joerg }
    170       1.1  joerg 
    171       1.1  joerg 
    172       1.1  joerg static int
    173       1.1  joerg man_node_append(struct man *man, struct man_node *p)
    174       1.1  joerg {
    175       1.1  joerg 
    176       1.1  joerg 	assert(man->last);
    177       1.1  joerg 	assert(man->first);
    178       1.1  joerg 	assert(MAN_ROOT != p->type);
    179       1.1  joerg 
    180       1.1  joerg 	switch (man->next) {
    181       1.1  joerg 	case (MAN_NEXT_SIBLING):
    182       1.1  joerg 		man->last->next = p;
    183       1.1  joerg 		p->prev = man->last;
    184       1.1  joerg 		p->parent = man->last->parent;
    185       1.1  joerg 		break;
    186       1.1  joerg 	case (MAN_NEXT_CHILD):
    187       1.1  joerg 		man->last->child = p;
    188       1.1  joerg 		p->parent = man->last;
    189       1.1  joerg 		break;
    190       1.1  joerg 	default:
    191       1.1  joerg 		abort();
    192       1.1  joerg 		/* NOTREACHED */
    193       1.1  joerg 	}
    194       1.1  joerg 
    195   1.1.1.5  joerg 	assert(p->parent);
    196       1.1  joerg 	p->parent->nchild++;
    197       1.1  joerg 
    198       1.1  joerg 	if ( ! man_valid_pre(man, p))
    199       1.1  joerg 		return(0);
    200       1.1  joerg 
    201       1.1  joerg 	switch (p->type) {
    202       1.1  joerg 	case (MAN_HEAD):
    203       1.1  joerg 		assert(MAN_BLOCK == p->parent->type);
    204       1.1  joerg 		p->parent->head = p;
    205       1.1  joerg 		break;
    206       1.1  joerg 	case (MAN_BODY):
    207       1.1  joerg 		assert(MAN_BLOCK == p->parent->type);
    208       1.1  joerg 		p->parent->body = p;
    209       1.1  joerg 		break;
    210       1.1  joerg 	default:
    211       1.1  joerg 		break;
    212       1.1  joerg 	}
    213       1.1  joerg 
    214       1.1  joerg 	man->last = p;
    215       1.1  joerg 
    216       1.1  joerg 	switch (p->type) {
    217  1.1.1.10  joerg 	case (MAN_TBL):
    218  1.1.1.10  joerg 		/* FALLTHROUGH */
    219       1.1  joerg 	case (MAN_TEXT):
    220       1.1  joerg 		if ( ! man_valid_post(man))
    221       1.1  joerg 			return(0);
    222       1.1  joerg 		break;
    223       1.1  joerg 	default:
    224       1.1  joerg 		break;
    225       1.1  joerg 	}
    226       1.1  joerg 
    227       1.1  joerg 	return(1);
    228       1.1  joerg }
    229       1.1  joerg 
    230       1.1  joerg 
    231       1.1  joerg static struct man_node *
    232   1.1.1.5  joerg man_node_alloc(int line, int pos, enum man_type type, enum mant tok)
    233       1.1  joerg {
    234       1.1  joerg 	struct man_node *p;
    235       1.1  joerg 
    236   1.1.1.3  joerg 	p = mandoc_calloc(1, sizeof(struct man_node));
    237       1.1  joerg 	p->line = line;
    238       1.1  joerg 	p->pos = pos;
    239       1.1  joerg 	p->type = type;
    240       1.1  joerg 	p->tok = tok;
    241       1.1  joerg 	return(p);
    242       1.1  joerg }
    243       1.1  joerg 
    244       1.1  joerg 
    245       1.1  joerg int
    246   1.1.1.5  joerg man_elem_alloc(struct man *m, int line, int pos, enum mant tok)
    247       1.1  joerg {
    248       1.1  joerg 	struct man_node *p;
    249       1.1  joerg 
    250       1.1  joerg 	p = man_node_alloc(line, pos, MAN_ELEM, tok);
    251       1.1  joerg 	if ( ! man_node_append(m, p))
    252       1.1  joerg 		return(0);
    253       1.1  joerg 	m->next = MAN_NEXT_CHILD;
    254       1.1  joerg 	return(1);
    255       1.1  joerg }
    256       1.1  joerg 
    257       1.1  joerg 
    258       1.1  joerg int
    259   1.1.1.5  joerg man_head_alloc(struct man *m, int line, int pos, enum mant tok)
    260       1.1  joerg {
    261       1.1  joerg 	struct man_node *p;
    262       1.1  joerg 
    263       1.1  joerg 	p = man_node_alloc(line, pos, MAN_HEAD, tok);
    264       1.1  joerg 	if ( ! man_node_append(m, p))
    265       1.1  joerg 		return(0);
    266       1.1  joerg 	m->next = MAN_NEXT_CHILD;
    267       1.1  joerg 	return(1);
    268       1.1  joerg }
    269       1.1  joerg 
    270       1.1  joerg 
    271       1.1  joerg int
    272   1.1.1.5  joerg man_body_alloc(struct man *m, int line, int pos, enum mant tok)
    273       1.1  joerg {
    274       1.1  joerg 	struct man_node *p;
    275       1.1  joerg 
    276       1.1  joerg 	p = man_node_alloc(line, pos, MAN_BODY, tok);
    277       1.1  joerg 	if ( ! man_node_append(m, p))
    278       1.1  joerg 		return(0);
    279       1.1  joerg 	m->next = MAN_NEXT_CHILD;
    280       1.1  joerg 	return(1);
    281       1.1  joerg }
    282       1.1  joerg 
    283       1.1  joerg 
    284       1.1  joerg int
    285   1.1.1.5  joerg man_block_alloc(struct man *m, int line, int pos, enum mant tok)
    286       1.1  joerg {
    287       1.1  joerg 	struct man_node *p;
    288       1.1  joerg 
    289       1.1  joerg 	p = man_node_alloc(line, pos, MAN_BLOCK, tok);
    290       1.1  joerg 	if ( ! man_node_append(m, p))
    291       1.1  joerg 		return(0);
    292       1.1  joerg 	m->next = MAN_NEXT_CHILD;
    293       1.1  joerg 	return(1);
    294       1.1  joerg }
    295       1.1  joerg 
    296  1.1.1.10  joerg static int
    297  1.1.1.10  joerg man_span_alloc(struct man *m, const struct tbl_span *span)
    298  1.1.1.10  joerg {
    299  1.1.1.10  joerg 	struct man_node	*n;
    300  1.1.1.10  joerg 
    301  1.1.1.10  joerg 	/* FIXME: grab from span */
    302  1.1.1.10  joerg 	n = man_node_alloc(0, 0, MAN_TBL, MAN_MAX);
    303  1.1.1.10  joerg 	n->span = span;
    304  1.1.1.10  joerg 
    305  1.1.1.10  joerg 	if ( ! man_node_append(m, n))
    306  1.1.1.10  joerg 		return(0);
    307  1.1.1.10  joerg 
    308  1.1.1.10  joerg 	m->next = MAN_NEXT_SIBLING;
    309  1.1.1.10  joerg 	return(1);
    310  1.1.1.10  joerg }
    311       1.1  joerg 
    312   1.1.1.6  joerg int
    313   1.1.1.6  joerg man_word_alloc(struct man *m, int line, int pos, const char *word)
    314       1.1  joerg {
    315       1.1  joerg 	struct man_node	*n;
    316   1.1.1.6  joerg 	size_t		 sv, len;
    317   1.1.1.6  joerg 
    318   1.1.1.6  joerg 	len = strlen(word);
    319       1.1  joerg 
    320   1.1.1.5  joerg 	n = man_node_alloc(line, pos, MAN_TEXT, MAN_MAX);
    321   1.1.1.3  joerg 	n->string = mandoc_malloc(len + 1);
    322   1.1.1.6  joerg 	sv = strlcpy(n->string, word, len + 1);
    323       1.1  joerg 
    324       1.1  joerg 	/* Prohibit truncation. */
    325       1.1  joerg 	assert(sv < len + 1);
    326       1.1  joerg 
    327       1.1  joerg 	if ( ! man_node_append(m, n))
    328       1.1  joerg 		return(0);
    329   1.1.1.6  joerg 
    330       1.1  joerg 	m->next = MAN_NEXT_SIBLING;
    331       1.1  joerg 	return(1);
    332       1.1  joerg }
    333       1.1  joerg 
    334       1.1  joerg 
    335   1.1.1.5  joerg /*
    336   1.1.1.5  joerg  * Free all of the resources held by a node.  This does NOT unlink a
    337   1.1.1.5  joerg  * node from its context; for that, see man_node_unlink().
    338   1.1.1.5  joerg  */
    339   1.1.1.5  joerg static void
    340       1.1  joerg man_node_free(struct man_node *p)
    341       1.1  joerg {
    342       1.1  joerg 
    343       1.1  joerg 	if (p->string)
    344       1.1  joerg 		free(p->string);
    345       1.1  joerg 	free(p);
    346       1.1  joerg }
    347       1.1  joerg 
    348       1.1  joerg 
    349       1.1  joerg void
    350   1.1.1.5  joerg man_node_delete(struct man *m, struct man_node *p)
    351       1.1  joerg {
    352       1.1  joerg 
    353   1.1.1.5  joerg 	while (p->child)
    354   1.1.1.5  joerg 		man_node_delete(m, p->child);
    355   1.1.1.5  joerg 
    356   1.1.1.5  joerg 	man_node_unlink(m, p);
    357       1.1  joerg 	man_node_free(p);
    358       1.1  joerg }
    359       1.1  joerg 
    360       1.1  joerg 
    361  1.1.1.10  joerg int
    362  1.1.1.10  joerg man_addspan(struct man *m, const struct tbl_span *sp)
    363  1.1.1.10  joerg {
    364  1.1.1.10  joerg 
    365  1.1.1.10  joerg 	assert( ! (MAN_HALT & m->flags));
    366  1.1.1.10  joerg 	if ( ! man_span_alloc(m, sp))
    367  1.1.1.10  joerg 		return(0);
    368  1.1.1.10  joerg 	return(man_descope(m, 0, 0));
    369  1.1.1.10  joerg }
    370  1.1.1.10  joerg 
    371  1.1.1.10  joerg static int
    372  1.1.1.10  joerg man_descope(struct man *m, int line, int offs)
    373  1.1.1.10  joerg {
    374  1.1.1.10  joerg 	/*
    375  1.1.1.10  joerg 	 * Co-ordinate what happens with having a next-line scope open:
    376  1.1.1.10  joerg 	 * first close out the element scope (if applicable), then close
    377  1.1.1.10  joerg 	 * out the block scope (also if applicable).
    378  1.1.1.10  joerg 	 */
    379  1.1.1.10  joerg 
    380  1.1.1.10  joerg 	if (MAN_ELINE & m->flags) {
    381  1.1.1.10  joerg 		m->flags &= ~MAN_ELINE;
    382  1.1.1.10  joerg 		if ( ! man_unscope(m, m->last->parent, MANDOCERR_MAX))
    383  1.1.1.10  joerg 			return(0);
    384  1.1.1.10  joerg 	}
    385  1.1.1.10  joerg 
    386  1.1.1.10  joerg 	if ( ! (MAN_BLINE & m->flags))
    387  1.1.1.10  joerg 		return(1);
    388  1.1.1.10  joerg 	m->flags &= ~MAN_BLINE;
    389  1.1.1.10  joerg 
    390  1.1.1.10  joerg 	if ( ! man_unscope(m, m->last->parent, MANDOCERR_MAX))
    391  1.1.1.10  joerg 		return(0);
    392  1.1.1.10  joerg 	return(man_body_alloc(m, line, offs, m->last->tok));
    393  1.1.1.10  joerg }
    394  1.1.1.10  joerg 
    395  1.1.1.10  joerg 
    396       1.1  joerg static int
    397   1.1.1.6  joerg man_ptext(struct man *m, int line, char *buf, int offs)
    398       1.1  joerg {
    399   1.1.1.6  joerg 	int		 i;
    400   1.1.1.6  joerg 
    401   1.1.1.6  joerg 	/* Ignore bogus comments. */
    402   1.1.1.6  joerg 
    403   1.1.1.6  joerg 	if ('\\' == buf[offs] &&
    404   1.1.1.6  joerg 			'.' == buf[offs + 1] &&
    405  1.1.1.10  joerg 			'"' == buf[offs + 2]) {
    406  1.1.1.10  joerg 		man_pmsg(m, line, offs, MANDOCERR_BADCOMMENT);
    407  1.1.1.10  joerg 		return(1);
    408  1.1.1.10  joerg 	}
    409       1.1  joerg 
    410       1.1  joerg 	/* Literal free-form text whitespace is preserved. */
    411       1.1  joerg 
    412       1.1  joerg 	if (MAN_LITERAL & m->flags) {
    413   1.1.1.6  joerg 		if ( ! man_word_alloc(m, line, offs, buf + offs))
    414       1.1  joerg 			return(0);
    415  1.1.1.10  joerg 		return(man_descope(m, line, offs));
    416       1.1  joerg 	}
    417       1.1  joerg 
    418   1.1.1.6  joerg 	/* Pump blank lines directly into the backend. */
    419       1.1  joerg 
    420   1.1.1.6  joerg 	for (i = offs; ' ' == buf[i]; i++)
    421       1.1  joerg 		/* Skip leading whitespace. */ ;
    422   1.1.1.4  joerg 
    423   1.1.1.4  joerg 	if ('\0' == buf[i]) {
    424   1.1.1.6  joerg 		/* Allocate a blank entry. */
    425   1.1.1.6  joerg 		if ( ! man_word_alloc(m, line, offs, ""))
    426       1.1  joerg 			return(0);
    427  1.1.1.10  joerg 		return(man_descope(m, line, offs));
    428       1.1  joerg 	}
    429       1.1  joerg 
    430   1.1.1.6  joerg 	/*
    431   1.1.1.6  joerg 	 * Warn if the last un-escaped character is whitespace. Then
    432   1.1.1.6  joerg 	 * strip away the remaining spaces (tabs stay!).
    433   1.1.1.6  joerg 	 */
    434       1.1  joerg 
    435   1.1.1.6  joerg 	i = (int)strlen(buf);
    436   1.1.1.6  joerg 	assert(i);
    437   1.1.1.4  joerg 
    438   1.1.1.6  joerg 	if (' ' == buf[i - 1] || '\t' == buf[i - 1]) {
    439   1.1.1.6  joerg 		if (i > 1 && '\\' != buf[i - 2])
    440  1.1.1.10  joerg 			man_pmsg(m, line, i - 1, MANDOCERR_EOLNSPACE);
    441   1.1.1.4  joerg 
    442   1.1.1.6  joerg 		for (--i; i && ' ' == buf[i]; i--)
    443   1.1.1.6  joerg 			/* Spin back to non-space. */ ;
    444   1.1.1.4  joerg 
    445   1.1.1.6  joerg 		/* Jump ahead of escaped whitespace. */
    446   1.1.1.6  joerg 		i += '\\' == buf[i] ? 2 : 1;
    447   1.1.1.4  joerg 
    448   1.1.1.6  joerg 		buf[i] = '\0';
    449       1.1  joerg 	}
    450       1.1  joerg 
    451   1.1.1.6  joerg 	if ( ! man_word_alloc(m, line, offs, buf + offs))
    452       1.1  joerg 		return(0);
    453       1.1  joerg 
    454   1.1.1.6  joerg 	/*
    455   1.1.1.6  joerg 	 * End-of-sentence check.  If the last character is an unescaped
    456   1.1.1.6  joerg 	 * EOS character, then flag the node as being the end of a
    457   1.1.1.6  joerg 	 * sentence.  The front-end will know how to interpret this.
    458   1.1.1.6  joerg 	 */
    459   1.1.1.6  joerg 
    460   1.1.1.6  joerg 	assert(i);
    461   1.1.1.9  joerg 	if (mandoc_eos(buf, (size_t)i, 0))
    462   1.1.1.6  joerg 		m->last->flags |= MAN_EOS;
    463       1.1  joerg 
    464  1.1.1.10  joerg 	return(man_descope(m, line, offs));
    465       1.1  joerg }
    466       1.1  joerg 
    467       1.1  joerg 
    468   1.1.1.2  joerg static int
    469   1.1.1.6  joerg man_pmacro(struct man *m, int ln, char *buf, int offs)
    470       1.1  joerg {
    471   1.1.1.5  joerg 	int		 i, j, ppos;
    472   1.1.1.5  joerg 	enum mant	 tok;
    473       1.1  joerg 	char		 mac[5];
    474       1.1  joerg 	struct man_node	*n;
    475       1.1  joerg 
    476       1.1  joerg 	/* Comments and empties are quickly ignored. */
    477       1.1  joerg 
    478   1.1.1.6  joerg 	offs++;
    479   1.1.1.6  joerg 
    480   1.1.1.6  joerg 	if ('\0' == buf[offs])
    481   1.1.1.3  joerg 		return(1);
    482       1.1  joerg 
    483   1.1.1.6  joerg 	i = offs;
    484       1.1  joerg 
    485   1.1.1.5  joerg 	/*
    486   1.1.1.5  joerg 	 * Skip whitespace between the control character and initial
    487   1.1.1.5  joerg 	 * text.  "Whitespace" is both spaces and tabs.
    488   1.1.1.5  joerg 	 */
    489   1.1.1.6  joerg 
    490   1.1.1.5  joerg 	if (' ' == buf[i] || '\t' == buf[i]) {
    491       1.1  joerg 		i++;
    492   1.1.1.5  joerg 		while (buf[i] && (' ' == buf[i] || '\t' == buf[i]))
    493       1.1  joerg 			i++;
    494   1.1.1.4  joerg 		if ('\0' == buf[i])
    495       1.1  joerg 			goto out;
    496       1.1  joerg 	}
    497       1.1  joerg 
    498       1.1  joerg 	ppos = i;
    499       1.1  joerg 
    500  1.1.1.10  joerg 	/*
    501  1.1.1.10  joerg 	 * Copy the first word into a nil-terminated buffer.
    502  1.1.1.10  joerg 	 * Stop copying when a tab, space, or eoln is encountered.
    503  1.1.1.10  joerg 	 */
    504       1.1  joerg 
    505  1.1.1.10  joerg 	j = 0;
    506  1.1.1.10  joerg 	while (j < 4 && '\0' != buf[i] && ' ' != buf[i] && '\t' != buf[i])
    507  1.1.1.10  joerg 		mac[j++] = buf[i++];
    508   1.1.1.3  joerg 	mac[j] = '\0';
    509       1.1  joerg 
    510  1.1.1.10  joerg 	tok = (j > 0 && j < 4) ? man_hash_find(mac) : MAN_MAX;
    511  1.1.1.10  joerg 	if (MAN_MAX == tok) {
    512  1.1.1.10  joerg 		man_vmsg(m, MANDOCERR_MACRO, ln, ppos, "%s", buf + ppos - 1);
    513       1.1  joerg 		return(1);
    514       1.1  joerg 	}
    515       1.1  joerg 
    516       1.1  joerg 	/* The macro is sane.  Jump to the next word. */
    517       1.1  joerg 
    518       1.1  joerg 	while (buf[i] && ' ' == buf[i])
    519       1.1  joerg 		i++;
    520       1.1  joerg 
    521   1.1.1.6  joerg 	/*
    522   1.1.1.6  joerg 	 * Trailing whitespace.  Note that tabs are allowed to be passed
    523   1.1.1.6  joerg 	 * into the parser as "text", so we only warn about spaces here.
    524   1.1.1.6  joerg 	 */
    525   1.1.1.4  joerg 
    526   1.1.1.4  joerg 	if ('\0' == buf[i] && ' ' == buf[i - 1])
    527  1.1.1.10  joerg 		man_pmsg(m, ln, i - 1, MANDOCERR_EOLNSPACE);
    528   1.1.1.4  joerg 
    529   1.1.1.5  joerg 	/*
    530  1.1.1.10  joerg 	 * Remove prior ELINE macro, as it's being clobbered by a new
    531   1.1.1.5  joerg 	 * macro.  Note that NSCOPED macros do not close out ELINE
    532   1.1.1.5  joerg 	 * macros---they don't print text---so we let those slip by.
    533   1.1.1.5  joerg 	 */
    534   1.1.1.5  joerg 
    535   1.1.1.5  joerg 	if ( ! (MAN_NSCOPED & man_macros[tok].flags) &&
    536   1.1.1.5  joerg 			m->flags & MAN_ELINE) {
    537       1.1  joerg 		n = m->last;
    538  1.1.1.10  joerg 		assert(MAN_TEXT != n->type);
    539   1.1.1.5  joerg 
    540  1.1.1.10  joerg 		/* Remove repeated NSCOPED macros causing ELINE. */
    541   1.1.1.5  joerg 
    542  1.1.1.10  joerg 		if (MAN_NSCOPED & man_macros[n->tok].flags)
    543  1.1.1.10  joerg 			n = n->parent;
    544  1.1.1.10  joerg 
    545  1.1.1.10  joerg 		man_vmsg(m, MANDOCERR_LINESCOPE, n->line, n->pos,
    546  1.1.1.10  joerg 				"%s", man_macronames[n->tok]);
    547       1.1  joerg 
    548   1.1.1.5  joerg 		man_node_delete(m, n);
    549       1.1  joerg 		m->flags &= ~MAN_ELINE;
    550       1.1  joerg 	}
    551       1.1  joerg 
    552   1.1.1.5  joerg 	/*
    553   1.1.1.5  joerg 	 * Save the fact that we're in the next-line for a block.  In
    554   1.1.1.5  joerg 	 * this way, embedded roff instructions can "remember" state
    555   1.1.1.5  joerg 	 * when they exit.
    556   1.1.1.5  joerg 	 */
    557       1.1  joerg 
    558   1.1.1.5  joerg 	if (MAN_BLINE & m->flags)
    559   1.1.1.5  joerg 		m->flags |= MAN_BPLINE;
    560       1.1  joerg 
    561   1.1.1.5  joerg 	/* Call to handler... */
    562   1.1.1.5  joerg 
    563   1.1.1.5  joerg 	assert(man_macros[tok].fp);
    564   1.1.1.5  joerg 	if ( ! (*man_macros[tok].fp)(m, tok, ln, ppos, &i, buf))
    565       1.1  joerg 		goto err;
    566       1.1  joerg 
    567       1.1  joerg out:
    568   1.1.1.5  joerg 	/*
    569   1.1.1.5  joerg 	 * We weren't in a block-line scope when entering the
    570   1.1.1.5  joerg 	 * above-parsed macro, so return.
    571   1.1.1.5  joerg 	 */
    572   1.1.1.5  joerg 
    573   1.1.1.5  joerg 	if ( ! (MAN_BPLINE & m->flags)) {
    574   1.1.1.5  joerg 		m->flags &= ~MAN_ILINE;
    575       1.1  joerg 		return(1);
    576   1.1.1.5  joerg 	}
    577   1.1.1.5  joerg 	m->flags &= ~MAN_BPLINE;
    578   1.1.1.5  joerg 
    579   1.1.1.5  joerg 	/*
    580   1.1.1.5  joerg 	 * If we're in a block scope, then allow this macro to slip by
    581   1.1.1.5  joerg 	 * without closing scope around it.
    582   1.1.1.5  joerg 	 */
    583   1.1.1.5  joerg 
    584   1.1.1.5  joerg 	if (MAN_ILINE & m->flags) {
    585   1.1.1.5  joerg 		m->flags &= ~MAN_ILINE;
    586   1.1.1.5  joerg 		return(1);
    587   1.1.1.5  joerg 	}
    588       1.1  joerg 
    589       1.1  joerg 	/*
    590       1.1  joerg 	 * If we've opened a new next-line element scope, then return
    591       1.1  joerg 	 * now, as the next line will close out the block scope.
    592       1.1  joerg 	 */
    593       1.1  joerg 
    594       1.1  joerg 	if (MAN_ELINE & m->flags)
    595       1.1  joerg 		return(1);
    596       1.1  joerg 
    597       1.1  joerg 	/* Close out the block scope opened in the prior line.  */
    598       1.1  joerg 
    599       1.1  joerg 	assert(MAN_BLINE & m->flags);
    600       1.1  joerg 	m->flags &= ~MAN_BLINE;
    601       1.1  joerg 
    602   1.1.1.6  joerg 	if ( ! man_unscope(m, m->last->parent, MANDOCERR_MAX))
    603       1.1  joerg 		return(0);
    604   1.1.1.6  joerg 	return(man_body_alloc(m, ln, offs, m->last->tok));
    605       1.1  joerg 
    606       1.1  joerg err:	/* Error out. */
    607       1.1  joerg 
    608       1.1  joerg 	m->flags |= MAN_HALT;
    609       1.1  joerg 	return(0);
    610       1.1  joerg }
    611       1.1  joerg 
    612       1.1  joerg 
    613       1.1  joerg int
    614   1.1.1.6  joerg man_vmsg(struct man *man, enum mandocerr t,
    615   1.1.1.6  joerg 		int ln, int pos, const char *fmt, ...)
    616       1.1  joerg {
    617       1.1  joerg 	char		 buf[256];
    618       1.1  joerg 	va_list		 ap;
    619       1.1  joerg 
    620       1.1  joerg 	va_start(ap, fmt);
    621   1.1.1.6  joerg 	vsnprintf(buf, sizeof(buf) - 1, fmt, ap);
    622       1.1  joerg 	va_end(ap);
    623   1.1.1.6  joerg 	return((*man->msg)(t, man->data, ln, pos, buf));
    624       1.1  joerg }
    625   1.1.1.5  joerg 
    626   1.1.1.5  joerg 
    627   1.1.1.5  joerg /*
    628   1.1.1.5  joerg  * Unlink a node from its context.  If "m" is provided, the last parse
    629   1.1.1.5  joerg  * point will also be adjusted accordingly.
    630   1.1.1.5  joerg  */
    631   1.1.1.5  joerg static void
    632   1.1.1.5  joerg man_node_unlink(struct man *m, struct man_node *n)
    633   1.1.1.5  joerg {
    634   1.1.1.5  joerg 
    635   1.1.1.5  joerg 	/* Adjust siblings. */
    636   1.1.1.5  joerg 
    637   1.1.1.5  joerg 	if (n->prev)
    638   1.1.1.5  joerg 		n->prev->next = n->next;
    639   1.1.1.5  joerg 	if (n->next)
    640   1.1.1.5  joerg 		n->next->prev = n->prev;
    641   1.1.1.5  joerg 
    642   1.1.1.5  joerg 	/* Adjust parent. */
    643   1.1.1.5  joerg 
    644   1.1.1.5  joerg 	if (n->parent) {
    645   1.1.1.5  joerg 		n->parent->nchild--;
    646   1.1.1.5  joerg 		if (n->parent->child == n)
    647   1.1.1.5  joerg 			n->parent->child = n->prev ? n->prev : n->next;
    648   1.1.1.5  joerg 	}
    649   1.1.1.5  joerg 
    650   1.1.1.5  joerg 	/* Adjust parse point, if applicable. */
    651   1.1.1.5  joerg 
    652   1.1.1.5  joerg 	if (m && m->last == n) {
    653   1.1.1.5  joerg 		/*XXX: this can occur when bailing from validation. */
    654   1.1.1.5  joerg 		/*assert(NULL == n->next);*/
    655   1.1.1.5  joerg 		if (n->prev) {
    656   1.1.1.5  joerg 			m->last = n->prev;
    657   1.1.1.5  joerg 			m->next = MAN_NEXT_SIBLING;
    658   1.1.1.5  joerg 		} else {
    659   1.1.1.5  joerg 			m->last = n->parent;
    660   1.1.1.5  joerg 			m->next = MAN_NEXT_CHILD;
    661   1.1.1.5  joerg 		}
    662   1.1.1.5  joerg 	}
    663   1.1.1.5  joerg 
    664   1.1.1.5  joerg 	if (m && m->first == n)
    665   1.1.1.5  joerg 		m->first = NULL;
    666   1.1.1.5  joerg }
    667