xref: /freebsd/contrib/mandoc/dbm.c (revision 61d06d6bd19dafe8ea971dd43e8328fa1b473456)
1*61d06d6bSBaptiste Daroussin /*	$Id: dbm.c,v 1.5 2016/10/18 22:27:25 schwarze Exp $ */
2*61d06d6bSBaptiste Daroussin /*
3*61d06d6bSBaptiste Daroussin  * Copyright (c) 2016 Ingo Schwarze <schwarze@openbsd.org>
4*61d06d6bSBaptiste Daroussin  *
5*61d06d6bSBaptiste Daroussin  * Permission to use, copy, modify, and distribute this software for any
6*61d06d6bSBaptiste Daroussin  * purpose with or without fee is hereby granted, provided that the above
7*61d06d6bSBaptiste Daroussin  * copyright notice and this permission notice appear in all copies.
8*61d06d6bSBaptiste Daroussin  *
9*61d06d6bSBaptiste Daroussin  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10*61d06d6bSBaptiste Daroussin  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11*61d06d6bSBaptiste Daroussin  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12*61d06d6bSBaptiste Daroussin  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13*61d06d6bSBaptiste Daroussin  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14*61d06d6bSBaptiste Daroussin  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15*61d06d6bSBaptiste Daroussin  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16*61d06d6bSBaptiste Daroussin  *
17*61d06d6bSBaptiste Daroussin  * Map-based version of the mandoc database, for read-only access.
18*61d06d6bSBaptiste Daroussin  * The interface is defined in "dbm.h".
19*61d06d6bSBaptiste Daroussin  */
20*61d06d6bSBaptiste Daroussin #include "config.h"
21*61d06d6bSBaptiste Daroussin 
22*61d06d6bSBaptiste Daroussin #include <assert.h>
23*61d06d6bSBaptiste Daroussin #if HAVE_ENDIAN
24*61d06d6bSBaptiste Daroussin #include <endian.h>
25*61d06d6bSBaptiste Daroussin #elif HAVE_SYS_ENDIAN
26*61d06d6bSBaptiste Daroussin #include <sys/endian.h>
27*61d06d6bSBaptiste Daroussin #elif HAVE_NTOHL
28*61d06d6bSBaptiste Daroussin #include <arpa/inet.h>
29*61d06d6bSBaptiste Daroussin #endif
30*61d06d6bSBaptiste Daroussin #if HAVE_ERR
31*61d06d6bSBaptiste Daroussin #include <err.h>
32*61d06d6bSBaptiste Daroussin #endif
33*61d06d6bSBaptiste Daroussin #include <errno.h>
34*61d06d6bSBaptiste Daroussin #include <regex.h>
35*61d06d6bSBaptiste Daroussin #include <stdint.h>
36*61d06d6bSBaptiste Daroussin #include <stdio.h>
37*61d06d6bSBaptiste Daroussin #include <stdlib.h>
38*61d06d6bSBaptiste Daroussin #include <string.h>
39*61d06d6bSBaptiste Daroussin 
40*61d06d6bSBaptiste Daroussin #include "mansearch.h"
41*61d06d6bSBaptiste Daroussin #include "dbm_map.h"
42*61d06d6bSBaptiste Daroussin #include "dbm.h"
43*61d06d6bSBaptiste Daroussin 
44*61d06d6bSBaptiste Daroussin struct macro {
45*61d06d6bSBaptiste Daroussin 	int32_t	value;
46*61d06d6bSBaptiste Daroussin 	int32_t	pages;
47*61d06d6bSBaptiste Daroussin };
48*61d06d6bSBaptiste Daroussin 
49*61d06d6bSBaptiste Daroussin struct page {
50*61d06d6bSBaptiste Daroussin 	int32_t	name;
51*61d06d6bSBaptiste Daroussin 	int32_t	sect;
52*61d06d6bSBaptiste Daroussin 	int32_t	arch;
53*61d06d6bSBaptiste Daroussin 	int32_t	desc;
54*61d06d6bSBaptiste Daroussin 	int32_t	file;
55*61d06d6bSBaptiste Daroussin };
56*61d06d6bSBaptiste Daroussin 
57*61d06d6bSBaptiste Daroussin enum iter {
58*61d06d6bSBaptiste Daroussin 	ITER_NONE = 0,
59*61d06d6bSBaptiste Daroussin 	ITER_NAME,
60*61d06d6bSBaptiste Daroussin 	ITER_SECT,
61*61d06d6bSBaptiste Daroussin 	ITER_ARCH,
62*61d06d6bSBaptiste Daroussin 	ITER_DESC,
63*61d06d6bSBaptiste Daroussin 	ITER_MACRO
64*61d06d6bSBaptiste Daroussin };
65*61d06d6bSBaptiste Daroussin 
66*61d06d6bSBaptiste Daroussin static struct macro	*macros[MACRO_MAX];
67*61d06d6bSBaptiste Daroussin static int32_t		 nvals[MACRO_MAX];
68*61d06d6bSBaptiste Daroussin static struct page	*pages;
69*61d06d6bSBaptiste Daroussin static int32_t		 npages;
70*61d06d6bSBaptiste Daroussin static enum iter	 iteration;
71*61d06d6bSBaptiste Daroussin 
72*61d06d6bSBaptiste Daroussin static struct dbm_res	 page_bytitle(enum iter, const struct dbm_match *);
73*61d06d6bSBaptiste Daroussin static struct dbm_res	 page_byarch(const struct dbm_match *);
74*61d06d6bSBaptiste Daroussin static struct dbm_res	 page_bymacro(int32_t, const struct dbm_match *);
75*61d06d6bSBaptiste Daroussin static char		*macro_bypage(int32_t, int32_t);
76*61d06d6bSBaptiste Daroussin 
77*61d06d6bSBaptiste Daroussin 
78*61d06d6bSBaptiste Daroussin /*** top level functions **********************************************/
79*61d06d6bSBaptiste Daroussin 
80*61d06d6bSBaptiste Daroussin /*
81*61d06d6bSBaptiste Daroussin  * Open a disk-based mandoc database for read-only access.
82*61d06d6bSBaptiste Daroussin  * Map the pages and macros[] arrays.
83*61d06d6bSBaptiste Daroussin  * Return 0 on success.  Return -1 and set errno on failure.
84*61d06d6bSBaptiste Daroussin  */
85*61d06d6bSBaptiste Daroussin int
86*61d06d6bSBaptiste Daroussin dbm_open(const char *fname)
87*61d06d6bSBaptiste Daroussin {
88*61d06d6bSBaptiste Daroussin 	const int32_t	*mp, *ep;
89*61d06d6bSBaptiste Daroussin 	int32_t		 im;
90*61d06d6bSBaptiste Daroussin 
91*61d06d6bSBaptiste Daroussin 	if (dbm_map(fname) == -1)
92*61d06d6bSBaptiste Daroussin 		return -1;
93*61d06d6bSBaptiste Daroussin 
94*61d06d6bSBaptiste Daroussin 	if ((npages = be32toh(*dbm_getint(4))) < 0) {
95*61d06d6bSBaptiste Daroussin 		warnx("dbm_open(%s): Invalid number of pages: %d",
96*61d06d6bSBaptiste Daroussin 		    fname, npages);
97*61d06d6bSBaptiste Daroussin 		goto fail;
98*61d06d6bSBaptiste Daroussin 	}
99*61d06d6bSBaptiste Daroussin 	pages = (struct page *)dbm_getint(5);
100*61d06d6bSBaptiste Daroussin 
101*61d06d6bSBaptiste Daroussin 	if ((mp = dbm_get(*dbm_getint(2))) == NULL) {
102*61d06d6bSBaptiste Daroussin 		warnx("dbm_open(%s): Invalid offset of macros array", fname);
103*61d06d6bSBaptiste Daroussin 		goto fail;
104*61d06d6bSBaptiste Daroussin 	}
105*61d06d6bSBaptiste Daroussin 	if (be32toh(*mp) != MACRO_MAX) {
106*61d06d6bSBaptiste Daroussin 		warnx("dbm_open(%s): Invalid number of macros: %d",
107*61d06d6bSBaptiste Daroussin 		    fname, be32toh(*mp));
108*61d06d6bSBaptiste Daroussin 		goto fail;
109*61d06d6bSBaptiste Daroussin 	}
110*61d06d6bSBaptiste Daroussin 	for (im = 0; im < MACRO_MAX; im++) {
111*61d06d6bSBaptiste Daroussin 		if ((ep = dbm_get(*++mp)) == NULL) {
112*61d06d6bSBaptiste Daroussin 			warnx("dbm_open(%s): Invalid offset of macro %d",
113*61d06d6bSBaptiste Daroussin 			    fname, im);
114*61d06d6bSBaptiste Daroussin 			goto fail;
115*61d06d6bSBaptiste Daroussin 		}
116*61d06d6bSBaptiste Daroussin 		nvals[im] = be32toh(*ep);
117*61d06d6bSBaptiste Daroussin 		macros[im] = (struct macro *)++ep;
118*61d06d6bSBaptiste Daroussin 	}
119*61d06d6bSBaptiste Daroussin 	return 0;
120*61d06d6bSBaptiste Daroussin 
121*61d06d6bSBaptiste Daroussin fail:
122*61d06d6bSBaptiste Daroussin 	dbm_unmap();
123*61d06d6bSBaptiste Daroussin 	errno = EFTYPE;
124*61d06d6bSBaptiste Daroussin 	return -1;
125*61d06d6bSBaptiste Daroussin }
126*61d06d6bSBaptiste Daroussin 
127*61d06d6bSBaptiste Daroussin void
128*61d06d6bSBaptiste Daroussin dbm_close(void)
129*61d06d6bSBaptiste Daroussin {
130*61d06d6bSBaptiste Daroussin 	dbm_unmap();
131*61d06d6bSBaptiste Daroussin }
132*61d06d6bSBaptiste Daroussin 
133*61d06d6bSBaptiste Daroussin 
134*61d06d6bSBaptiste Daroussin /*** functions for handling pages *************************************/
135*61d06d6bSBaptiste Daroussin 
136*61d06d6bSBaptiste Daroussin int32_t
137*61d06d6bSBaptiste Daroussin dbm_page_count(void)
138*61d06d6bSBaptiste Daroussin {
139*61d06d6bSBaptiste Daroussin 	return npages;
140*61d06d6bSBaptiste Daroussin }
141*61d06d6bSBaptiste Daroussin 
142*61d06d6bSBaptiste Daroussin /*
143*61d06d6bSBaptiste Daroussin  * Give the caller pointers to the data for one manual page.
144*61d06d6bSBaptiste Daroussin  */
145*61d06d6bSBaptiste Daroussin struct dbm_page *
146*61d06d6bSBaptiste Daroussin dbm_page_get(int32_t ip)
147*61d06d6bSBaptiste Daroussin {
148*61d06d6bSBaptiste Daroussin 	static struct dbm_page	 res;
149*61d06d6bSBaptiste Daroussin 
150*61d06d6bSBaptiste Daroussin 	assert(ip >= 0);
151*61d06d6bSBaptiste Daroussin 	assert(ip < npages);
152*61d06d6bSBaptiste Daroussin 	res.name = dbm_get(pages[ip].name);
153*61d06d6bSBaptiste Daroussin 	if (res.name == NULL)
154*61d06d6bSBaptiste Daroussin 		res.name = "(NULL)";
155*61d06d6bSBaptiste Daroussin 	res.sect = dbm_get(pages[ip].sect);
156*61d06d6bSBaptiste Daroussin 	if (res.sect == NULL)
157*61d06d6bSBaptiste Daroussin 		res.sect = "(NULL)";
158*61d06d6bSBaptiste Daroussin 	res.arch = pages[ip].arch ? dbm_get(pages[ip].arch) : NULL;
159*61d06d6bSBaptiste Daroussin 	res.desc = dbm_get(pages[ip].desc);
160*61d06d6bSBaptiste Daroussin 	if (res.desc == NULL)
161*61d06d6bSBaptiste Daroussin 		res.desc = "(NULL)";
162*61d06d6bSBaptiste Daroussin 	res.file = dbm_get(pages[ip].file);
163*61d06d6bSBaptiste Daroussin 	if (res.file == NULL)
164*61d06d6bSBaptiste Daroussin 		res.file = " (NULL)";
165*61d06d6bSBaptiste Daroussin 	res.addr = dbm_addr(pages + ip);
166*61d06d6bSBaptiste Daroussin 	return &res;
167*61d06d6bSBaptiste Daroussin }
168*61d06d6bSBaptiste Daroussin 
169*61d06d6bSBaptiste Daroussin /*
170*61d06d6bSBaptiste Daroussin  * Functions to start filtered iterations over manual pages.
171*61d06d6bSBaptiste Daroussin  */
172*61d06d6bSBaptiste Daroussin void
173*61d06d6bSBaptiste Daroussin dbm_page_byname(const struct dbm_match *match)
174*61d06d6bSBaptiste Daroussin {
175*61d06d6bSBaptiste Daroussin 	assert(match != NULL);
176*61d06d6bSBaptiste Daroussin 	page_bytitle(ITER_NAME, match);
177*61d06d6bSBaptiste Daroussin }
178*61d06d6bSBaptiste Daroussin 
179*61d06d6bSBaptiste Daroussin void
180*61d06d6bSBaptiste Daroussin dbm_page_bysect(const struct dbm_match *match)
181*61d06d6bSBaptiste Daroussin {
182*61d06d6bSBaptiste Daroussin 	assert(match != NULL);
183*61d06d6bSBaptiste Daroussin 	page_bytitle(ITER_SECT, match);
184*61d06d6bSBaptiste Daroussin }
185*61d06d6bSBaptiste Daroussin 
186*61d06d6bSBaptiste Daroussin void
187*61d06d6bSBaptiste Daroussin dbm_page_byarch(const struct dbm_match *match)
188*61d06d6bSBaptiste Daroussin {
189*61d06d6bSBaptiste Daroussin 	assert(match != NULL);
190*61d06d6bSBaptiste Daroussin 	page_byarch(match);
191*61d06d6bSBaptiste Daroussin }
192*61d06d6bSBaptiste Daroussin 
193*61d06d6bSBaptiste Daroussin void
194*61d06d6bSBaptiste Daroussin dbm_page_bydesc(const struct dbm_match *match)
195*61d06d6bSBaptiste Daroussin {
196*61d06d6bSBaptiste Daroussin 	assert(match != NULL);
197*61d06d6bSBaptiste Daroussin 	page_bytitle(ITER_DESC, match);
198*61d06d6bSBaptiste Daroussin }
199*61d06d6bSBaptiste Daroussin 
200*61d06d6bSBaptiste Daroussin void
201*61d06d6bSBaptiste Daroussin dbm_page_bymacro(int32_t im, const struct dbm_match *match)
202*61d06d6bSBaptiste Daroussin {
203*61d06d6bSBaptiste Daroussin 	assert(im >= 0);
204*61d06d6bSBaptiste Daroussin 	assert(im < MACRO_MAX);
205*61d06d6bSBaptiste Daroussin 	assert(match != NULL);
206*61d06d6bSBaptiste Daroussin 	page_bymacro(im, match);
207*61d06d6bSBaptiste Daroussin }
208*61d06d6bSBaptiste Daroussin 
209*61d06d6bSBaptiste Daroussin /*
210*61d06d6bSBaptiste Daroussin  * Return the number of the next manual page in the current iteration.
211*61d06d6bSBaptiste Daroussin  */
212*61d06d6bSBaptiste Daroussin struct dbm_res
213*61d06d6bSBaptiste Daroussin dbm_page_next(void)
214*61d06d6bSBaptiste Daroussin {
215*61d06d6bSBaptiste Daroussin 	struct dbm_res			 res = {-1, 0};
216*61d06d6bSBaptiste Daroussin 
217*61d06d6bSBaptiste Daroussin 	switch(iteration) {
218*61d06d6bSBaptiste Daroussin 	case ITER_NONE:
219*61d06d6bSBaptiste Daroussin 		return res;
220*61d06d6bSBaptiste Daroussin 	case ITER_ARCH:
221*61d06d6bSBaptiste Daroussin 		return page_byarch(NULL);
222*61d06d6bSBaptiste Daroussin 	case ITER_MACRO:
223*61d06d6bSBaptiste Daroussin 		return page_bymacro(0, NULL);
224*61d06d6bSBaptiste Daroussin 	default:
225*61d06d6bSBaptiste Daroussin 		return page_bytitle(iteration, NULL);
226*61d06d6bSBaptiste Daroussin 	}
227*61d06d6bSBaptiste Daroussin }
228*61d06d6bSBaptiste Daroussin 
229*61d06d6bSBaptiste Daroussin /*
230*61d06d6bSBaptiste Daroussin  * Functions implementing the iteration over manual pages.
231*61d06d6bSBaptiste Daroussin  */
232*61d06d6bSBaptiste Daroussin static struct dbm_res
233*61d06d6bSBaptiste Daroussin page_bytitle(enum iter arg_iter, const struct dbm_match *arg_match)
234*61d06d6bSBaptiste Daroussin {
235*61d06d6bSBaptiste Daroussin 	static const struct dbm_match	*match;
236*61d06d6bSBaptiste Daroussin 	static const char		*cp;
237*61d06d6bSBaptiste Daroussin 	static int32_t			 ip;
238*61d06d6bSBaptiste Daroussin 	struct dbm_res			 res = {-1, 0};
239*61d06d6bSBaptiste Daroussin 
240*61d06d6bSBaptiste Daroussin 	assert(arg_iter == ITER_NAME || arg_iter == ITER_DESC ||
241*61d06d6bSBaptiste Daroussin 	    arg_iter == ITER_SECT);
242*61d06d6bSBaptiste Daroussin 
243*61d06d6bSBaptiste Daroussin 	/* Initialize for a new iteration. */
244*61d06d6bSBaptiste Daroussin 
245*61d06d6bSBaptiste Daroussin 	if (arg_match != NULL) {
246*61d06d6bSBaptiste Daroussin 		iteration = arg_iter;
247*61d06d6bSBaptiste Daroussin 		match = arg_match;
248*61d06d6bSBaptiste Daroussin 		switch (iteration) {
249*61d06d6bSBaptiste Daroussin 		case ITER_NAME:
250*61d06d6bSBaptiste Daroussin 			cp = dbm_get(pages[0].name);
251*61d06d6bSBaptiste Daroussin 			break;
252*61d06d6bSBaptiste Daroussin 		case ITER_SECT:
253*61d06d6bSBaptiste Daroussin 			cp = dbm_get(pages[0].sect);
254*61d06d6bSBaptiste Daroussin 			break;
255*61d06d6bSBaptiste Daroussin 		case ITER_DESC:
256*61d06d6bSBaptiste Daroussin 			cp = dbm_get(pages[0].desc);
257*61d06d6bSBaptiste Daroussin 			break;
258*61d06d6bSBaptiste Daroussin 		default:
259*61d06d6bSBaptiste Daroussin 			abort();
260*61d06d6bSBaptiste Daroussin 		}
261*61d06d6bSBaptiste Daroussin 		if (cp == NULL) {
262*61d06d6bSBaptiste Daroussin 			iteration = ITER_NONE;
263*61d06d6bSBaptiste Daroussin 			match = NULL;
264*61d06d6bSBaptiste Daroussin 			cp = NULL;
265*61d06d6bSBaptiste Daroussin 			ip = npages;
266*61d06d6bSBaptiste Daroussin 		} else
267*61d06d6bSBaptiste Daroussin 			ip = 0;
268*61d06d6bSBaptiste Daroussin 		return res;
269*61d06d6bSBaptiste Daroussin 	}
270*61d06d6bSBaptiste Daroussin 
271*61d06d6bSBaptiste Daroussin 	/* Search for a name. */
272*61d06d6bSBaptiste Daroussin 
273*61d06d6bSBaptiste Daroussin 	while (ip < npages) {
274*61d06d6bSBaptiste Daroussin 		if (iteration == ITER_NAME)
275*61d06d6bSBaptiste Daroussin 			cp++;
276*61d06d6bSBaptiste Daroussin 		if (dbm_match(match, cp))
277*61d06d6bSBaptiste Daroussin 			break;
278*61d06d6bSBaptiste Daroussin 		cp = strchr(cp, '\0') + 1;
279*61d06d6bSBaptiste Daroussin 		if (iteration == ITER_DESC)
280*61d06d6bSBaptiste Daroussin 			ip++;
281*61d06d6bSBaptiste Daroussin 		else if (*cp == '\0') {
282*61d06d6bSBaptiste Daroussin 			cp++;
283*61d06d6bSBaptiste Daroussin 			ip++;
284*61d06d6bSBaptiste Daroussin 		}
285*61d06d6bSBaptiste Daroussin 	}
286*61d06d6bSBaptiste Daroussin 
287*61d06d6bSBaptiste Daroussin 	/* Reached the end without a match. */
288*61d06d6bSBaptiste Daroussin 
289*61d06d6bSBaptiste Daroussin 	if (ip == npages) {
290*61d06d6bSBaptiste Daroussin 		iteration = ITER_NONE;
291*61d06d6bSBaptiste Daroussin 		match = NULL;
292*61d06d6bSBaptiste Daroussin 		cp = NULL;
293*61d06d6bSBaptiste Daroussin 		return res;
294*61d06d6bSBaptiste Daroussin 	}
295*61d06d6bSBaptiste Daroussin 
296*61d06d6bSBaptiste Daroussin 	/* Found a match; save the quality for later retrieval. */
297*61d06d6bSBaptiste Daroussin 
298*61d06d6bSBaptiste Daroussin 	res.page = ip;
299*61d06d6bSBaptiste Daroussin 	res.bits = iteration == ITER_NAME ? cp[-1] : 0;
300*61d06d6bSBaptiste Daroussin 
301*61d06d6bSBaptiste Daroussin 	/* Skip the remaining names of this page. */
302*61d06d6bSBaptiste Daroussin 
303*61d06d6bSBaptiste Daroussin 	if (++ip < npages) {
304*61d06d6bSBaptiste Daroussin 		do {
305*61d06d6bSBaptiste Daroussin 			cp++;
306*61d06d6bSBaptiste Daroussin 		} while (cp[-1] != '\0' ||
307*61d06d6bSBaptiste Daroussin 		    (iteration != ITER_DESC && cp[-2] != '\0'));
308*61d06d6bSBaptiste Daroussin 	}
309*61d06d6bSBaptiste Daroussin 	return res;
310*61d06d6bSBaptiste Daroussin }
311*61d06d6bSBaptiste Daroussin 
312*61d06d6bSBaptiste Daroussin static struct dbm_res
313*61d06d6bSBaptiste Daroussin page_byarch(const struct dbm_match *arg_match)
314*61d06d6bSBaptiste Daroussin {
315*61d06d6bSBaptiste Daroussin 	static const struct dbm_match	*match;
316*61d06d6bSBaptiste Daroussin 	struct dbm_res			 res = {-1, 0};
317*61d06d6bSBaptiste Daroussin 	static int32_t			 ip;
318*61d06d6bSBaptiste Daroussin 	const char			*cp;
319*61d06d6bSBaptiste Daroussin 
320*61d06d6bSBaptiste Daroussin 	/* Initialize for a new iteration. */
321*61d06d6bSBaptiste Daroussin 
322*61d06d6bSBaptiste Daroussin 	if (arg_match != NULL) {
323*61d06d6bSBaptiste Daroussin 		iteration = ITER_ARCH;
324*61d06d6bSBaptiste Daroussin 		match = arg_match;
325*61d06d6bSBaptiste Daroussin 		ip = 0;
326*61d06d6bSBaptiste Daroussin 		return res;
327*61d06d6bSBaptiste Daroussin 	}
328*61d06d6bSBaptiste Daroussin 
329*61d06d6bSBaptiste Daroussin 	/* Search for an architecture. */
330*61d06d6bSBaptiste Daroussin 
331*61d06d6bSBaptiste Daroussin 	for ( ; ip < npages; ip++)
332*61d06d6bSBaptiste Daroussin 		if (pages[ip].arch)
333*61d06d6bSBaptiste Daroussin 			for (cp = dbm_get(pages[ip].arch);
334*61d06d6bSBaptiste Daroussin 			    *cp != '\0';
335*61d06d6bSBaptiste Daroussin 			    cp = strchr(cp, '\0') + 1)
336*61d06d6bSBaptiste Daroussin 				if (dbm_match(match, cp)) {
337*61d06d6bSBaptiste Daroussin 					res.page = ip++;
338*61d06d6bSBaptiste Daroussin 					return res;
339*61d06d6bSBaptiste Daroussin 				}
340*61d06d6bSBaptiste Daroussin 
341*61d06d6bSBaptiste Daroussin 	/* Reached the end without a match. */
342*61d06d6bSBaptiste Daroussin 
343*61d06d6bSBaptiste Daroussin 	iteration = ITER_NONE;
344*61d06d6bSBaptiste Daroussin 	match = NULL;
345*61d06d6bSBaptiste Daroussin 	return res;
346*61d06d6bSBaptiste Daroussin }
347*61d06d6bSBaptiste Daroussin 
348*61d06d6bSBaptiste Daroussin static struct dbm_res
349*61d06d6bSBaptiste Daroussin page_bymacro(int32_t arg_im, const struct dbm_match *arg_match)
350*61d06d6bSBaptiste Daroussin {
351*61d06d6bSBaptiste Daroussin 	static const struct dbm_match	*match;
352*61d06d6bSBaptiste Daroussin 	static const int32_t		*pp;
353*61d06d6bSBaptiste Daroussin 	static const char		*cp;
354*61d06d6bSBaptiste Daroussin 	static int32_t			 im, iv;
355*61d06d6bSBaptiste Daroussin 	struct dbm_res			 res = {-1, 0};
356*61d06d6bSBaptiste Daroussin 
357*61d06d6bSBaptiste Daroussin 	assert(im >= 0);
358*61d06d6bSBaptiste Daroussin 	assert(im < MACRO_MAX);
359*61d06d6bSBaptiste Daroussin 
360*61d06d6bSBaptiste Daroussin 	/* Initialize for a new iteration. */
361*61d06d6bSBaptiste Daroussin 
362*61d06d6bSBaptiste Daroussin 	if (arg_match != NULL) {
363*61d06d6bSBaptiste Daroussin 		iteration = ITER_MACRO;
364*61d06d6bSBaptiste Daroussin 		match = arg_match;
365*61d06d6bSBaptiste Daroussin 		im = arg_im;
366*61d06d6bSBaptiste Daroussin 		cp = nvals[im] ? dbm_get(macros[im]->value) : NULL;
367*61d06d6bSBaptiste Daroussin 		pp = NULL;
368*61d06d6bSBaptiste Daroussin 		iv = -1;
369*61d06d6bSBaptiste Daroussin 		return res;
370*61d06d6bSBaptiste Daroussin 	}
371*61d06d6bSBaptiste Daroussin 	if (iteration != ITER_MACRO)
372*61d06d6bSBaptiste Daroussin 		return res;
373*61d06d6bSBaptiste Daroussin 
374*61d06d6bSBaptiste Daroussin 	/* Find the next matching macro value. */
375*61d06d6bSBaptiste Daroussin 
376*61d06d6bSBaptiste Daroussin 	while (pp == NULL || *pp == 0) {
377*61d06d6bSBaptiste Daroussin 		if (++iv == nvals[im]) {
378*61d06d6bSBaptiste Daroussin 			iteration = ITER_NONE;
379*61d06d6bSBaptiste Daroussin 			return res;
380*61d06d6bSBaptiste Daroussin 		}
381*61d06d6bSBaptiste Daroussin 		if (iv)
382*61d06d6bSBaptiste Daroussin 			cp = strchr(cp, '\0') + 1;
383*61d06d6bSBaptiste Daroussin 		if (dbm_match(match, cp))
384*61d06d6bSBaptiste Daroussin 			pp = dbm_get(macros[im][iv].pages);
385*61d06d6bSBaptiste Daroussin 	}
386*61d06d6bSBaptiste Daroussin 
387*61d06d6bSBaptiste Daroussin 	/* Found a matching page. */
388*61d06d6bSBaptiste Daroussin 
389*61d06d6bSBaptiste Daroussin 	res.page = (struct page *)dbm_get(*pp++) - pages;
390*61d06d6bSBaptiste Daroussin 	return res;
391*61d06d6bSBaptiste Daroussin }
392*61d06d6bSBaptiste Daroussin 
393*61d06d6bSBaptiste Daroussin 
394*61d06d6bSBaptiste Daroussin /*** functions for handling macros ************************************/
395*61d06d6bSBaptiste Daroussin 
396*61d06d6bSBaptiste Daroussin int32_t
397*61d06d6bSBaptiste Daroussin dbm_macro_count(int32_t im)
398*61d06d6bSBaptiste Daroussin {
399*61d06d6bSBaptiste Daroussin 	assert(im >= 0);
400*61d06d6bSBaptiste Daroussin 	assert(im < MACRO_MAX);
401*61d06d6bSBaptiste Daroussin 	return nvals[im];
402*61d06d6bSBaptiste Daroussin }
403*61d06d6bSBaptiste Daroussin 
404*61d06d6bSBaptiste Daroussin struct dbm_macro *
405*61d06d6bSBaptiste Daroussin dbm_macro_get(int32_t im, int32_t iv)
406*61d06d6bSBaptiste Daroussin {
407*61d06d6bSBaptiste Daroussin 	static struct dbm_macro macro;
408*61d06d6bSBaptiste Daroussin 
409*61d06d6bSBaptiste Daroussin 	assert(im >= 0);
410*61d06d6bSBaptiste Daroussin 	assert(im < MACRO_MAX);
411*61d06d6bSBaptiste Daroussin 	assert(iv >= 0);
412*61d06d6bSBaptiste Daroussin 	assert(iv < nvals[im]);
413*61d06d6bSBaptiste Daroussin 	macro.value = dbm_get(macros[im][iv].value);
414*61d06d6bSBaptiste Daroussin 	macro.pp = dbm_get(macros[im][iv].pages);
415*61d06d6bSBaptiste Daroussin 	return &macro;
416*61d06d6bSBaptiste Daroussin }
417*61d06d6bSBaptiste Daroussin 
418*61d06d6bSBaptiste Daroussin /*
419*61d06d6bSBaptiste Daroussin  * Filtered iteration over macro entries.
420*61d06d6bSBaptiste Daroussin  */
421*61d06d6bSBaptiste Daroussin void
422*61d06d6bSBaptiste Daroussin dbm_macro_bypage(int32_t im, int32_t ip)
423*61d06d6bSBaptiste Daroussin {
424*61d06d6bSBaptiste Daroussin 	assert(im >= 0);
425*61d06d6bSBaptiste Daroussin 	assert(im < MACRO_MAX);
426*61d06d6bSBaptiste Daroussin 	assert(ip != 0);
427*61d06d6bSBaptiste Daroussin 	macro_bypage(im, ip);
428*61d06d6bSBaptiste Daroussin }
429*61d06d6bSBaptiste Daroussin 
430*61d06d6bSBaptiste Daroussin char *
431*61d06d6bSBaptiste Daroussin dbm_macro_next(void)
432*61d06d6bSBaptiste Daroussin {
433*61d06d6bSBaptiste Daroussin 	return macro_bypage(MACRO_MAX, 0);
434*61d06d6bSBaptiste Daroussin }
435*61d06d6bSBaptiste Daroussin 
436*61d06d6bSBaptiste Daroussin static char *
437*61d06d6bSBaptiste Daroussin macro_bypage(int32_t arg_im, int32_t arg_ip)
438*61d06d6bSBaptiste Daroussin {
439*61d06d6bSBaptiste Daroussin 	static const int32_t	*pp;
440*61d06d6bSBaptiste Daroussin 	static int32_t		 im, ip, iv;
441*61d06d6bSBaptiste Daroussin 
442*61d06d6bSBaptiste Daroussin 	/* Initialize for a new iteration. */
443*61d06d6bSBaptiste Daroussin 
444*61d06d6bSBaptiste Daroussin 	if (arg_im < MACRO_MAX && arg_ip != 0) {
445*61d06d6bSBaptiste Daroussin 		im = arg_im;
446*61d06d6bSBaptiste Daroussin 		ip = arg_ip;
447*61d06d6bSBaptiste Daroussin 		pp = dbm_get(macros[im]->pages);
448*61d06d6bSBaptiste Daroussin 		iv = 0;
449*61d06d6bSBaptiste Daroussin 		return NULL;
450*61d06d6bSBaptiste Daroussin 	}
451*61d06d6bSBaptiste Daroussin 	if (im >= MACRO_MAX)
452*61d06d6bSBaptiste Daroussin 		return NULL;
453*61d06d6bSBaptiste Daroussin 
454*61d06d6bSBaptiste Daroussin 	/* Search for the next value. */
455*61d06d6bSBaptiste Daroussin 
456*61d06d6bSBaptiste Daroussin 	while (iv < nvals[im]) {
457*61d06d6bSBaptiste Daroussin 		if (*pp == ip)
458*61d06d6bSBaptiste Daroussin 			break;
459*61d06d6bSBaptiste Daroussin 		if (*pp == 0)
460*61d06d6bSBaptiste Daroussin 			iv++;
461*61d06d6bSBaptiste Daroussin 		pp++;
462*61d06d6bSBaptiste Daroussin 	}
463*61d06d6bSBaptiste Daroussin 
464*61d06d6bSBaptiste Daroussin 	/* Reached the end without a match. */
465*61d06d6bSBaptiste Daroussin 
466*61d06d6bSBaptiste Daroussin 	if (iv == nvals[im]) {
467*61d06d6bSBaptiste Daroussin 		im = MACRO_MAX;
468*61d06d6bSBaptiste Daroussin 		ip = 0;
469*61d06d6bSBaptiste Daroussin 		pp = NULL;
470*61d06d6bSBaptiste Daroussin 		return NULL;
471*61d06d6bSBaptiste Daroussin 	}
472*61d06d6bSBaptiste Daroussin 
473*61d06d6bSBaptiste Daroussin 	/* Found a match; skip the remaining pages of this entry. */
474*61d06d6bSBaptiste Daroussin 
475*61d06d6bSBaptiste Daroussin 	if (++iv < nvals[im])
476*61d06d6bSBaptiste Daroussin 		while (*pp++ != 0)
477*61d06d6bSBaptiste Daroussin 			continue;
478*61d06d6bSBaptiste Daroussin 
479*61d06d6bSBaptiste Daroussin 	return dbm_get(macros[im][iv - 1].value);
480*61d06d6bSBaptiste Daroussin }
481