mansearch.c revision 1.19
1/*	$Id: mansearch.c,v 1.19 2014/04/11 15:45:39 schwarze Exp $ */
2/*
3 * Copyright (c) 2012 Kristaps Dzonsons <kristaps@bsd.lv>
4 * Copyright (c) 2013, 2014 Ingo Schwarze <schwarze@openbsd.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18#include <sys/mman.h>
19#include <assert.h>
20#include <fcntl.h>
21#include <getopt.h>
22#include <limits.h>
23#include <regex.h>
24#include <stdio.h>
25#include <stdint.h>
26#include <stddef.h>
27#include <stdlib.h>
28#include <string.h>
29#include <unistd.h>
30
31#include <ohash.h>
32#include <sqlite3.h>
33
34#include "mandoc.h"
35#include "mandoc_aux.h"
36#include "manpath.h"
37#include "mansearch.h"
38
39extern int mansearch_keymax;
40extern const char *const mansearch_keynames[];
41
42#define	SQL_BIND_TEXT(_db, _s, _i, _v) \
43	do { if (SQLITE_OK != sqlite3_bind_text \
44		((_s), (_i)++, (_v), -1, SQLITE_STATIC)) \
45		fprintf(stderr, "%s\n", sqlite3_errmsg((_db))); \
46	} while (0)
47#define	SQL_BIND_INT64(_db, _s, _i, _v) \
48	do { if (SQLITE_OK != sqlite3_bind_int64 \
49		((_s), (_i)++, (_v))) \
50		fprintf(stderr, "%s\n", sqlite3_errmsg((_db))); \
51	} while (0)
52#define	SQL_BIND_BLOB(_db, _s, _i, _v) \
53	do { if (SQLITE_OK != sqlite3_bind_blob \
54		((_s), (_i)++, (&_v), sizeof(_v), SQLITE_STATIC)) \
55		fprintf(stderr, "%s\n", sqlite3_errmsg((_db))); \
56	} while (0)
57
58struct	expr {
59	uint64_t 	 bits;    /* type-mask */
60	const char	*substr;  /* to search for, if applicable */
61	regex_t		 regexp;  /* compiled regexp, if applicable */
62	int		 open;    /* opening parentheses before */
63	int		 and;	  /* logical AND before */
64	int		 close;   /* closing parentheses after */
65	struct expr	*next;    /* next in sequence */
66};
67
68struct	match {
69	uint64_t	 id; /* identifier in database */
70	char		*desc; /* manual page description */
71	int		 form; /* 0 == catpage */
72};
73
74static	void		 buildnames(struct manpage *, sqlite3 *,
75				sqlite3_stmt *, uint64_t,
76				const char *, int form);
77static	char		*buildoutput(sqlite3 *, sqlite3_stmt *,
78				 uint64_t, uint64_t);
79static	void		*hash_alloc(size_t, void *);
80static	void		 hash_free(void *, size_t, void *);
81static	void		*hash_halloc(size_t, void *);
82static	struct expr	*exprcomp(const struct mansearch *,
83				int, char *[]);
84static	void		 exprfree(struct expr *);
85static	struct expr	*exprspec(struct expr *, uint64_t,
86				 const char *, const char *);
87static	struct expr	*exprterm(const struct mansearch *, char *, int);
88static	void		 sql_append(char **sql, size_t *sz,
89				const char *newstr, int count);
90static	void		 sql_match(sqlite3_context *context,
91				int argc, sqlite3_value **argv);
92static	void		 sql_regexp(sqlite3_context *context,
93				int argc, sqlite3_value **argv);
94static	char		*sql_statement(const struct expr *);
95
96int
97mansearch_setup(int start)
98{
99	static void	*pagecache;
100	int		 c;
101
102#define	PC_PAGESIZE	1280
103#define	PC_NUMPAGES	256
104
105	if (start) {
106		if (NULL != pagecache) {
107			fprintf(stderr, "pagecache already enabled\n");
108			return((int)MANDOCLEVEL_BADARG);
109		}
110
111		pagecache = mmap(NULL, PC_PAGESIZE * PC_NUMPAGES,
112		    PROT_READ | PROT_WRITE, MAP_ANON, -1, 0);
113
114		if (MAP_FAILED == pagecache) {
115			perror("mmap");
116			pagecache = NULL;
117			return((int)MANDOCLEVEL_SYSERR);
118		}
119
120		c = sqlite3_config(SQLITE_CONFIG_PAGECACHE,
121		    pagecache, PC_PAGESIZE, PC_NUMPAGES);
122
123		if (SQLITE_OK == c)
124			return((int)MANDOCLEVEL_OK);
125
126		fprintf(stderr, "pagecache: %s\n", sqlite3_errstr(c));
127
128	} else if (NULL == pagecache) {
129		fprintf(stderr, "pagecache missing\n");
130		return((int)MANDOCLEVEL_BADARG);
131	}
132
133	if (-1 == munmap(pagecache, PC_PAGESIZE * PC_NUMPAGES)) {
134		perror("munmap");
135		pagecache = NULL;
136		return((int)MANDOCLEVEL_SYSERR);
137	}
138
139	pagecache = NULL;
140	return((int)MANDOCLEVEL_OK);
141}
142
143int
144mansearch(const struct mansearch *search,
145		const struct manpaths *paths,
146		int argc, char *argv[],
147		const char *outkey,
148		struct manpage **res, size_t *sz)
149{
150	int		 fd, rc, c, indexbit;
151	int64_t		 id;
152	uint64_t	 outbit, iterbit;
153	char		 buf[PATH_MAX];
154	char		*sql;
155	struct manpage	*mpage;
156	struct expr	*e, *ep;
157	sqlite3		*db;
158	sqlite3_stmt	*s, *s2;
159	struct match	*mp;
160	struct ohash_info info;
161	struct ohash	 htab;
162	unsigned int	 idx;
163	size_t		 i, j, cur, maxres;
164
165	memset(&info, 0, sizeof(struct ohash_info));
166
167	info.halloc = hash_halloc;
168	info.alloc = hash_alloc;
169	info.hfree = hash_free;
170	info.key_offset = offsetof(struct match, id);
171
172	*sz = cur = maxres = 0;
173	sql = NULL;
174	*res = NULL;
175	fd = -1;
176	e = NULL;
177	rc = 0;
178
179	if (0 == argc)
180		goto out;
181	if (NULL == (e = exprcomp(search, argc, argv)))
182		goto out;
183
184	outbit = 0;
185	if (NULL != outkey) {
186		for (indexbit = 0, iterbit = 1;
187		     indexbit < mansearch_keymax;
188		     indexbit++, iterbit <<= 1) {
189			if (0 == strcasecmp(outkey,
190			    mansearch_keynames[indexbit])) {
191				outbit = iterbit;
192				break;
193			}
194		}
195	}
196
197	/*
198	 * Save a descriptor to the current working directory.
199	 * Since pathnames in the "paths" variable might be relative,
200	 * and we'll be chdir()ing into them, we need to keep a handle
201	 * on our current directory from which to start the chdir().
202	 */
203
204	if (NULL == getcwd(buf, PATH_MAX)) {
205		perror(NULL);
206		goto out;
207	} else if (-1 == (fd = open(buf, O_RDONLY, 0))) {
208		perror(buf);
209		goto out;
210	}
211
212	sql = sql_statement(e);
213
214	/*
215	 * Loop over the directories (containing databases) for us to
216	 * search.
217	 * Don't let missing/bad databases/directories phase us.
218	 * In each, try to open the resident database and, if it opens,
219	 * scan it for our match expression.
220	 */
221
222	for (i = 0; i < paths->sz; i++) {
223		if (-1 == fchdir(fd)) {
224			perror(buf);
225			free(*res);
226			break;
227		} else if (-1 == chdir(paths->paths[i])) {
228			perror(paths->paths[i]);
229			continue;
230		}
231
232		c =  sqlite3_open_v2
233			(MANDOC_DB, &db,
234			 SQLITE_OPEN_READONLY, NULL);
235
236		if (SQLITE_OK != c) {
237			perror(MANDOC_DB);
238			sqlite3_close(db);
239			continue;
240		}
241
242		/*
243		 * Define the SQL functions for substring
244		 * and regular expression matching.
245		 */
246
247		c = sqlite3_create_function(db, "match", 2,
248		    SQLITE_ANY, NULL, sql_match, NULL, NULL);
249		assert(SQLITE_OK == c);
250		c = sqlite3_create_function(db, "regexp", 2,
251		    SQLITE_ANY, NULL, sql_regexp, NULL, NULL);
252		assert(SQLITE_OK == c);
253
254		j = 1;
255		c = sqlite3_prepare_v2(db, sql, -1, &s, NULL);
256		if (SQLITE_OK != c)
257			fprintf(stderr, "%s\n", sqlite3_errmsg(db));
258
259		for (ep = e; NULL != ep; ep = ep->next) {
260			if (NULL == ep->substr) {
261				SQL_BIND_BLOB(db, s, j, ep->regexp);
262			} else
263				SQL_BIND_TEXT(db, s, j, ep->substr);
264			if (0 == ((TYPE_Nd | TYPE_Nm) & ep->bits))
265				SQL_BIND_INT64(db, s, j, ep->bits);
266		}
267
268		memset(&htab, 0, sizeof(struct ohash));
269		ohash_init(&htab, 4, &info);
270
271		/*
272		 * Hash each entry on its [unique] document identifier.
273		 * This is a uint64_t.
274		 * Instead of using a hash function, simply convert the
275		 * uint64_t to a uint32_t, the hash value's type.
276		 * This gives good performance and preserves the
277		 * distribution of buckets in the table.
278		 */
279		while (SQLITE_ROW == (c = sqlite3_step(s))) {
280			id = sqlite3_column_int64(s, 2);
281			idx = ohash_lookup_memory
282				(&htab, (char *)&id,
283				 sizeof(uint64_t), (uint32_t)id);
284
285			if (NULL != ohash_find(&htab, idx))
286				continue;
287
288			mp = mandoc_calloc(1, sizeof(struct match));
289			mp->id = id;
290			mp->form = sqlite3_column_int(s, 1);
291			if (TYPE_Nd == outbit)
292				mp->desc = mandoc_strdup(
293				    sqlite3_column_text(s, 0));
294			ohash_insert(&htab, idx, mp);
295		}
296
297		if (SQLITE_DONE != c)
298			fprintf(stderr, "%s\n", sqlite3_errmsg(db));
299
300		sqlite3_finalize(s);
301
302		c = sqlite3_prepare_v2(db,
303		    "SELECT * FROM mlinks WHERE pageid=?"
304		    " ORDER BY sec, arch, name",
305		    -1, &s, NULL);
306		if (SQLITE_OK != c)
307			fprintf(stderr, "%s\n", sqlite3_errmsg(db));
308
309		c = sqlite3_prepare_v2(db,
310		    "SELECT * FROM keys WHERE pageid=? AND bits & ?",
311		    -1, &s2, NULL);
312		if (SQLITE_OK != c)
313			fprintf(stderr, "%s\n", sqlite3_errmsg(db));
314
315		for (mp = ohash_first(&htab, &idx);
316				NULL != mp;
317				mp = ohash_next(&htab, &idx)) {
318			if (cur + 1 > maxres) {
319				maxres += 1024;
320				*res = mandoc_realloc
321					(*res, maxres * sizeof(struct manpage));
322			}
323			mpage = *res + cur;
324			mpage->form = mp->form;
325			buildnames(mpage, db, s, mp->id,
326			    paths->paths[i], mp->form);
327			mpage->output = TYPE_Nd & outbit ?
328			    mp->desc : outbit ?
329			    buildoutput(db, s2, mp->id, outbit) : NULL;
330
331			free(mp);
332			cur++;
333		}
334
335		sqlite3_finalize(s);
336		sqlite3_finalize(s2);
337		sqlite3_close(db);
338		ohash_delete(&htab);
339	}
340	rc = 1;
341out:
342	exprfree(e);
343	if (-1 != fd)
344		close(fd);
345	free(sql);
346	*sz = cur;
347	return(rc);
348}
349
350static void
351buildnames(struct manpage *mpage, sqlite3 *db, sqlite3_stmt *s,
352		uint64_t id, const char *path, int form)
353{
354	char		*newnames, *prevsec, *prevarch;
355	const char	*oldnames, *sep1, *name, *sec, *sep2, *arch, *fsec;
356	size_t		 i;
357	int		 c;
358
359	mpage->file = NULL;
360	mpage->names = NULL;
361	prevsec = prevarch = NULL;
362	i = 1;
363	SQL_BIND_INT64(db, s, i, id);
364	while (SQLITE_ROW == (c = sqlite3_step(s))) {
365
366		/* Decide whether we already have some names. */
367
368		if (NULL == mpage->names) {
369			oldnames = "";
370			sep1 = "";
371		} else {
372			oldnames = mpage->names;
373			sep1 = ", ";
374		}
375
376		/* Fetch the next name. */
377
378		sec = sqlite3_column_text(s, 0);
379		arch = sqlite3_column_text(s, 1);
380		name = sqlite3_column_text(s, 2);
381
382		/* If the section changed, append the old one. */
383
384		if (NULL != prevsec &&
385		    (strcmp(sec, prevsec) ||
386		     strcmp(arch, prevarch))) {
387			sep2 = '\0' == *prevarch ? "" : "/";
388			mandoc_asprintf(&newnames, "%s(%s%s%s)",
389			    oldnames, prevsec, sep2, prevarch);
390			free(mpage->names);
391			oldnames = mpage->names = newnames;
392			free(prevsec);
393			free(prevarch);
394			prevsec = prevarch = NULL;
395		}
396
397		/* Save the new section, to append it later. */
398
399		if (NULL == prevsec) {
400			prevsec = mandoc_strdup(sec);
401			prevarch = mandoc_strdup(arch);
402		}
403
404		/* Append the new name. */
405
406		mandoc_asprintf(&newnames, "%s%s%s",
407		    oldnames, sep1, name);
408		free(mpage->names);
409		mpage->names = newnames;
410
411		/* Also save the first file name encountered. */
412
413		if (NULL != mpage->file)
414			continue;
415
416		if (form) {
417			sep1 = "man";
418			fsec = sec;
419		} else {
420			sep1 = "cat";
421			fsec = "0";
422		}
423		sep2 = '\0' == *arch ? "" : "/";
424		mandoc_asprintf(&mpage->file, "%s/%s%s%s%s/%s.%s",
425		    path, sep1, sec, sep2, arch, name, fsec);
426	}
427	if (SQLITE_DONE != c)
428		fprintf(stderr, "%s\n", sqlite3_errmsg(db));
429	sqlite3_reset(s);
430
431	/* Append one final section to the names. */
432
433	if (NULL != prevsec) {
434		sep2 = '\0' == *prevarch ? "" : "/";
435		mandoc_asprintf(&newnames, "%s(%s%s%s)",
436		    mpage->names, prevsec, sep2, prevarch);
437		free(mpage->names);
438		mpage->names = newnames;
439		free(prevsec);
440		free(prevarch);
441	}
442}
443
444static char *
445buildoutput(sqlite3 *db, sqlite3_stmt *s, uint64_t id, uint64_t outbit)
446{
447	char		*output, *newoutput;
448	const char	*oldoutput, *sep1, *data;
449	size_t		 i;
450	int		 c;
451
452	output = NULL;
453	i = 1;
454	SQL_BIND_INT64(db, s, i, id);
455	SQL_BIND_INT64(db, s, i, outbit);
456	while (SQLITE_ROW == (c = sqlite3_step(s))) {
457		if (NULL == output) {
458			oldoutput = "";
459			sep1 = "";
460		} else {
461			oldoutput = output;
462			sep1 = " # ";
463		}
464		data = sqlite3_column_text(s, 1);
465		mandoc_asprintf(&newoutput, "%s%s%s",
466		    oldoutput, sep1, data);
467		free(output);
468		output = newoutput;
469	}
470	if (SQLITE_DONE != c)
471		fprintf(stderr, "%s\n", sqlite3_errmsg(db));
472	sqlite3_reset(s);
473	return(output);
474}
475
476/*
477 * Implement substring match as an application-defined SQL function.
478 * Using the SQL LIKE or GLOB operators instead would be a bad idea
479 * because that would require escaping metacharacters in the string
480 * being searched for.
481 */
482static void
483sql_match(sqlite3_context *context, int argc, sqlite3_value **argv)
484{
485
486	assert(2 == argc);
487	sqlite3_result_int(context, NULL != strcasestr(
488	    (const char *)sqlite3_value_text(argv[1]),
489	    (const char *)sqlite3_value_text(argv[0])));
490}
491
492/*
493 * Implement regular expression match
494 * as an application-defined SQL function.
495 */
496static void
497sql_regexp(sqlite3_context *context, int argc, sqlite3_value **argv)
498{
499
500	assert(2 == argc);
501	sqlite3_result_int(context, !regexec(
502	    (regex_t *)sqlite3_value_blob(argv[0]),
503	    (const char *)sqlite3_value_text(argv[1]),
504	    0, NULL, 0));
505}
506
507static void
508sql_append(char **sql, size_t *sz, const char *newstr, int count)
509{
510	size_t		 newsz;
511
512	newsz = 1 < count ? (size_t)count : strlen(newstr);
513	*sql = mandoc_realloc(*sql, *sz + newsz + 1);
514	if (1 < count)
515		memset(*sql + *sz, *newstr, (size_t)count);
516	else
517		memcpy(*sql + *sz, newstr, newsz);
518	*sz += newsz;
519	(*sql)[*sz] = '\0';
520}
521
522/*
523 * Prepare the search SQL statement.
524 */
525static char *
526sql_statement(const struct expr *e)
527{
528	char		*sql;
529	size_t		 sz;
530	int		 needop;
531
532	sql = mandoc_strdup("SELECT * FROM mpages WHERE ");
533	sz = strlen(sql);
534
535	for (needop = 0; NULL != e; e = e->next) {
536		if (e->and)
537			sql_append(&sql, &sz, " AND ", 1);
538		else if (needop)
539			sql_append(&sql, &sz, " OR ", 1);
540		if (e->open)
541			sql_append(&sql, &sz, "(", e->open);
542		sql_append(&sql, &sz,
543		    TYPE_Nd & e->bits
544		    ? (NULL == e->substr
545			? "desc REGEXP ?"
546			: "desc MATCH ?")
547		    : TYPE_Nm == e->bits
548		    ? (NULL == e->substr
549			? "id IN (SELECT pageid FROM names "
550			  "WHERE name REGEXP ?)"
551			: "id IN (SELECT pageid FROM names "
552			  "WHERE name MATCH ?)")
553		    : (NULL == e->substr
554			? "id IN (SELECT pageid FROM keys "
555			  "WHERE key REGEXP ? AND bits & ?)"
556			: "id IN (SELECT pageid FROM keys "
557			  "WHERE key MATCH ? AND bits & ?)"), 1);
558		if (e->close)
559			sql_append(&sql, &sz, ")", e->close);
560		needop = 1;
561	}
562
563	return(sql);
564}
565
566/*
567 * Compile a set of string tokens into an expression.
568 * Tokens in "argv" are assumed to be individual expression atoms (e.g.,
569 * "(", "foo=bar", etc.).
570 */
571static struct expr *
572exprcomp(const struct mansearch *search, int argc, char *argv[])
573{
574	uint64_t	 mask;
575	int		 i, toopen, logic, igncase, toclose;
576	struct expr	*first, *prev, *cur, *next;
577
578	first = cur = NULL;
579	logic = igncase = toclose = 0;
580	toopen = 1;
581
582	for (i = 0; i < argc; i++) {
583		if (0 == strcmp("(", argv[i])) {
584			if (igncase)
585				goto fail;
586			toopen++;
587			toclose++;
588			continue;
589		} else if (0 == strcmp(")", argv[i])) {
590			if (toopen || logic || igncase || NULL == cur)
591				goto fail;
592			cur->close++;
593			if (0 > --toclose)
594				goto fail;
595			continue;
596		} else if (0 == strcmp("-a", argv[i])) {
597			if (toopen || logic || igncase || NULL == cur)
598				goto fail;
599			logic = 1;
600			continue;
601		} else if (0 == strcmp("-o", argv[i])) {
602			if (toopen || logic || igncase || NULL == cur)
603				goto fail;
604			logic = 2;
605			continue;
606		} else if (0 == strcmp("-i", argv[i])) {
607			if (igncase)
608				goto fail;
609			igncase = 1;
610			continue;
611		}
612		next = exprterm(search, argv[i], !igncase);
613		if (NULL == next)
614			goto fail;
615		if (NULL == first)
616			first = next;
617		else
618			cur->next = next;
619		prev = cur = next;
620
621		/*
622		 * Searching for descriptions must be split out
623		 * because they are stored in the mpages table,
624		 * not in the keys table.
625		 */
626
627		for (mask = TYPE_Nm; mask <= TYPE_Nd; mask <<= 1) {
628			if (mask & cur->bits && ~mask & cur->bits) {
629				next = mandoc_calloc(1,
630				    sizeof(struct expr));
631				memcpy(next, cur, sizeof(struct expr));
632				prev->open = 1;
633				cur->bits = mask;
634				cur->next = next;
635				cur = next;
636				cur->bits &= ~mask;
637			}
638		}
639		prev->and = (1 == logic);
640		prev->open += toopen;
641		if (cur != prev)
642			cur->close = 1;
643
644		toopen = logic = igncase = 0;
645	}
646	if (toopen || logic || igncase || toclose)
647		goto fail;
648
649	cur->close++;
650	cur = exprspec(cur, TYPE_arch, search->arch, "^(%s|any)$");
651	exprspec(cur, TYPE_sec, search->sec, "^%s$");
652
653	return(first);
654
655fail:
656	if (NULL != first)
657		exprfree(first);
658	return(NULL);
659}
660
661static struct expr *
662exprspec(struct expr *cur, uint64_t key, const char *value,
663		const char *format)
664{
665	char	 errbuf[BUFSIZ];
666	char	*cp;
667	int	 irc;
668
669	if (NULL == value)
670		return(cur);
671
672	mandoc_asprintf(&cp, format, value);
673	cur->next = mandoc_calloc(1, sizeof(struct expr));
674	cur = cur->next;
675	cur->and = 1;
676	cur->bits = key;
677	if (0 != (irc = regcomp(&cur->regexp, cp,
678	    REG_EXTENDED | REG_NOSUB | REG_ICASE))) {
679		regerror(irc, &cur->regexp, errbuf, sizeof(errbuf));
680		fprintf(stderr, "regcomp: %s\n", errbuf);
681		cur->substr = value;
682	}
683	free(cp);
684	return(cur);
685}
686
687static struct expr *
688exprterm(const struct mansearch *search, char *buf, int cs)
689{
690	char		 errbuf[BUFSIZ];
691	struct expr	*e;
692	char		*key, *v;
693	uint64_t	 iterbit;
694	int		 i, irc;
695
696	if ('\0' == *buf)
697		return(NULL);
698
699	e = mandoc_calloc(1, sizeof(struct expr));
700
701	/*"whatis" mode uses an opaque string and default fields. */
702
703	if (MANSEARCH_WHATIS & search->flags) {
704		e->substr = buf;
705		e->bits = search->deftype;
706		return(e);
707	}
708
709	/*
710	 * If no =~ is specified, search with equality over names and
711	 * descriptions.
712	 * If =~ begins the phrase, use name and description fields.
713	 */
714
715	if (NULL == (v = strpbrk(buf, "=~"))) {
716		e->substr = buf;
717		e->bits = search->deftype;
718		return(e);
719	} else if (v == buf)
720		e->bits = search->deftype;
721
722	if ('~' == *v++) {
723		if (NULL != strstr(buf, "arch"))
724			cs = 0;
725		if (0 != (irc = regcomp(&e->regexp, v,
726		    REG_EXTENDED | REG_NOSUB | (cs ? 0 : REG_ICASE)))) {
727			regerror(irc, &e->regexp, errbuf, sizeof(errbuf));
728			fprintf(stderr, "regcomp: %s\n", errbuf);
729			free(e);
730			return(NULL);
731		}
732	} else
733		e->substr = v;
734	v[-1] = '\0';
735
736	/*
737	 * Parse out all possible fields.
738	 * If the field doesn't resolve, bail.
739	 */
740
741	while (NULL != (key = strsep(&buf, ","))) {
742		if ('\0' == *key)
743			continue;
744		for (i = 0, iterbit = 1;
745		     i < mansearch_keymax;
746		     i++, iterbit <<= 1) {
747			if (0 == strcasecmp(key,
748			    mansearch_keynames[i])) {
749				e->bits |= iterbit;
750				break;
751			}
752		}
753		if (i == mansearch_keymax) {
754			if (strcasecmp(key, "any")) {
755				free(e);
756				return(NULL);
757			}
758			e->bits |= ~0ULL;
759		}
760	}
761
762	return(e);
763}
764
765static void
766exprfree(struct expr *p)
767{
768	struct expr	*pp;
769
770	while (NULL != p) {
771		pp = p->next;
772		free(p);
773		p = pp;
774	}
775}
776
777static void *
778hash_halloc(size_t sz, void *arg)
779{
780
781	return(mandoc_calloc(sz, 1));
782}
783
784static void *
785hash_alloc(size_t sz, void *arg)
786{
787
788	return(mandoc_malloc(sz));
789}
790
791static void
792hash_free(void *p, size_t sz, void *arg)
793{
794
795	free(p);
796}
797