示例#1
0
void
man_mdoc(void *arg, const struct mdoc *mdoc)
{
	const struct mdoc_meta *meta;
	struct mdoc_node *n;

	meta = mdoc_meta(mdoc);
	n = mdoc_node(mdoc)->child;

	printf(".TH \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"\n",
	    meta->title,
	    (meta->msec == NULL ? "" : meta->msec),
	    meta->date, meta->os, meta->vol);

	/* Disable hyphenation and if nroff, disable justification. */
	printf(".nh\n.if n .ad l");

	outflags = MMAN_nl | MMAN_Sm;
	if (0 == fontqueue.size) {
		fontqueue.size = 8;
		fontqueue.head = fontqueue.tail = mandoc_malloc(8);
		*fontqueue.tail = 'R';
	}
	while (n != NULL) {
		print_node(meta, n);
		n = n->next;
	}
	putchar('\n');
}
示例#2
0
struct mchars *
mchars_alloc(void)
{
	struct mchars	 *tab;
	struct ln	**htab;
	struct ln	 *pp;
	int		  i, hash;

	/*
	 * Constructs a very basic chaining hashtable.  The hash routine
	 * is simply the integral value of the first character.
	 * Subsequent entries are chained in the order they're processed.
	 */

	tab = mandoc_malloc(sizeof(struct mchars));
	htab = mandoc_calloc(PRINT_HI - PRINT_LO + 1, sizeof(struct ln **));

	for (i = 0; i < LINES_MAX; i++) {
		hash = (int)lines[i].code[0] - PRINT_LO;

		if (NULL == (pp = htab[hash])) {
			htab[hash] = &lines[i];
			continue;
		}

		for ( ; pp->next; pp = pp->next)
			/* Scan ahead. */ ;
		pp->next = &lines[i];
	}

	tab->htab = htab;
	return(tab);
}
示例#3
0
void
man_mdoc(void *arg, const struct roff_man *mdoc)
{
	struct roff_node *n;

	printf(".\\\" Automatically generated from an mdoc input file."
	    "  Do not edit.\n");
	for (n = mdoc->first->child; n != NULL; n = n->next) {
		if (n->type != ROFFT_COMMENT)
			break;
		printf(".\\\"%s\n", n->string);
	}

	printf(".TH \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"\n",
	    mdoc->meta.title,
	    (mdoc->meta.msec == NULL ? "" : mdoc->meta.msec),
	    mdoc->meta.date, mdoc->meta.os, mdoc->meta.vol);

	/* Disable hyphenation and if nroff, disable justification. */
	printf(".nh\n.if n .ad l");

	outflags = MMAN_nl | MMAN_Sm;
	if (0 == fontqueue.size) {
		fontqueue.size = 8;
		fontqueue.head = fontqueue.tail = mandoc_malloc(8);
		*fontqueue.tail = 'R';
	}
	for (; n != NULL; n = n->next)
		print_node(&mdoc->meta, n);
	putchar('\n');
}
示例#4
0
static char *
time2a(time_t t)
{
	struct tm	*tm;
	char		*buf, *p;
	size_t		 ssz;
	int		 isz;

	tm = localtime(&t);

	/*
	 * Reserve space:
	 * up to 9 characters for the month (September) + blank
	 * up to 2 characters for the day + comma + blank
	 * 4 characters for the year and a terminating '\0'
	 */
	p = buf = mandoc_malloc(10 + 4 + 4 + 1);

	if (0 == (ssz = strftime(p, 10 + 1, "%B ", tm)))
		goto fail;
	p += (int)ssz;

	if (-1 == (isz = snprintf(p, 4 + 1, "%d, ", tm->tm_mday)))
		goto fail;
	p += isz;

	if (0 == strftime(p, 4 + 1, "%Y", tm))
		goto fail;
	return(buf);

fail:
	free(buf);
	return(NULL);
}
示例#5
0
void
roff_setreg(struct roff *r, const char *name, int val, char sign)
{
	struct roffreg	*reg;

	/* Search for an existing register with the same name. */
	reg = r->regtab;

	while (reg && strcmp(name, reg->key.p))
		reg = reg->next;

	if (NULL == reg) {
		/* Create a new register. */
		reg = mandoc_malloc(sizeof(struct roffreg));
		reg->key.p = mandoc_strdup(name);
		reg->key.sz = strlen(name);
		reg->val = 0;
		reg->next = r->regtab;
		r->regtab = reg;
	}

	if ('+' == sign)
		reg->val += val;
	else if ('-' == sign)
		reg->val -= val;
	else
		reg->val = val;
}
示例#6
0
static int
post_lb(POST_ARGS)
{
	const char	*p;
	char		*buf;
	size_t		 sz;

	check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 1);

	assert(mdoc->last->child);
	assert(MDOC_TEXT == mdoc->last->child->type);

	p = mdoc_a2lib(mdoc->last->child->string);

	/* If lookup ok, replace with table value. */

	if (p) {
		free(mdoc->last->child->string);
		mdoc->last->child->string = mandoc_strdup(p);
		return(1);
	}

	/* If not, use "library ``xxxx''. */

	sz = strlen(mdoc->last->child->string) +
		2 + strlen("\\(lqlibrary\\(rq");
	buf = mandoc_malloc(sz);
	snprintf(buf, sz, "library \\(lq%s\\(rq", 
			mdoc->last->child->string);
	free(mdoc->last->child->string);
	mdoc->last->child->string = buf;
	return(1);
}
示例#7
0
char *
mandoc_strndup(const char *ptr, size_t sz)
{
	char	*p;

	p = mandoc_malloc(sz + 1);
	memcpy(p, ptr, sz);
	p[(int)sz] = '\0';
	return p;
}
示例#8
0
文件: roff.c 项目: StarchLinux/mandoc
/* ARGSUSED */
static enum rofferr
roff_userdef(ROFF_ARGS)
{
	const char	 *arg[9];
	char		 *cp, *n1, *n2;
	int		  i;

	/*
	 * Collect pointers to macro argument strings
	 * and null-terminate them.
	 */
	cp = *bufp + pos;
	for (i = 0; i < 9; i++)
		arg[i] = '\0' == *cp ? "" :
		    mandoc_getarg(r->parse, &cp, ln, &pos);

	/*
	 * Expand macro arguments.
	 */
	*szp = 0;
	n1 = cp = mandoc_strdup(r->current_string);
	while (NULL != (cp = strstr(cp, "\\$"))) {
		i = cp[2] - '1';
		if (0 > i || 8 < i) {
			/* Not an argument invocation. */
			cp += 2;
			continue;
		}

		*szp = strlen(n1) - 3 + strlen(arg[i]) + 1;
		n2 = mandoc_malloc(*szp);

		strlcpy(n2, n1, (size_t)(cp - n1 + 1));
		strlcat(n2, arg[i], *szp);
		strlcat(n2, cp + 3, *szp);

		cp = n2 + (cp - n1);
		free(n1);
		n1 = n2;
	}

	/*
	 * Replace the macro invocation
	 * by the expanded macro.
	 */
	free(*bufp);
	*bufp = n1;
	if (0 == *szp)
		*szp = strlen(*bufp) + 1;

	return(*szp > 1 && '\n' == (*bufp)[(int)*szp - 2] ?
	   ROFF_REPARSE : ROFF_APPEND);
}
示例#9
0
文件: html.c 项目: gokzy/netbsd-src
struct tag *
print_otag(struct html *h, enum htmltag tag,
		int sz, const struct htmlpair *p)
{
	int		 i;
	struct tag	*t;

	/* Push this tags onto the stack of open scopes. */

	if ( ! (HTML_NOSTACK & htmltags[tag].flags)) {
		t = mandoc_malloc(sizeof(struct tag));
		t->tag = tag;
		t->next = h->tags.head;
		h->tags.head = t;
	} else
		t = NULL;

	if ( ! (HTML_NOSPACE & h->flags))
		if ( ! (HTML_CLRLINE & htmltags[tag].flags)) {
			/* Manage keeps! */
			if ( ! (HTML_KEEP & h->flags)) {
				if (HTML_PREKEEP & h->flags)
					h->flags |= HTML_KEEP;
				putchar(' ');
			} else
				printf("&#160;");
		}

	if ( ! (h->flags & HTML_NONOSPACE))
		h->flags &= ~HTML_NOSPACE;
	else
		h->flags |= HTML_NOSPACE;

	/* Print out the tag name and attributes. */

	printf("<%s", htmltags[tag].name);
	for (i = 0; i < sz; i++)
		print_attr(h, htmlattrs[p[i].key], p[i].val);

	/* Accommodate for "well-formed" singleton escaping. */

	if (HTML_AUTOCLOSE & htmltags[tag].flags)
		putchar('/');

	putchar('>');

	h->flags |= HTML_NOSPACE;

	if ((HTML_AUTOCLOSE | HTML_CLRLINE) & htmltags[tag].flags)
		putchar('\n');

	return t;
}
示例#10
0
/*
 * Initialise the stored database key whose data buffer is shared
 * between uses (as the key must sometimes be constructed from an array
 * of 
 */
static void
dbt_init(DBT *key, size_t *ksz)
{

	if (0 == *ksz) {
		assert(0 == key->size);
		assert(NULL == key->data);
		key->data = mandoc_malloc(MANDOC_BUFSZ);
		*ksz = MANDOC_BUFSZ;
	}

	key->size = 0;
}
示例#11
0
static void
argv_single(struct mdoc *mdoc, int line,
		struct mdoc_argv *v, int *pos, char *buf)
{
	enum margserr	 ac;
	char		*p;

	ac = args(mdoc, line, pos, buf, ARGSFL_NONE, &p);
	if (ac == ARGS_EOLN)
		return;

	v->sz = 1;
	v->value = mandoc_malloc(sizeof(char *));
	v->value[0] = mandoc_strdup(p);
}
示例#12
0
int
mdoc_word_alloc(struct mdoc *m, int line, int pos, const char *p)
{
    struct mdoc_node *n;
    size_t		  sv, len;

    len = strlen(p);

    n = node_alloc(m, line, pos, MDOC_MAX, MDOC_TEXT);
    n->string = mandoc_malloc(len + 1);
    sv = strlcpy(n->string, p, len + 1);

    /* Prohibit truncation. */
    assert(sv < len + 1);

    if ( ! node_append(m, n))
        return(0);

    m->next = MDOC_NEXT_SIBLING;
    return(1);
}
示例#13
0
static int
argv_opt_single(struct mdoc *m, int line, 
		struct mdoc_argv *v, int *pos, char *buf)
{
	enum margserr	 ac;
	char		*p;

	if ('-' == buf[*pos])
		return(1);

	ac = args(m, line, pos, buf, ARGSFL_NONE, &p);
	if (ARGS_ERROR == ac)
		return(0);
	if (ARGS_EOLN == ac)
		return(1);

	v->sz = 1;
	v->value = mandoc_malloc(sizeof(char *));
	v->value[0] = mandoc_strdup(p);

	return(1);
}
示例#14
0
static int
argv_single(struct mdoc *m, int line, 
		struct mdoc_argv *v, int *pos, char *buf)
{
	int		 ppos;
	enum margserr	 ac;
	char		*p;

	ppos = *pos;

	ac = args(m, line, pos, buf, ARGSFL_NONE, &p);
	if (ARGS_EOLN == ac) {
		mdoc_pmsg(m, line, ppos, MANDOCERR_SYNTARGVCOUNT);
		return(0);
	} else if (ARGS_ERROR == ac)
		return(0);

	v->sz = 1;
	v->value = mandoc_malloc(sizeof(char *));
	v->value[0] = mandoc_strdup(p);

	return(1);
}
示例#15
0
void
man_mdoc(void *arg, const struct roff_man *mdoc)
{
	struct roff_node *n;

	printf(".TH \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"\n",
	    mdoc->meta.title,
	    (mdoc->meta.msec == NULL ? "" : mdoc->meta.msec),
	    mdoc->meta.date, mdoc->meta.os, mdoc->meta.vol);

	/* Disable hyphenation and if nroff, disable justification. */
	printf(".nh\n.if n .ad l");

	outflags = MMAN_nl | MMAN_Sm;
	if (0 == fontqueue.size) {
		fontqueue.size = 8;
		fontqueue.head = fontqueue.tail = mandoc_malloc(8);
		*fontqueue.tail = 'R';
	}
	for (n = mdoc->first->child; n != NULL; n = n->next)
		print_node(&mdoc->meta, n);
	putchar('\n');
}
示例#16
0
static int
post_at(POST_ARGS)
{
	const char	 *p, *q;
	char		 *buf;
	size_t		  sz;

	/*
	 * If we have a child, look it up in the standard keys.  If a
	 * key exist, use that instead of the child; if it doesn't,
	 * prefix "AT&T UNIX " to the existing data.
	 */
	
	if (NULL == mdoc->last->child)
		return(1);

	assert(MDOC_TEXT == mdoc->last->child->type);
	p = mdoc_a2att(mdoc->last->child->string);

	if (p) {
		free(mdoc->last->child->string);
		mdoc->last->child->string = mandoc_strdup(p);
	} else {
		mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADATT);
		p = "AT&T UNIX ";
		q = mdoc->last->child->string;
		sz = strlen(p) + strlen(q) + 1;
		buf = mandoc_malloc(sz);
		strlcpy(buf, p, sz);
		strlcat(buf, q, sz);
		free(mdoc->last->child->string);
		mdoc->last->child->string = buf;
	}

	return(1);
}
示例#17
0
/*
 * In the current line, expand user-defined strings ("\*")
 * and references to number registers ("\n").
 * Also check the syntax of other escape sequences.
 */
static enum rofferr
roff_res(struct roff *r, char **bufp, size_t *szp, int ln, int pos)
{
	char		 ubuf[12]; /* buffer to print the number */
	const char	*stesc;	/* start of an escape sequence ('\\') */
	const char	*stnam;	/* start of the name, after "[(*" */
	const char	*cp;	/* end of the name, e.g. before ']' */
	const char	*res;	/* the string to be substituted */
	char		*nbuf;	/* new buffer to copy bufp to */
	size_t		 nsz;	/* size of the new buffer */
	size_t		 maxl;  /* expected length of the escape name */
	size_t		 naml;	/* actual length of the escape name */
	int		 expand_count;	/* to avoid infinite loops */

	expand_count = 0;

again:
	cp = *bufp + pos;
	while (NULL != (cp = strchr(cp, '\\'))) {
		stesc = cp++;

		/*
		 * The second character must be an asterisk or an n.
		 * If it isn't, skip it anyway:  It is escaped,
		 * so it can't start another escape sequence.
		 */

		if ('\0' == *cp)
			return(ROFF_CONT);

		switch (*cp) {
		case ('*'):
			res = NULL;
			break;
		case ('n'):
			res = ubuf;
			break;
		default:
			if (ESCAPE_ERROR != mandoc_escape(&cp, NULL, NULL))
				continue;
			mandoc_msg
				(MANDOCERR_BADESCAPE, r->parse, 
				 ln, (int)(stesc - *bufp), NULL);
			return(ROFF_CONT);
		}

		cp++;

		/*
		 * The third character decides the length
		 * of the name of the string or register.
		 * Save a pointer to the name.
		 */

		switch (*cp) {
		case ('\0'):
			return(ROFF_CONT);
		case ('('):
			cp++;
			maxl = 2;
			break;
		case ('['):
			cp++;
			maxl = 0;
			break;
		default:
			maxl = 1;
			break;
		}
		stnam = cp;

		/* Advance to the end of the name. */

		for (naml = 0; 0 == maxl || naml < maxl; naml++, cp++) {
			if ('\0' == *cp) {
				mandoc_msg
					(MANDOCERR_BADESCAPE, 
					 r->parse, ln, 
					 (int)(stesc - *bufp), NULL);
				return(ROFF_CONT);
			}
			if (0 == maxl && ']' == *cp)
				break;
		}

		/*
		 * Retrieve the replacement string; if it is
		 * undefined, resume searching for escapes.
		 */

		if (NULL == res)
			res = roff_getstrn(r, stnam, naml);
		else
			snprintf(ubuf, sizeof(ubuf), "%d",
			    roff_getregn(r, stnam, naml));

		if (NULL == res) {
			mandoc_msg
				(MANDOCERR_BADESCAPE, r->parse, 
				 ln, (int)(stesc - *bufp), NULL);
			res = "";
		}

		/* Replace the escape sequence by the string. */

		pos = stesc - *bufp;

		nsz = *szp + strlen(res) + 1;
		nbuf = mandoc_malloc(nsz);

		strlcpy(nbuf, *bufp, (size_t)(stesc - *bufp + 1));
		strlcat(nbuf, res, nsz);
		strlcat(nbuf, cp + (maxl ? 0 : 1), nsz);

		free(*bufp);

		*bufp = nbuf;
		*szp = nsz;

		if (EXPAND_LIMIT >= ++expand_count)
			goto again;

		/* Just leave the string unexpanded. */
		mandoc_msg(MANDOCERR_ROFFLOOP, r->parse, ln, pos, NULL);
		return(ROFF_IGN);
	}
	return(ROFF_CONT);
}
struct tag *
print_otag(struct html *h, enum htmltag tag, 
		int sz, const struct htmlpair *p)
{
	int		 i;
	struct tag	*t;

	/* Push this tags onto the stack of open scopes. */

	if ( ! (HTML_NOSTACK & htmltags[tag].flags)) {
		t = mandoc_malloc(sizeof(struct tag));
		t->tag = tag;
		t->next = h->tags.head;
		h->tags.head = t;
	} else
		t = NULL;

	if ( ! (HTML_NOSPACE & h->flags))
		if ( ! (HTML_CLRLINE & htmltags[tag].flags)) {
			/* Manage keeps! */
			if ( ! (HTML_KEEP & h->flags)) {
				if (HTML_PREKEEP & h->flags)
					h->flags |= HTML_KEEP;
				putchar(' ');
			} else
				printf("&#160;");
		}

	if ( ! (h->flags & HTML_NONOSPACE))
		h->flags &= ~HTML_NOSPACE;
	else
		h->flags |= HTML_NOSPACE;

	/* Print out the tag name and attributes. */

	printf("<%s", htmltags[tag].name);
	for (i = 0; i < sz; i++)
		print_attr(h, htmlattrs[p[i].key], p[i].val);

	/* Add non-overridable attributes. */

	if (TAG_HTML == tag && HTML_XHTML_1_0_STRICT == h->type) {
		print_attr(h, "xmlns", "http://www.w3.org/1999/xhtml");
		print_attr(h, "xml:lang", "en");
		print_attr(h, "lang", "en");
	}

	/* Accommodate for XML "well-formed" singleton escaping. */

	if (HTML_AUTOCLOSE & htmltags[tag].flags)
		switch (h->type) {
		case (HTML_XHTML_1_0_STRICT):
			putchar('/');
			break;
		default:
			break;
		}

	putchar('>');

	h->flags |= HTML_NOSPACE;

	if ((HTML_AUTOCLOSE | HTML_CLRLINE) & htmltags[tag].flags)
		putchar('\n');

	return(t);
}
示例#19
0
文件: roff.c 项目: StarchLinux/mandoc
/*
 * Pre-filter each and every line for reserved words (one beginning with
 * `\*', e.g., `\*(ab').  These must be handled before the actual line
 * is processed. 
 * This also checks the syntax of regular escapes.
 */
static enum rofferr
roff_res(struct roff *r, char **bufp, size_t *szp, int ln, int pos)
{
	enum mandoc_esc	 esc;
	const char	*stesc;	/* start of an escape sequence ('\\') */
	const char	*stnam;	/* start of the name, after "[(*" */
	const char	*cp;	/* end of the name, e.g. before ']' */
	const char	*res;	/* the string to be substituted */
	int		 i, maxl, expand_count;
	size_t		 nsz;
	char		*n;

	expand_count = 0;

again:
	cp = *bufp + pos;
	while (NULL != (cp = strchr(cp, '\\'))) {
		stesc = cp++;

		/*
		 * The second character must be an asterisk.
		 * If it isn't, skip it anyway:  It is escaped,
		 * so it can't start another escape sequence.
		 */

		if ('\0' == *cp)
			return(ROFF_CONT);

		if ('*' != *cp) {
			res = cp;
			esc = mandoc_escape(&cp, NULL, NULL);
			if (ESCAPE_ERROR != esc)
				continue;
			cp = res;
			mandoc_msg
				(MANDOCERR_BADESCAPE, r->parse, 
				 ln, (int)(stesc - *bufp), NULL);
			return(ROFF_CONT);
		}

		cp++;

		/*
		 * The third character decides the length
		 * of the name of the string.
		 * Save a pointer to the name.
		 */

		switch (*cp) {
		case ('\0'):
			return(ROFF_CONT);
		case ('('):
			cp++;
			maxl = 2;
			break;
		case ('['):
			cp++;
			maxl = 0;
			break;
		default:
			maxl = 1;
			break;
		}
		stnam = cp;

		/* Advance to the end of the name. */

		for (i = 0; 0 == maxl || i < maxl; i++, cp++) {
			if ('\0' == *cp) {
				mandoc_msg
					(MANDOCERR_BADESCAPE, 
					 r->parse, ln, 
					 (int)(stesc - *bufp), NULL);
				return(ROFF_CONT);
			}
			if (0 == maxl && ']' == *cp)
				break;
		}

		/*
		 * Retrieve the replacement string; if it is
		 * undefined, resume searching for escapes.
		 */

		res = roff_getstrn(r, stnam, (size_t)i);

		if (NULL == res) {
			mandoc_msg
				(MANDOCERR_BADESCAPE, r->parse, 
				 ln, (int)(stesc - *bufp), NULL);
			res = "";
		}

		/* Replace the escape sequence by the string. */

		pos = stesc - *bufp;

		nsz = *szp + strlen(res) + 1;
		n = mandoc_malloc(nsz);

		strlcpy(n, *bufp, (size_t)(stesc - *bufp + 1));
		strlcat(n, res, nsz);
		strlcat(n, cp + (maxl ? 0 : 1), nsz);

		free(*bufp);

		*bufp = n;
		*szp = nsz;

		if (EXPAND_LIMIT >= ++expand_count)
			goto again;

		/* Just leave the string unexpanded. */
		mandoc_msg(MANDOCERR_ROFFLOOP, r->parse, ln, pos, NULL);
		return(ROFF_IGN);
	}
	return(ROFF_CONT);
}
示例#20
0
文件: roff.c 项目: StarchLinux/mandoc
static void
roff_setstrn(struct roffkv **r, const char *name, size_t namesz,
		const char *string, size_t stringsz, int multiline)
{
	struct roffkv	*n;
	char		*c;
	int		 i;
	size_t		 oldch, newch;

	/* Search for an existing string with the same name. */
	n = *r;

	while (n && strcmp(name, n->key.p))
		n = n->next;

	if (NULL == n) {
		/* Create a new string table entry. */
		n = mandoc_malloc(sizeof(struct roffkv));
		n->key.p = mandoc_strndup(name, namesz);
		n->key.sz = namesz;
		n->val.p = NULL;
		n->val.sz = 0;
		n->next = *r;
		*r = n;
	} else if (0 == multiline) {
		/* In multiline mode, append; else replace. */
		free(n->val.p);
		n->val.p = NULL;
		n->val.sz = 0;
	}

	if (NULL == string)
		return;

	/*
	 * One additional byte for the '\n' in multiline mode,
	 * and one for the terminating '\0'.
	 */
	newch = stringsz + (multiline ? 2u : 1u);

	if (NULL == n->val.p) {
		n->val.p = mandoc_malloc(newch);
		*n->val.p = '\0';
		oldch = 0;
	} else {
		oldch = n->val.sz;
		n->val.p = mandoc_realloc(n->val.p, oldch + newch);
	}

	/* Skip existing content in the destination buffer. */
	c = n->val.p + (int)oldch;

	/* Append new content to the destination buffer. */
	i = 0;
	while (i < (int)stringsz) {
		/*
		 * Rudimentary roff copy mode:
		 * Handle escaped backslashes.
		 */
		if ('\\' == string[i] && '\\' == string[i + 1])
			i++;
		*c++ = string[i++];
	}

	/* Append terminating bytes. */
	if (multiline)
		*c++ = '\n';

	*c = '\0';
	n->val.sz = (int)(c - n->val.p);
}
示例#21
0
static void *
hash_alloc(size_t sz, void *arg)
{

	return(mandoc_malloc(sz));
}
示例#22
0
文件: roff.c 项目: StarchLinux/mandoc
/* ARGSUSED */
static enum rofferr
roff_block(ROFF_ARGS)
{
	int		sv;
	size_t		sz;
	char		*name;

	name = NULL;

	if (ROFF_ig != tok) {
		if ('\0' == (*bufp)[pos]) {
			mandoc_msg(MANDOCERR_NOARGS, r->parse, ln, ppos, NULL);
			return(ROFF_IGN);
		}

		/*
		 * Re-write `de1', since we don't really care about
		 * groff's strange compatibility mode, into `de'.
		 */

		if (ROFF_de1 == tok)
			tok = ROFF_de;
		if (ROFF_de == tok)
			name = *bufp + pos;
		else
			mandoc_msg(MANDOCERR_REQUEST, r->parse, ln, ppos,
			    roffs[tok].name);

		while ((*bufp)[pos] && ! isspace((unsigned char)(*bufp)[pos]))
			pos++;

		while (isspace((unsigned char)(*bufp)[pos]))
			(*bufp)[pos++] = '\0';
	}

	roffnode_push(r, tok, name, ln, ppos);

	/*
	 * At the beginning of a `de' macro, clear the existing string
	 * with the same name, if there is one.  New content will be
	 * added from roff_block_text() in multiline mode.
	 */

	if (ROFF_de == tok)
		roff_setstr(r, name, "", 0);

	if ('\0' == (*bufp)[pos])
		return(ROFF_IGN);

	/* If present, process the custom end-of-line marker. */

	sv = pos;
	while ((*bufp)[pos] && ! isspace((unsigned char)(*bufp)[pos]))
		pos++;

	/*
	 * Note: groff does NOT like escape characters in the input.
	 * Instead of detecting this, we're just going to let it fly and
	 * to hell with it.
	 */

	assert(pos > sv);
	sz = (size_t)(pos - sv);

	if (1 == sz && '.' == (*bufp)[sv])
		return(ROFF_IGN);

	r->last->end = mandoc_malloc(sz + 1);

	memcpy(r->last->end, *bufp + sv, sz);
	r->last->end[(int)sz] = '\0';

	if ((*bufp)[pos])
		mandoc_msg(MANDOCERR_ARGSLOST, r->parse, ln, pos, NULL);

	return(ROFF_IGN);
}
示例#23
0
static void
getdata(struct tbl_node *tbl, struct tbl_span *dp,
		int ln, const char *p, int *pos)
{
	struct tbl_dat	*dat, *pdat;
	struct tbl_cell	*cp;
	struct tbl_span	*pdp;
	int		 sv;

	/*
	 * Determine the length of the string in the cell
	 * and advance the parse point to the end of the cell.
	 */

	sv = *pos;
	while (p[*pos] != '\0' && p[*pos] != tbl->opts.tab)
		(*pos)++;

	/* Advance to the next layout cell, skipping spanners. */

	cp = dp->last == NULL ? dp->layout->first : dp->last->layout->next;
	while (cp != NULL && cp->pos == TBL_CELL_SPAN)
		cp = cp->next;

	/*
	 * If the current layout row is out of cells, allocate
	 * a new cell if another row of the table has at least
	 * this number of columns, or discard the input if we
	 * are beyond the last column of the table as a whole.
	 */

	if (cp == NULL) {
		if (dp->layout->last->col + 1 < dp->opts->cols) {
			cp = mandoc_calloc(1, sizeof(*cp));
			cp->pos = TBL_CELL_LEFT;
			dp->layout->last->next = cp;
			cp->col = dp->layout->last->col + 1;
			dp->layout->last = cp;
		} else {
			mandoc_msg(MANDOCERR_TBLDATA_EXTRA,
			    ln, sv, "%s", p + sv);
			while (p[*pos] != '\0')
				(*pos)++;
			return;
		}
	}

	dat = mandoc_malloc(sizeof(*dat));
	dat->layout = cp;
	dat->next = NULL;
	dat->string = NULL;
	dat->hspans = 0;
	dat->vspans = 0;
	dat->block = 0;
	dat->pos = TBL_DATA_NONE;

	/*
	 * Increment the number of vertical spans in a data cell above,
	 * if this cell vertically extends one or more cells above.
	 * The iteration must be done over data rows,
	 * not over layout rows, because one layout row
	 * can be reused for more than one data row.
	 */

	if (cp->pos == TBL_CELL_DOWN ||
	    (*pos - sv == 2 && p[sv] == '\\' && p[sv + 1] == '^')) {
		pdp = dp;
		while ((pdp = pdp->prev) != NULL) {
			pdat = pdp->first;
			while (pdat != NULL &&
			    pdat->layout->col < dat->layout->col)
				pdat = pdat->next;
			if (pdat == NULL)
				break;
			if (pdat->layout->pos != TBL_CELL_DOWN &&
			    strcmp(pdat->string, "\\^") != 0) {
				pdat->vspans++;
				break;
			}
		}
	}

	/*
	 * Count the number of horizontal spans to the right of this cell.
	 * This is purely a matter of the layout, independent of the data.
	 */

	for (cp = cp->next; cp != NULL; cp = cp->next)
		if (cp->pos == TBL_CELL_SPAN)
			dat->hspans++;
		else
			break;

	/* Append the new data cell to the data row. */

	if (dp->last == NULL)
		dp->first = dat;
	else
		dp->last->next = dat;
	dp->last = dat;

	/*
	 * Check for a continued-data scope opening.  This consists of a
	 * trailing `T{' at the end of the line.  Subsequent lines,
	 * until a standalone `T}', are included in our cell.
	 */

	if (*pos - sv == 2 && p[sv] == 'T' && p[sv + 1] == '{') {
		tbl->part = TBL_PART_CDATA;
		return;
	}

	dat->string = mandoc_strndup(p + sv, *pos - sv);

	if (p[*pos] != '\0')
		(*pos)++;

	if ( ! strcmp(dat->string, "_"))
		dat->pos = TBL_DATA_HORIZ;
	else if ( ! strcmp(dat->string, "="))
		dat->pos = TBL_DATA_DHORIZ;
	else if ( ! strcmp(dat->string, "\\_"))
		dat->pos = TBL_DATA_NHORIZ;
	else if ( ! strcmp(dat->string, "\\="))
		dat->pos = TBL_DATA_NDHORIZ;
	else
		dat->pos = TBL_DATA_DATA;

	if ((dat->layout->pos == TBL_CELL_HORIZ ||
	    dat->layout->pos == TBL_CELL_DHORIZ ||
	    dat->layout->pos == TBL_CELL_DOWN) &&
	    dat->pos == TBL_DATA_DATA && *dat->string != '\0')
		mandoc_msg(MANDOCERR_TBLDATA_SPAN,
		    ln, sv, "%s", dat->string);
}
示例#24
0
文件: mandocdb.c 项目: Hooman3/minix
int
main(int argc, char *argv[])
{
	struct mparse	*mp; /* parse sequence */
	struct manpaths	 dirs;
	struct mdb	 mdb;
	struct recs	 recs;
	enum op		 op; /* current operation */
	const char	*dir;
	int		 ch, i, flags;
	char		 dirbuf[MAXPATHLEN];
	DB		*hash; /* temporary keyword hashtable */
	BTREEINFO	 info; /* btree configuration */
	size_t		 sz1, sz2;
	struct buf	 buf, /* keyword buffer */
			 dbuf; /* description buffer */
	struct of	*of; /* list of files for processing */
	extern int	 optind;
	extern char	*optarg;

	progname = strrchr(argv[0], '/');
	if (progname == NULL)
		progname = argv[0];
	else
		++progname;

	memset(&dirs, 0, sizeof(struct manpaths));
	memset(&mdb, 0, sizeof(struct mdb));
	memset(&recs, 0, sizeof(struct recs));

	of = NULL;
	mp = NULL;
	hash = NULL;
	op = OP_DEFAULT;
	dir = NULL;

	while (-1 != (ch = getopt(argc, argv, "aC:d:tu:vW")))
		switch (ch) {
		case ('a'):
			use_all = 1;
			break;
		case ('C'):
			if (op) {
				fprintf(stderr,
				    "-C: conflicting options\n");
				goto usage;
			}
			dir = optarg;
			op = OP_CONFFILE;
			break;
		case ('d'):
			if (op) {
				fprintf(stderr,
				    "-d: conflicting options\n");
				goto usage;
			}
			dir = optarg;
			op = OP_UPDATE;
			break;
		case ('t'):
			dup2(STDOUT_FILENO, STDERR_FILENO);
			if (op) {
				fprintf(stderr,
				    "-t: conflicting options\n");
				goto usage;
			}
			op = OP_TEST;
			use_all = 1;
			warnings = 1;
			break;
		case ('u'):
			if (op) {
				fprintf(stderr,
				    "-u: conflicting options\n");
				goto usage;
			}
			dir = optarg;
			op = OP_DELETE;
			break;
		case ('v'):
			verb++;
			break;
		case ('W'):
			warnings = 1;
			break;
		default:
			goto usage;
		}

	argc -= optind;
	argv += optind;

	if (OP_CONFFILE == op && argc > 0) {
		fprintf(stderr, "-C: too many arguments\n");
		goto usage;
	}

	memset(&info, 0, sizeof(BTREEINFO));
	info.lorder = 4321;
	info.flags = R_DUP;

	mp = mparse_alloc(MPARSE_AUTO, MANDOCLEVEL_FATAL, NULL, NULL);

	memset(&buf, 0, sizeof(struct buf));
	memset(&dbuf, 0, sizeof(struct buf));

	buf.size = dbuf.size = MANDOC_BUFSZ;

	buf.cp = mandoc_malloc(buf.size);
	dbuf.cp = mandoc_malloc(dbuf.size);

	if (OP_TEST == op) {
		ofile_argbuild(argc, argv, &of, ".");
		if (NULL == of)
			goto out;
		index_merge(of, mp, &dbuf, &buf, 
				hash, &mdb, &recs, ".");
		goto out;
	}

	if (OP_UPDATE == op || OP_DELETE == op) {
		strlcat(mdb.dbn, dir, MAXPATHLEN);
		strlcat(mdb.dbn, "/", MAXPATHLEN);
		sz1 = strlcat(mdb.dbn, MANDOC_DB, MAXPATHLEN);

		strlcat(mdb.idxn, dir, MAXPATHLEN);
		strlcat(mdb.idxn, "/", MAXPATHLEN);
		sz2 = strlcat(mdb.idxn, MANDOC_IDX, MAXPATHLEN);

		if (sz1 >= MAXPATHLEN || sz2 >= MAXPATHLEN) {
			fprintf(stderr, "%s: path too long\n", dir);
			exit((int)MANDOCLEVEL_BADARG);
		}

		flags = O_CREAT | O_RDWR;
		mdb.db = dbopen(mdb.dbn, flags, 0644, DB_BTREE, &info);
		mdb.idx = dbopen(mdb.idxn, flags, 0644, DB_RECNO, NULL);

		if (NULL == mdb.db) {
			perror(mdb.dbn);
			exit((int)MANDOCLEVEL_SYSERR);
		} else if (NULL == mdb.idx) {
			perror(mdb.idxn);
			exit((int)MANDOCLEVEL_SYSERR);
		}

		ofile_argbuild(argc, argv, &of, dir);

		if (NULL == of)
			goto out;

		index_prune(of, &mdb, &recs, dir);

		/*
		 * Go to the root of the respective manual tree.
		 * This must work or no manuals may be found (they're
		 * indexed relative to the root).
		 */

		if (OP_UPDATE == op) {
			if (-1 == chdir(dir)) {
				perror(dir);
				exit((int)MANDOCLEVEL_SYSERR);
			}
			index_merge(of, mp, &dbuf, &buf, hash,
					&mdb, &recs, dir);
		}

		goto out;
	}

	/*
	 * Configure the directories we're going to scan.
	 * If we have command-line arguments, use them.
	 * If not, we use man(1)'s method (see mandocdb.8).
	 */

	if (argc > 0) {
		dirs.paths = mandoc_calloc(argc, sizeof(char *));
		dirs.sz = argc;
		for (i = 0; i < argc; i++) 
			dirs.paths[i] = mandoc_strdup(argv[i]);
	} else
		manpath_parse(&dirs, dir, NULL, NULL);

	for (i = 0; i < dirs.sz; i++) {
		/*
		 * Go to the root of the respective manual tree.
		 * This must work or no manuals may be found:
		 * They are indexed relative to the root.
		 */

		if (-1 == chdir(dirs.paths[i])) {
			perror(dirs.paths[i]);
			exit((int)MANDOCLEVEL_SYSERR);
		}

		strlcpy(mdb.dbn, MANDOC_DB, MAXPATHLEN);
		strlcpy(mdb.idxn, MANDOC_IDX, MAXPATHLEN);

		flags = O_CREAT | O_TRUNC | O_RDWR;
		mdb.db = dbopen(mdb.dbn, flags, 0644, DB_BTREE, &info);
		mdb.idx = dbopen(mdb.idxn, flags, 0644, DB_RECNO, NULL);

		if (NULL == mdb.db) {
			perror(mdb.dbn);
			exit((int)MANDOCLEVEL_SYSERR);
		} else if (NULL == mdb.idx) {
			perror(mdb.idxn);
			exit((int)MANDOCLEVEL_SYSERR);
		}

		/*
		 * Search for manuals and fill the new database.
		 */

		strlcpy(dirbuf, dirs.paths[i], MAXPATHLEN);
	       	ofile_dirbuild(".", "", "", 0, &of, dirbuf);

		if (NULL != of) {
			index_merge(of, mp, &dbuf, &buf, hash,
			     &mdb, &recs, dirs.paths[i]);
			ofile_free(of);
			of = NULL;
		}

		(*mdb.db->close)(mdb.db);
		(*mdb.idx->close)(mdb.idx);
		mdb.db = NULL;
		mdb.idx = NULL;
	}

out:
	if (mdb.db)
		(*mdb.db->close)(mdb.db);
	if (mdb.idx)
		(*mdb.idx->close)(mdb.idx);
	if (hash)
		(*hash->close)(hash);
	if (mp)
		mparse_free(mp);

	manpath_free(&dirs);
	ofile_free(of);
	free(buf.cp);
	free(dbuf.cp);
	free(recs.stack);

	return(MANDOCLEVEL_OK);

usage:
	fprintf(stderr,
		"usage: %s [-av] [-C file] | dir ... | -t file ...\n"
		"                        -d dir [file ...] | "
		"-u dir [file ...]\n",
		progname);

	return((int)MANDOCLEVEL_BADARG);
}
示例#25
0
文件: cgi.c 项目: mr-justin/freebsd
static void
pg_search(const struct req *req)
{
	struct mansearch	  search;
	struct manpaths		  paths;
	struct manpage		 *res;
	char			**argv;
	char			 *query, *rp, *wp;
	size_t			  ressz;
	int			  argc;

	/*
	 * Begin by chdir()ing into the root of the manpath.
	 * This way we can pick up the database files, which are
	 * relative to the manpath root.
	 */

	if (-1 == (chdir(req->q.manpath))) {
		fprintf(stderr, "chdir %s: %s\n",
		    req->q.manpath, strerror(errno));
		pg_error_internal();
		return;
	}

	search.arch = req->q.arch;
	search.sec = req->q.sec;
	search.outkey = "Nd";
	search.argmode = req->q.equal ? ARG_NAME : ARG_EXPR;
	search.firstmatch = 1;

	paths.sz = 1;
	paths.paths = mandoc_malloc(sizeof(char *));
	paths.paths[0] = mandoc_strdup(".");

	/*
	 * Break apart at spaces with backslash-escaping.
	 */

	argc = 0;
	argv = NULL;
	rp = query = mandoc_strdup(req->q.query);
	for (;;) {
		while (isspace((unsigned char)*rp))
			rp++;
		if (*rp == '\0')
			break;
		argv = mandoc_reallocarray(argv, argc + 1, sizeof(char *));
		argv[argc++] = wp = rp;
		for (;;) {
			if (isspace((unsigned char)*rp)) {
				*wp = '\0';
				rp++;
				break;
			}
			if (rp[0] == '\\' && rp[1] != '\0')
				rp++;
			if (wp != rp)
				*wp = *rp;
			if (*rp == '\0')
				break;
			wp++;
			rp++;
		}
	}

	if (0 == mansearch(&search, &paths, argc, argv, &res, &ressz))
		pg_noresult(req, "You entered an invalid query.");
	else if (0 == ressz)
		pg_noresult(req, "No results found.");
	else
		pg_searchres(req, res, ressz);

	free(query);
	mansearch_free(res, ressz);
	free(paths.paths[0]);
	free(paths.paths);
}
示例#26
0
static int
post_bl_block_tag(POST_ARGS)
{
	struct mdoc_node *n, *nn;
	size_t		  sz, ssz;
	int		  i;
	char		  buf[NUMSIZ];

	/*
	 * Calculate the -width for a `Bl -tag' list if it hasn't been
	 * provided.  Uses the first head macro.  NOTE AGAIN: this is
	 * ONLY if the -width argument has NOT been provided.  See
	 * post_bl_block_width() for converting the -width string.
	 */

	sz = 10;
	n = mdoc->last;

	for (nn = n->body->child; nn; nn = nn->next) {
		if (MDOC_It != nn->tok)
			continue;

		assert(MDOC_BLOCK == nn->type);
		nn = nn->head->child;

		if (nn == NULL)
			break;

		if (MDOC_TEXT == nn->type) {
			sz = strlen(nn->string) + 1;
			break;
		}

		if (0 != (ssz = mdoc_macro2len(nn->tok)))
			sz = ssz;

		break;
	} 

	/* Defaults to ten ens. */

	snprintf(buf, NUMSIZ, "%zun", sz);

	/*
	 * We have to dynamically add this to the macro's argument list.
	 * We're guaranteed that a MDOC_Width doesn't already exist.
	 */

	assert(n->args);
	i = (int)(n->args->argc)++;

	n->args->argv = mandoc_realloc(n->args->argv, 
			n->args->argc * sizeof(struct mdoc_argv));

	n->args->argv[i].arg = MDOC_Width;
	n->args->argv[i].line = n->line;
	n->args->argv[i].pos = n->pos;
	n->args->argv[i].sz = 1;
	n->args->argv[i].value = mandoc_malloc(sizeof(char *));
	n->args->argv[i].value[0] = mandoc_strdup(buf);

	/* Set our width! */
	n->norm->Bl.width = n->args->argv[i].value[0];
	return(1);
}
示例#27
0
static int
post_bl_head(POST_ARGS) 
{
	struct mdoc_node *np, *nn, *nnp;
	int		  i, j;

	if (LIST_column != mdoc->last->norm->Bl.type)
		/* FIXME: this should be ERROR class... */
		return(hwarn_eq0(mdoc));

	/*
	 * Convert old-style lists, where the column width specifiers
	 * trail as macro parameters, to the new-style ("normal-form")
	 * lists where they're argument values following -column.
	 */

	/* First, disallow both types and allow normal-form. */

	/* 
	 * TODO: technically, we can accept both and just merge the two
	 * lists, but I'll leave that for another day.
	 */

	if (mdoc->last->norm->Bl.ncols && mdoc->last->nchild) {
		mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_COLUMNS);
		return(0);
	} else if (NULL == mdoc->last->child)
		return(1);

	np = mdoc->last->parent;
	assert(np->args);

	for (j = 0; j < (int)np->args->argc; j++) 
		if (MDOC_Column == np->args->argv[j].arg)
			break;

	assert(j < (int)np->args->argc);
	assert(0 == np->args->argv[j].sz);

	/*
	 * Accomodate for new-style groff column syntax.  Shuffle the
	 * child nodes, all of which must be TEXT, as arguments for the
	 * column field.  Then, delete the head children.
	 */

	np->args->argv[j].sz = (size_t)mdoc->last->nchild;
	np->args->argv[j].value = mandoc_malloc
		((size_t)mdoc->last->nchild * sizeof(char *));

	mdoc->last->norm->Bl.ncols = np->args->argv[j].sz;
	mdoc->last->norm->Bl.cols = (const char **)np->args->argv[j].value;

	for (i = 0, nn = mdoc->last->child; nn; i++) {
		np->args->argv[j].value[i] = nn->string;
		nn->string = NULL;
		nnp = nn;
		nn = nn->next;
		mdoc_node_delete(NULL, nnp);
	}

	mdoc->last->nchild = 0;
	mdoc->last->child = NULL;

	return(1);
}
示例#28
0
文件: tbl_data.c 项目: UNGLinux/Obase
static int
data(struct tbl_node *tbl, struct tbl_span *dp, 
		int ln, const char *p, int *pos)
{
	struct tbl_dat	*dat;
	struct tbl_cell	*cp;
	int		 sv, spans;

	cp = NULL;
	if (dp->last && dp->last->layout)
		cp = dp->last->layout->next;
	else if (NULL == dp->last)
		cp = dp->layout->first;

	/* 
	 * Skip over spanners, since
	 * we want to match data with data layout cells in the header.
	 */

	while (cp && TBL_CELL_SPAN == cp->pos)
		cp = cp->next;

	/*
	 * Stop processing when we reach the end of the available layout
	 * cells.  This means that we have extra input.
	 */

	if (NULL == cp) {
		mandoc_msg(MANDOCERR_TBLEXTRADAT, 
				tbl->parse, ln, *pos, NULL);
		/* Skip to the end... */
		while (p[*pos])
			(*pos)++;
		return(1);
	}

	dat = mandoc_calloc(1, sizeof(struct tbl_dat));
	dat->layout = cp;
	dat->pos = TBL_DATA_NONE;

	assert(TBL_CELL_SPAN != cp->pos);

	for (spans = 0, cp = cp->next; cp; cp = cp->next)
		if (TBL_CELL_SPAN == cp->pos)
			spans++;
		else
			break;
	
	dat->spans = spans;

	if (dp->last) {
		dp->last->next = dat;
		dp->last = dat;
	} else
		dp->last = dp->first = dat;

	sv = *pos;
	while (p[*pos] && p[*pos] != tbl->opts.tab)
		(*pos)++;

	/*
	 * Check for a continued-data scope opening.  This consists of a
	 * trailing `T{' at the end of the line.  Subsequent lines,
	 * until a standalone `T}', are included in our cell.
	 */

	if (*pos - sv == 2 && 'T' == p[sv] && '{' == p[sv + 1]) {
		tbl->part = TBL_PART_CDATA;
		return(0);
	}

	assert(*pos - sv >= 0);

	dat->string = mandoc_malloc((size_t)(*pos - sv + 1));
	memcpy(dat->string, &p[sv], (size_t)(*pos - sv));
	dat->string[*pos - sv] = '\0';

	if (p[*pos])
		(*pos)++;

	if ( ! strcmp(dat->string, "_"))
		dat->pos = TBL_DATA_HORIZ;
	else if ( ! strcmp(dat->string, "="))
		dat->pos = TBL_DATA_DHORIZ;
	else if ( ! strcmp(dat->string, "\\_"))
		dat->pos = TBL_DATA_NHORIZ;
	else if ( ! strcmp(dat->string, "\\="))
		dat->pos = TBL_DATA_NDHORIZ;
	else
		dat->pos = TBL_DATA_DATA;

	if (TBL_CELL_HORIZ == dat->layout->pos ||
			TBL_CELL_DHORIZ == dat->layout->pos ||
			TBL_CELL_DOWN == dat->layout->pos)
		if (TBL_DATA_DATA == dat->pos && '\0' != *dat->string)
			mandoc_msg(MANDOCERR_TBLIGNDATA, 
					tbl->parse, ln, sv, NULL);

	return(1);
}
示例#29
0
static void
pg_search(const struct req *req, char *path)
{
	size_t		  tt, ressz;
	struct manpaths	  ps;
	int		  i, sz, rc;
	const char	 *ep, *start;
	struct res	*res;
	char		**cp;
	struct opts	  opt;
	struct expr	 *expr;

	if (req->q.manroot < 0 || 0 == req->psz) {
		resp_search(NULL, 0, (void *)req);
		return;
	}

	memset(&opt, 0, sizeof(struct opts));

	ep 	 = req->q.expr;
	opt.arch = req->q.arch;
	opt.cat  = req->q.sec;
	rc 	 = -1;
	sz 	 = 0;
	cp	 = NULL;
	ressz	 = 0;
	res	 = NULL;

	/*
	 * Begin by chdir()ing into the root of the manpath.
	 * This way we can pick up the database files, which are
	 * relative to the manpath root.
	 */

	assert(req->q.manroot < (int)req->psz);
	if (-1 == (chdir(req->p[req->q.manroot].path))) {
		perror(req->p[req->q.manroot].path);
		resp_search(NULL, 0, (void *)req);
		return;
	}

	memset(&ps, 0, sizeof(struct manpaths));
	manpath_manconf(&ps, "etc/catman.conf");

	/*
	 * Poor man's tokenisation: just break apart by spaces.
	 * Yes, this is half-ass.  But it works for now.
	 */

	while (ep && isspace((unsigned char)*ep))
		ep++;

	while (ep && '\0' != *ep) {
		cp = mandoc_realloc(cp, (sz + 1) * sizeof(char *));
		start = ep;
		while ('\0' != *ep && ! isspace((unsigned char)*ep))
			ep++;
		cp[sz] = mandoc_malloc((ep - start) + 1);
		memcpy(cp[sz], start, ep - start);
		cp[sz++][ep - start] = '\0';
		while (isspace((unsigned char)*ep))
			ep++;
	}

	/*
	 * Pump down into apropos backend.
	 * The resp_search() function is called with the results.
	 */

	expr = req->q.legacy ? 
		termcomp(sz, cp, &tt) : exprcomp(sz, cp, &tt);

	if (NULL != expr)
		rc = apropos_search
			(ps.sz, ps.paths, &opt, expr, tt, 
			 (void *)req, &ressz, &res, resp_search);

	/* ...unless errors occured. */

	if (0 == rc)
		resp_baddb();
	else if (-1 == rc)
		resp_search(NULL, 0, NULL);

	for (i = 0; i < sz; i++)
		free(cp[i]);

	free(cp);
	resfree(res, ressz);
	exprfree(expr);
	manpath_free(&ps);
}