1*99db7d0eSSascha Wildner /* $Id: dbm.c,v 1.7 2019/07/01 22:56:24 schwarze Exp $ */
254ba9607SSascha Wildner /*
354ba9607SSascha Wildner * Copyright (c) 2016 Ingo Schwarze <schwarze@openbsd.org>
454ba9607SSascha Wildner *
554ba9607SSascha Wildner * Permission to use, copy, modify, and distribute this software for any
654ba9607SSascha Wildner * purpose with or without fee is hereby granted, provided that the above
754ba9607SSascha Wildner * copyright notice and this permission notice appear in all copies.
854ba9607SSascha Wildner *
954ba9607SSascha Wildner * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1054ba9607SSascha Wildner * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1154ba9607SSascha Wildner * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1254ba9607SSascha Wildner * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1354ba9607SSascha Wildner * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1454ba9607SSascha Wildner * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1554ba9607SSascha Wildner * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1654ba9607SSascha Wildner *
1754ba9607SSascha Wildner * Map-based version of the mandoc database, for read-only access.
1854ba9607SSascha Wildner * The interface is defined in "dbm.h".
1954ba9607SSascha Wildner */
2054ba9607SSascha Wildner #include "config.h"
2154ba9607SSascha Wildner
2254ba9607SSascha Wildner #include <assert.h>
2354ba9607SSascha Wildner #if HAVE_ENDIAN
2454ba9607SSascha Wildner #include <endian.h>
2554ba9607SSascha Wildner #elif HAVE_SYS_ENDIAN
2654ba9607SSascha Wildner #include <sys/endian.h>
2754ba9607SSascha Wildner #elif HAVE_NTOHL
2854ba9607SSascha Wildner #include <arpa/inet.h>
2954ba9607SSascha Wildner #endif
3054ba9607SSascha Wildner #if HAVE_ERR
3154ba9607SSascha Wildner #include <err.h>
3254ba9607SSascha Wildner #endif
3354ba9607SSascha Wildner #include <errno.h>
3454ba9607SSascha Wildner #include <regex.h>
3554ba9607SSascha Wildner #include <stdint.h>
3654ba9607SSascha Wildner #include <stdio.h>
3754ba9607SSascha Wildner #include <stdlib.h>
3854ba9607SSascha Wildner #include <string.h>
3954ba9607SSascha Wildner
4054ba9607SSascha Wildner #include "mansearch.h"
4154ba9607SSascha Wildner #include "dbm_map.h"
4254ba9607SSascha Wildner #include "dbm.h"
4354ba9607SSascha Wildner
4454ba9607SSascha Wildner struct macro {
4554ba9607SSascha Wildner int32_t value;
4654ba9607SSascha Wildner int32_t pages;
4754ba9607SSascha Wildner };
4854ba9607SSascha Wildner
4954ba9607SSascha Wildner struct page {
5054ba9607SSascha Wildner int32_t name;
5154ba9607SSascha Wildner int32_t sect;
5254ba9607SSascha Wildner int32_t arch;
5354ba9607SSascha Wildner int32_t desc;
5454ba9607SSascha Wildner int32_t file;
5554ba9607SSascha Wildner };
5654ba9607SSascha Wildner
5754ba9607SSascha Wildner enum iter {
5854ba9607SSascha Wildner ITER_NONE = 0,
5954ba9607SSascha Wildner ITER_NAME,
6054ba9607SSascha Wildner ITER_SECT,
6154ba9607SSascha Wildner ITER_ARCH,
6254ba9607SSascha Wildner ITER_DESC,
6354ba9607SSascha Wildner ITER_MACRO
6454ba9607SSascha Wildner };
6554ba9607SSascha Wildner
6654ba9607SSascha Wildner static struct macro *macros[MACRO_MAX];
6754ba9607SSascha Wildner static int32_t nvals[MACRO_MAX];
6854ba9607SSascha Wildner static struct page *pages;
6954ba9607SSascha Wildner static int32_t npages;
7054ba9607SSascha Wildner static enum iter iteration;
7154ba9607SSascha Wildner
7254ba9607SSascha Wildner static struct dbm_res page_bytitle(enum iter, const struct dbm_match *);
7354ba9607SSascha Wildner static struct dbm_res page_byarch(const struct dbm_match *);
7454ba9607SSascha Wildner static struct dbm_res page_bymacro(int32_t, const struct dbm_match *);
7554ba9607SSascha Wildner static char *macro_bypage(int32_t, int32_t);
7654ba9607SSascha Wildner
7754ba9607SSascha Wildner
7854ba9607SSascha Wildner /*** top level functions **********************************************/
7954ba9607SSascha Wildner
8054ba9607SSascha Wildner /*
8154ba9607SSascha Wildner * Open a disk-based mandoc database for read-only access.
8254ba9607SSascha Wildner * Map the pages and macros[] arrays.
8354ba9607SSascha Wildner * Return 0 on success. Return -1 and set errno on failure.
8454ba9607SSascha Wildner */
8554ba9607SSascha Wildner int
dbm_open(const char * fname)8654ba9607SSascha Wildner dbm_open(const char *fname)
8754ba9607SSascha Wildner {
8854ba9607SSascha Wildner const int32_t *mp, *ep;
8954ba9607SSascha Wildner int32_t im;
9054ba9607SSascha Wildner
9154ba9607SSascha Wildner if (dbm_map(fname) == -1)
9254ba9607SSascha Wildner return -1;
9354ba9607SSascha Wildner
9454ba9607SSascha Wildner if ((npages = be32toh(*dbm_getint(4))) < 0) {
9554ba9607SSascha Wildner warnx("dbm_open(%s): Invalid number of pages: %d",
9654ba9607SSascha Wildner fname, npages);
9754ba9607SSascha Wildner goto fail;
9854ba9607SSascha Wildner }
9954ba9607SSascha Wildner pages = (struct page *)dbm_getint(5);
10054ba9607SSascha Wildner
10154ba9607SSascha Wildner if ((mp = dbm_get(*dbm_getint(2))) == NULL) {
10254ba9607SSascha Wildner warnx("dbm_open(%s): Invalid offset of macros array", fname);
10354ba9607SSascha Wildner goto fail;
10454ba9607SSascha Wildner }
10554ba9607SSascha Wildner if (be32toh(*mp) != MACRO_MAX) {
10654ba9607SSascha Wildner warnx("dbm_open(%s): Invalid number of macros: %d",
10754ba9607SSascha Wildner fname, be32toh(*mp));
10854ba9607SSascha Wildner goto fail;
10954ba9607SSascha Wildner }
11054ba9607SSascha Wildner for (im = 0; im < MACRO_MAX; im++) {
11154ba9607SSascha Wildner if ((ep = dbm_get(*++mp)) == NULL) {
11254ba9607SSascha Wildner warnx("dbm_open(%s): Invalid offset of macro %d",
11354ba9607SSascha Wildner fname, im);
11454ba9607SSascha Wildner goto fail;
11554ba9607SSascha Wildner }
11654ba9607SSascha Wildner nvals[im] = be32toh(*ep);
11754ba9607SSascha Wildner macros[im] = (struct macro *)++ep;
11854ba9607SSascha Wildner }
11954ba9607SSascha Wildner return 0;
12054ba9607SSascha Wildner
12154ba9607SSascha Wildner fail:
12254ba9607SSascha Wildner dbm_unmap();
12354ba9607SSascha Wildner errno = EFTYPE;
12454ba9607SSascha Wildner return -1;
12554ba9607SSascha Wildner }
12654ba9607SSascha Wildner
12754ba9607SSascha Wildner void
dbm_close(void)12854ba9607SSascha Wildner dbm_close(void)
12954ba9607SSascha Wildner {
13054ba9607SSascha Wildner dbm_unmap();
13154ba9607SSascha Wildner }
13254ba9607SSascha Wildner
13354ba9607SSascha Wildner
13454ba9607SSascha Wildner /*** functions for handling pages *************************************/
13554ba9607SSascha Wildner
13654ba9607SSascha Wildner int32_t
dbm_page_count(void)13754ba9607SSascha Wildner dbm_page_count(void)
13854ba9607SSascha Wildner {
13954ba9607SSascha Wildner return npages;
14054ba9607SSascha Wildner }
14154ba9607SSascha Wildner
14254ba9607SSascha Wildner /*
14354ba9607SSascha Wildner * Give the caller pointers to the data for one manual page.
14454ba9607SSascha Wildner */
14554ba9607SSascha Wildner struct dbm_page *
dbm_page_get(int32_t ip)14654ba9607SSascha Wildner dbm_page_get(int32_t ip)
14754ba9607SSascha Wildner {
14854ba9607SSascha Wildner static struct dbm_page res;
14954ba9607SSascha Wildner
15054ba9607SSascha Wildner assert(ip >= 0);
15154ba9607SSascha Wildner assert(ip < npages);
15254ba9607SSascha Wildner res.name = dbm_get(pages[ip].name);
15354ba9607SSascha Wildner if (res.name == NULL)
15454ba9607SSascha Wildner res.name = "(NULL)\0";
15554ba9607SSascha Wildner res.sect = dbm_get(pages[ip].sect);
15654ba9607SSascha Wildner if (res.sect == NULL)
15754ba9607SSascha Wildner res.sect = "(NULL)\0";
15854ba9607SSascha Wildner res.arch = pages[ip].arch ? dbm_get(pages[ip].arch) : NULL;
15954ba9607SSascha Wildner res.desc = dbm_get(pages[ip].desc);
16054ba9607SSascha Wildner if (res.desc == NULL)
16154ba9607SSascha Wildner res.desc = "(NULL)";
16254ba9607SSascha Wildner res.file = dbm_get(pages[ip].file);
16354ba9607SSascha Wildner if (res.file == NULL)
16454ba9607SSascha Wildner res.file = " (NULL)\0";
16554ba9607SSascha Wildner res.addr = dbm_addr(pages + ip);
16654ba9607SSascha Wildner return &res;
16754ba9607SSascha Wildner }
16854ba9607SSascha Wildner
16954ba9607SSascha Wildner /*
17054ba9607SSascha Wildner * Functions to start filtered iterations over manual pages.
17154ba9607SSascha Wildner */
17254ba9607SSascha Wildner void
dbm_page_byname(const struct dbm_match * match)17354ba9607SSascha Wildner dbm_page_byname(const struct dbm_match *match)
17454ba9607SSascha Wildner {
17554ba9607SSascha Wildner assert(match != NULL);
17654ba9607SSascha Wildner page_bytitle(ITER_NAME, match);
17754ba9607SSascha Wildner }
17854ba9607SSascha Wildner
17954ba9607SSascha Wildner void
dbm_page_bysect(const struct dbm_match * match)18054ba9607SSascha Wildner dbm_page_bysect(const struct dbm_match *match)
18154ba9607SSascha Wildner {
18254ba9607SSascha Wildner assert(match != NULL);
18354ba9607SSascha Wildner page_bytitle(ITER_SECT, match);
18454ba9607SSascha Wildner }
18554ba9607SSascha Wildner
18654ba9607SSascha Wildner void
dbm_page_byarch(const struct dbm_match * match)18754ba9607SSascha Wildner dbm_page_byarch(const struct dbm_match *match)
18854ba9607SSascha Wildner {
18954ba9607SSascha Wildner assert(match != NULL);
19054ba9607SSascha Wildner page_byarch(match);
19154ba9607SSascha Wildner }
19254ba9607SSascha Wildner
19354ba9607SSascha Wildner void
dbm_page_bydesc(const struct dbm_match * match)19454ba9607SSascha Wildner dbm_page_bydesc(const struct dbm_match *match)
19554ba9607SSascha Wildner {
19654ba9607SSascha Wildner assert(match != NULL);
19754ba9607SSascha Wildner page_bytitle(ITER_DESC, match);
19854ba9607SSascha Wildner }
19954ba9607SSascha Wildner
20054ba9607SSascha Wildner void
dbm_page_bymacro(int32_t im,const struct dbm_match * match)20154ba9607SSascha Wildner dbm_page_bymacro(int32_t im, const struct dbm_match *match)
20254ba9607SSascha Wildner {
20354ba9607SSascha Wildner assert(im >= 0);
20454ba9607SSascha Wildner assert(im < MACRO_MAX);
20554ba9607SSascha Wildner assert(match != NULL);
20654ba9607SSascha Wildner page_bymacro(im, match);
20754ba9607SSascha Wildner }
20854ba9607SSascha Wildner
20954ba9607SSascha Wildner /*
21054ba9607SSascha Wildner * Return the number of the next manual page in the current iteration.
21154ba9607SSascha Wildner */
21254ba9607SSascha Wildner struct dbm_res
dbm_page_next(void)21354ba9607SSascha Wildner dbm_page_next(void)
21454ba9607SSascha Wildner {
21554ba9607SSascha Wildner struct dbm_res res = {-1, 0};
21654ba9607SSascha Wildner
21754ba9607SSascha Wildner switch(iteration) {
21854ba9607SSascha Wildner case ITER_NONE:
21954ba9607SSascha Wildner return res;
22054ba9607SSascha Wildner case ITER_ARCH:
22154ba9607SSascha Wildner return page_byarch(NULL);
22254ba9607SSascha Wildner case ITER_MACRO:
22354ba9607SSascha Wildner return page_bymacro(0, NULL);
22454ba9607SSascha Wildner default:
22554ba9607SSascha Wildner return page_bytitle(iteration, NULL);
22654ba9607SSascha Wildner }
22754ba9607SSascha Wildner }
22854ba9607SSascha Wildner
22954ba9607SSascha Wildner /*
23054ba9607SSascha Wildner * Functions implementing the iteration over manual pages.
23154ba9607SSascha Wildner */
23254ba9607SSascha Wildner static struct dbm_res
page_bytitle(enum iter arg_iter,const struct dbm_match * arg_match)23354ba9607SSascha Wildner page_bytitle(enum iter arg_iter, const struct dbm_match *arg_match)
23454ba9607SSascha Wildner {
23554ba9607SSascha Wildner static const struct dbm_match *match;
23654ba9607SSascha Wildner static const char *cp;
23754ba9607SSascha Wildner static int32_t ip;
23854ba9607SSascha Wildner struct dbm_res res = {-1, 0};
23954ba9607SSascha Wildner
24054ba9607SSascha Wildner assert(arg_iter == ITER_NAME || arg_iter == ITER_DESC ||
24154ba9607SSascha Wildner arg_iter == ITER_SECT);
24254ba9607SSascha Wildner
24354ba9607SSascha Wildner /* Initialize for a new iteration. */
24454ba9607SSascha Wildner
24554ba9607SSascha Wildner if (arg_match != NULL) {
24654ba9607SSascha Wildner iteration = arg_iter;
24754ba9607SSascha Wildner match = arg_match;
24854ba9607SSascha Wildner switch (iteration) {
24954ba9607SSascha Wildner case ITER_NAME:
25054ba9607SSascha Wildner cp = dbm_get(pages[0].name);
25154ba9607SSascha Wildner break;
25254ba9607SSascha Wildner case ITER_SECT:
25354ba9607SSascha Wildner cp = dbm_get(pages[0].sect);
25454ba9607SSascha Wildner break;
25554ba9607SSascha Wildner case ITER_DESC:
25654ba9607SSascha Wildner cp = dbm_get(pages[0].desc);
25754ba9607SSascha Wildner break;
25854ba9607SSascha Wildner default:
25954ba9607SSascha Wildner abort();
26054ba9607SSascha Wildner }
26154ba9607SSascha Wildner if (cp == NULL) {
26254ba9607SSascha Wildner iteration = ITER_NONE;
26354ba9607SSascha Wildner match = NULL;
26454ba9607SSascha Wildner cp = NULL;
26554ba9607SSascha Wildner ip = npages;
26654ba9607SSascha Wildner } else
26754ba9607SSascha Wildner ip = 0;
26854ba9607SSascha Wildner return res;
26954ba9607SSascha Wildner }
27054ba9607SSascha Wildner
27154ba9607SSascha Wildner /* Search for a name. */
27254ba9607SSascha Wildner
27354ba9607SSascha Wildner while (ip < npages) {
27454ba9607SSascha Wildner if (iteration == ITER_NAME)
27554ba9607SSascha Wildner cp++;
27654ba9607SSascha Wildner if (dbm_match(match, cp))
27754ba9607SSascha Wildner break;
27854ba9607SSascha Wildner cp = strchr(cp, '\0') + 1;
27954ba9607SSascha Wildner if (iteration == ITER_DESC)
28054ba9607SSascha Wildner ip++;
28154ba9607SSascha Wildner else if (*cp == '\0') {
28254ba9607SSascha Wildner cp++;
28354ba9607SSascha Wildner ip++;
28454ba9607SSascha Wildner }
28554ba9607SSascha Wildner }
28654ba9607SSascha Wildner
28754ba9607SSascha Wildner /* Reached the end without a match. */
28854ba9607SSascha Wildner
28954ba9607SSascha Wildner if (ip == npages) {
29054ba9607SSascha Wildner iteration = ITER_NONE;
29154ba9607SSascha Wildner match = NULL;
29254ba9607SSascha Wildner cp = NULL;
29354ba9607SSascha Wildner return res;
29454ba9607SSascha Wildner }
29554ba9607SSascha Wildner
29654ba9607SSascha Wildner /* Found a match; save the quality for later retrieval. */
29754ba9607SSascha Wildner
29854ba9607SSascha Wildner res.page = ip;
29954ba9607SSascha Wildner res.bits = iteration == ITER_NAME ? cp[-1] : 0;
30054ba9607SSascha Wildner
30154ba9607SSascha Wildner /* Skip the remaining names of this page. */
30254ba9607SSascha Wildner
30354ba9607SSascha Wildner if (++ip < npages) {
30454ba9607SSascha Wildner do {
30554ba9607SSascha Wildner cp++;
30654ba9607SSascha Wildner } while (cp[-1] != '\0' ||
30754ba9607SSascha Wildner (iteration != ITER_DESC && cp[-2] != '\0'));
30854ba9607SSascha Wildner }
30954ba9607SSascha Wildner return res;
31054ba9607SSascha Wildner }
31154ba9607SSascha Wildner
31254ba9607SSascha Wildner static struct dbm_res
page_byarch(const struct dbm_match * arg_match)31354ba9607SSascha Wildner page_byarch(const struct dbm_match *arg_match)
31454ba9607SSascha Wildner {
31554ba9607SSascha Wildner static const struct dbm_match *match;
31654ba9607SSascha Wildner struct dbm_res res = {-1, 0};
31754ba9607SSascha Wildner static int32_t ip;
31854ba9607SSascha Wildner const char *cp;
31954ba9607SSascha Wildner
32054ba9607SSascha Wildner /* Initialize for a new iteration. */
32154ba9607SSascha Wildner
32254ba9607SSascha Wildner if (arg_match != NULL) {
32354ba9607SSascha Wildner iteration = ITER_ARCH;
32454ba9607SSascha Wildner match = arg_match;
32554ba9607SSascha Wildner ip = 0;
32654ba9607SSascha Wildner return res;
32754ba9607SSascha Wildner }
32854ba9607SSascha Wildner
32954ba9607SSascha Wildner /* Search for an architecture. */
33054ba9607SSascha Wildner
33154ba9607SSascha Wildner for ( ; ip < npages; ip++)
33254ba9607SSascha Wildner if (pages[ip].arch)
33354ba9607SSascha Wildner for (cp = dbm_get(pages[ip].arch);
33454ba9607SSascha Wildner *cp != '\0';
33554ba9607SSascha Wildner cp = strchr(cp, '\0') + 1)
33654ba9607SSascha Wildner if (dbm_match(match, cp)) {
33754ba9607SSascha Wildner res.page = ip++;
33854ba9607SSascha Wildner return res;
33954ba9607SSascha Wildner }
34054ba9607SSascha Wildner
34154ba9607SSascha Wildner /* Reached the end without a match. */
34254ba9607SSascha Wildner
34354ba9607SSascha Wildner iteration = ITER_NONE;
34454ba9607SSascha Wildner match = NULL;
34554ba9607SSascha Wildner return res;
34654ba9607SSascha Wildner }
34754ba9607SSascha Wildner
34854ba9607SSascha Wildner static struct dbm_res
page_bymacro(int32_t arg_im,const struct dbm_match * arg_match)34954ba9607SSascha Wildner page_bymacro(int32_t arg_im, const struct dbm_match *arg_match)
35054ba9607SSascha Wildner {
35154ba9607SSascha Wildner static const struct dbm_match *match;
35254ba9607SSascha Wildner static const int32_t *pp;
35354ba9607SSascha Wildner static const char *cp;
35454ba9607SSascha Wildner static int32_t im, iv;
35554ba9607SSascha Wildner struct dbm_res res = {-1, 0};
35654ba9607SSascha Wildner
35754ba9607SSascha Wildner assert(im >= 0);
35854ba9607SSascha Wildner assert(im < MACRO_MAX);
35954ba9607SSascha Wildner
36054ba9607SSascha Wildner /* Initialize for a new iteration. */
36154ba9607SSascha Wildner
36254ba9607SSascha Wildner if (arg_match != NULL) {
36354ba9607SSascha Wildner iteration = ITER_MACRO;
36454ba9607SSascha Wildner match = arg_match;
36554ba9607SSascha Wildner im = arg_im;
36654ba9607SSascha Wildner cp = nvals[im] ? dbm_get(macros[im]->value) : NULL;
36754ba9607SSascha Wildner pp = NULL;
36854ba9607SSascha Wildner iv = -1;
36954ba9607SSascha Wildner return res;
37054ba9607SSascha Wildner }
37154ba9607SSascha Wildner if (iteration != ITER_MACRO)
37254ba9607SSascha Wildner return res;
37354ba9607SSascha Wildner
37454ba9607SSascha Wildner /* Find the next matching macro value. */
37554ba9607SSascha Wildner
37654ba9607SSascha Wildner while (pp == NULL || *pp == 0) {
37754ba9607SSascha Wildner if (++iv == nvals[im]) {
37854ba9607SSascha Wildner iteration = ITER_NONE;
37954ba9607SSascha Wildner return res;
38054ba9607SSascha Wildner }
38154ba9607SSascha Wildner if (iv)
38254ba9607SSascha Wildner cp = strchr(cp, '\0') + 1;
38354ba9607SSascha Wildner if (dbm_match(match, cp))
38454ba9607SSascha Wildner pp = dbm_get(macros[im][iv].pages);
38554ba9607SSascha Wildner }
38654ba9607SSascha Wildner
38754ba9607SSascha Wildner /* Found a matching page. */
38854ba9607SSascha Wildner
38954ba9607SSascha Wildner res.page = (struct page *)dbm_get(*pp++) - pages;
39054ba9607SSascha Wildner return res;
39154ba9607SSascha Wildner }
39254ba9607SSascha Wildner
39354ba9607SSascha Wildner
39454ba9607SSascha Wildner /*** functions for handling macros ************************************/
39554ba9607SSascha Wildner
39654ba9607SSascha Wildner int32_t
dbm_macro_count(int32_t im)39754ba9607SSascha Wildner dbm_macro_count(int32_t im)
39854ba9607SSascha Wildner {
39954ba9607SSascha Wildner assert(im >= 0);
40054ba9607SSascha Wildner assert(im < MACRO_MAX);
40154ba9607SSascha Wildner return nvals[im];
40254ba9607SSascha Wildner }
40354ba9607SSascha Wildner
40454ba9607SSascha Wildner struct dbm_macro *
dbm_macro_get(int32_t im,int32_t iv)40554ba9607SSascha Wildner dbm_macro_get(int32_t im, int32_t iv)
40654ba9607SSascha Wildner {
40754ba9607SSascha Wildner static struct dbm_macro macro;
40854ba9607SSascha Wildner
40954ba9607SSascha Wildner assert(im >= 0);
41054ba9607SSascha Wildner assert(im < MACRO_MAX);
41154ba9607SSascha Wildner assert(iv >= 0);
41254ba9607SSascha Wildner assert(iv < nvals[im]);
41354ba9607SSascha Wildner macro.value = dbm_get(macros[im][iv].value);
41454ba9607SSascha Wildner macro.pp = dbm_get(macros[im][iv].pages);
41554ba9607SSascha Wildner return ¯o;
41654ba9607SSascha Wildner }
41754ba9607SSascha Wildner
41854ba9607SSascha Wildner /*
41954ba9607SSascha Wildner * Filtered iteration over macro entries.
42054ba9607SSascha Wildner */
42154ba9607SSascha Wildner void
dbm_macro_bypage(int32_t im,int32_t ip)42254ba9607SSascha Wildner dbm_macro_bypage(int32_t im, int32_t ip)
42354ba9607SSascha Wildner {
42454ba9607SSascha Wildner assert(im >= 0);
42554ba9607SSascha Wildner assert(im < MACRO_MAX);
42654ba9607SSascha Wildner assert(ip != 0);
42754ba9607SSascha Wildner macro_bypage(im, ip);
42854ba9607SSascha Wildner }
42954ba9607SSascha Wildner
43054ba9607SSascha Wildner char *
dbm_macro_next(void)43154ba9607SSascha Wildner dbm_macro_next(void)
43254ba9607SSascha Wildner {
43354ba9607SSascha Wildner return macro_bypage(MACRO_MAX, 0);
43454ba9607SSascha Wildner }
43554ba9607SSascha Wildner
43654ba9607SSascha Wildner static char *
macro_bypage(int32_t arg_im,int32_t arg_ip)43754ba9607SSascha Wildner macro_bypage(int32_t arg_im, int32_t arg_ip)
43854ba9607SSascha Wildner {
43954ba9607SSascha Wildner static const int32_t *pp;
44054ba9607SSascha Wildner static int32_t im, ip, iv;
44154ba9607SSascha Wildner
44254ba9607SSascha Wildner /* Initialize for a new iteration. */
44354ba9607SSascha Wildner
44454ba9607SSascha Wildner if (arg_im < MACRO_MAX && arg_ip != 0) {
44554ba9607SSascha Wildner im = arg_im;
44654ba9607SSascha Wildner ip = arg_ip;
44754ba9607SSascha Wildner pp = dbm_get(macros[im]->pages);
44854ba9607SSascha Wildner iv = 0;
44954ba9607SSascha Wildner return NULL;
45054ba9607SSascha Wildner }
45154ba9607SSascha Wildner if (im >= MACRO_MAX)
45254ba9607SSascha Wildner return NULL;
45354ba9607SSascha Wildner
45454ba9607SSascha Wildner /* Search for the next value. */
45554ba9607SSascha Wildner
45654ba9607SSascha Wildner while (iv < nvals[im]) {
45754ba9607SSascha Wildner if (*pp == ip)
45854ba9607SSascha Wildner break;
45954ba9607SSascha Wildner if (*pp == 0)
46054ba9607SSascha Wildner iv++;
46154ba9607SSascha Wildner pp++;
46254ba9607SSascha Wildner }
46354ba9607SSascha Wildner
46454ba9607SSascha Wildner /* Reached the end without a match. */
46554ba9607SSascha Wildner
46654ba9607SSascha Wildner if (iv == nvals[im]) {
46754ba9607SSascha Wildner im = MACRO_MAX;
46854ba9607SSascha Wildner ip = 0;
46954ba9607SSascha Wildner pp = NULL;
47054ba9607SSascha Wildner return NULL;
47154ba9607SSascha Wildner }
47254ba9607SSascha Wildner
47354ba9607SSascha Wildner /* Found a match; skip the remaining pages of this entry. */
47454ba9607SSascha Wildner
47554ba9607SSascha Wildner if (++iv < nvals[im])
47654ba9607SSascha Wildner while (*pp++ != 0)
47754ba9607SSascha Wildner continue;
47854ba9607SSascha Wildner
47954ba9607SSascha Wildner return dbm_get(macros[im][iv - 1].value);
48054ba9607SSascha Wildner }
481