1*45a5aec3SBaptiste Daroussin /* $Id: dbm.c,v 1.7 2019/07/01 22:56:24 schwarze Exp $ */
261d06d6bSBaptiste Daroussin /*
361d06d6bSBaptiste Daroussin * Copyright (c) 2016 Ingo Schwarze <schwarze@openbsd.org>
461d06d6bSBaptiste Daroussin *
561d06d6bSBaptiste Daroussin * Permission to use, copy, modify, and distribute this software for any
661d06d6bSBaptiste Daroussin * purpose with or without fee is hereby granted, provided that the above
761d06d6bSBaptiste Daroussin * copyright notice and this permission notice appear in all copies.
861d06d6bSBaptiste Daroussin *
961d06d6bSBaptiste Daroussin * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1061d06d6bSBaptiste Daroussin * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1161d06d6bSBaptiste Daroussin * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1261d06d6bSBaptiste Daroussin * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1361d06d6bSBaptiste Daroussin * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1461d06d6bSBaptiste Daroussin * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1561d06d6bSBaptiste Daroussin * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1661d06d6bSBaptiste Daroussin *
1761d06d6bSBaptiste Daroussin * Map-based version of the mandoc database, for read-only access.
1861d06d6bSBaptiste Daroussin * The interface is defined in "dbm.h".
1961d06d6bSBaptiste Daroussin */
2061d06d6bSBaptiste Daroussin #include "config.h"
2161d06d6bSBaptiste Daroussin
2261d06d6bSBaptiste Daroussin #include <assert.h>
2361d06d6bSBaptiste Daroussin #if HAVE_ENDIAN
2461d06d6bSBaptiste Daroussin #include <endian.h>
2561d06d6bSBaptiste Daroussin #elif HAVE_SYS_ENDIAN
2661d06d6bSBaptiste Daroussin #include <sys/endian.h>
2761d06d6bSBaptiste Daroussin #elif HAVE_NTOHL
2861d06d6bSBaptiste Daroussin #include <arpa/inet.h>
2961d06d6bSBaptiste Daroussin #endif
3061d06d6bSBaptiste Daroussin #if HAVE_ERR
3161d06d6bSBaptiste Daroussin #include <err.h>
3261d06d6bSBaptiste Daroussin #endif
3361d06d6bSBaptiste Daroussin #include <errno.h>
3461d06d6bSBaptiste Daroussin #include <regex.h>
3561d06d6bSBaptiste Daroussin #include <stdint.h>
3661d06d6bSBaptiste Daroussin #include <stdio.h>
3761d06d6bSBaptiste Daroussin #include <stdlib.h>
3861d06d6bSBaptiste Daroussin #include <string.h>
3961d06d6bSBaptiste Daroussin
4061d06d6bSBaptiste Daroussin #include "mansearch.h"
4161d06d6bSBaptiste Daroussin #include "dbm_map.h"
4261d06d6bSBaptiste Daroussin #include "dbm.h"
4361d06d6bSBaptiste Daroussin
4461d06d6bSBaptiste Daroussin struct macro {
4561d06d6bSBaptiste Daroussin int32_t value;
4661d06d6bSBaptiste Daroussin int32_t pages;
4761d06d6bSBaptiste Daroussin };
4861d06d6bSBaptiste Daroussin
4961d06d6bSBaptiste Daroussin struct page {
5061d06d6bSBaptiste Daroussin int32_t name;
5161d06d6bSBaptiste Daroussin int32_t sect;
5261d06d6bSBaptiste Daroussin int32_t arch;
5361d06d6bSBaptiste Daroussin int32_t desc;
5461d06d6bSBaptiste Daroussin int32_t file;
5561d06d6bSBaptiste Daroussin };
5661d06d6bSBaptiste Daroussin
5761d06d6bSBaptiste Daroussin enum iter {
5861d06d6bSBaptiste Daroussin ITER_NONE = 0,
5961d06d6bSBaptiste Daroussin ITER_NAME,
6061d06d6bSBaptiste Daroussin ITER_SECT,
6161d06d6bSBaptiste Daroussin ITER_ARCH,
6261d06d6bSBaptiste Daroussin ITER_DESC,
6361d06d6bSBaptiste Daroussin ITER_MACRO
6461d06d6bSBaptiste Daroussin };
6561d06d6bSBaptiste Daroussin
6661d06d6bSBaptiste Daroussin static struct macro *macros[MACRO_MAX];
6761d06d6bSBaptiste Daroussin static int32_t nvals[MACRO_MAX];
6861d06d6bSBaptiste Daroussin static struct page *pages;
6961d06d6bSBaptiste Daroussin static int32_t npages;
7061d06d6bSBaptiste Daroussin static enum iter iteration;
7161d06d6bSBaptiste Daroussin
7261d06d6bSBaptiste Daroussin static struct dbm_res page_bytitle(enum iter, const struct dbm_match *);
7361d06d6bSBaptiste Daroussin static struct dbm_res page_byarch(const struct dbm_match *);
7461d06d6bSBaptiste Daroussin static struct dbm_res page_bymacro(int32_t, const struct dbm_match *);
7561d06d6bSBaptiste Daroussin static char *macro_bypage(int32_t, int32_t);
7661d06d6bSBaptiste Daroussin
7761d06d6bSBaptiste Daroussin
7861d06d6bSBaptiste Daroussin /*** top level functions **********************************************/
7961d06d6bSBaptiste Daroussin
8061d06d6bSBaptiste Daroussin /*
8161d06d6bSBaptiste Daroussin * Open a disk-based mandoc database for read-only access.
8261d06d6bSBaptiste Daroussin * Map the pages and macros[] arrays.
8361d06d6bSBaptiste Daroussin * Return 0 on success. Return -1 and set errno on failure.
8461d06d6bSBaptiste Daroussin */
8561d06d6bSBaptiste Daroussin int
dbm_open(const char * fname)8661d06d6bSBaptiste Daroussin dbm_open(const char *fname)
8761d06d6bSBaptiste Daroussin {
8861d06d6bSBaptiste Daroussin const int32_t *mp, *ep;
8961d06d6bSBaptiste Daroussin int32_t im;
9061d06d6bSBaptiste Daroussin
9161d06d6bSBaptiste Daroussin if (dbm_map(fname) == -1)
9261d06d6bSBaptiste Daroussin return -1;
9361d06d6bSBaptiste Daroussin
9461d06d6bSBaptiste Daroussin if ((npages = be32toh(*dbm_getint(4))) < 0) {
9561d06d6bSBaptiste Daroussin warnx("dbm_open(%s): Invalid number of pages: %d",
9661d06d6bSBaptiste Daroussin fname, npages);
9761d06d6bSBaptiste Daroussin goto fail;
9861d06d6bSBaptiste Daroussin }
9961d06d6bSBaptiste Daroussin pages = (struct page *)dbm_getint(5);
10061d06d6bSBaptiste Daroussin
10161d06d6bSBaptiste Daroussin if ((mp = dbm_get(*dbm_getint(2))) == NULL) {
10261d06d6bSBaptiste Daroussin warnx("dbm_open(%s): Invalid offset of macros array", fname);
10361d06d6bSBaptiste Daroussin goto fail;
10461d06d6bSBaptiste Daroussin }
10561d06d6bSBaptiste Daroussin if (be32toh(*mp) != MACRO_MAX) {
10661d06d6bSBaptiste Daroussin warnx("dbm_open(%s): Invalid number of macros: %d",
10761d06d6bSBaptiste Daroussin fname, be32toh(*mp));
10861d06d6bSBaptiste Daroussin goto fail;
10961d06d6bSBaptiste Daroussin }
11061d06d6bSBaptiste Daroussin for (im = 0; im < MACRO_MAX; im++) {
11161d06d6bSBaptiste Daroussin if ((ep = dbm_get(*++mp)) == NULL) {
11261d06d6bSBaptiste Daroussin warnx("dbm_open(%s): Invalid offset of macro %d",
11361d06d6bSBaptiste Daroussin fname, im);
11461d06d6bSBaptiste Daroussin goto fail;
11561d06d6bSBaptiste Daroussin }
11661d06d6bSBaptiste Daroussin nvals[im] = be32toh(*ep);
11761d06d6bSBaptiste Daroussin macros[im] = (struct macro *)++ep;
11861d06d6bSBaptiste Daroussin }
11961d06d6bSBaptiste Daroussin return 0;
12061d06d6bSBaptiste Daroussin
12161d06d6bSBaptiste Daroussin fail:
12261d06d6bSBaptiste Daroussin dbm_unmap();
12361d06d6bSBaptiste Daroussin errno = EFTYPE;
12461d06d6bSBaptiste Daroussin return -1;
12561d06d6bSBaptiste Daroussin }
12661d06d6bSBaptiste Daroussin
12761d06d6bSBaptiste Daroussin void
dbm_close(void)12861d06d6bSBaptiste Daroussin dbm_close(void)
12961d06d6bSBaptiste Daroussin {
13061d06d6bSBaptiste Daroussin dbm_unmap();
13161d06d6bSBaptiste Daroussin }
13261d06d6bSBaptiste Daroussin
13361d06d6bSBaptiste Daroussin
13461d06d6bSBaptiste Daroussin /*** functions for handling pages *************************************/
13561d06d6bSBaptiste Daroussin
13661d06d6bSBaptiste Daroussin int32_t
dbm_page_count(void)13761d06d6bSBaptiste Daroussin dbm_page_count(void)
13861d06d6bSBaptiste Daroussin {
13961d06d6bSBaptiste Daroussin return npages;
14061d06d6bSBaptiste Daroussin }
14161d06d6bSBaptiste Daroussin
14261d06d6bSBaptiste Daroussin /*
14361d06d6bSBaptiste Daroussin * Give the caller pointers to the data for one manual page.
14461d06d6bSBaptiste Daroussin */
14561d06d6bSBaptiste Daroussin struct dbm_page *
dbm_page_get(int32_t ip)14661d06d6bSBaptiste Daroussin dbm_page_get(int32_t ip)
14761d06d6bSBaptiste Daroussin {
14861d06d6bSBaptiste Daroussin static struct dbm_page res;
14961d06d6bSBaptiste Daroussin
15061d06d6bSBaptiste Daroussin assert(ip >= 0);
15161d06d6bSBaptiste Daroussin assert(ip < npages);
15261d06d6bSBaptiste Daroussin res.name = dbm_get(pages[ip].name);
15361d06d6bSBaptiste Daroussin if (res.name == NULL)
1547295610fSBaptiste Daroussin res.name = "(NULL)\0";
15561d06d6bSBaptiste Daroussin res.sect = dbm_get(pages[ip].sect);
15661d06d6bSBaptiste Daroussin if (res.sect == NULL)
1577295610fSBaptiste Daroussin res.sect = "(NULL)\0";
15861d06d6bSBaptiste Daroussin res.arch = pages[ip].arch ? dbm_get(pages[ip].arch) : NULL;
15961d06d6bSBaptiste Daroussin res.desc = dbm_get(pages[ip].desc);
16061d06d6bSBaptiste Daroussin if (res.desc == NULL)
16161d06d6bSBaptiste Daroussin res.desc = "(NULL)";
16261d06d6bSBaptiste Daroussin res.file = dbm_get(pages[ip].file);
16361d06d6bSBaptiste Daroussin if (res.file == NULL)
1647295610fSBaptiste Daroussin res.file = " (NULL)\0";
16561d06d6bSBaptiste Daroussin res.addr = dbm_addr(pages + ip);
16661d06d6bSBaptiste Daroussin return &res;
16761d06d6bSBaptiste Daroussin }
16861d06d6bSBaptiste Daroussin
16961d06d6bSBaptiste Daroussin /*
17061d06d6bSBaptiste Daroussin * Functions to start filtered iterations over manual pages.
17161d06d6bSBaptiste Daroussin */
17261d06d6bSBaptiste Daroussin void
dbm_page_byname(const struct dbm_match * match)17361d06d6bSBaptiste Daroussin dbm_page_byname(const struct dbm_match *match)
17461d06d6bSBaptiste Daroussin {
17561d06d6bSBaptiste Daroussin assert(match != NULL);
17661d06d6bSBaptiste Daroussin page_bytitle(ITER_NAME, match);
17761d06d6bSBaptiste Daroussin }
17861d06d6bSBaptiste Daroussin
17961d06d6bSBaptiste Daroussin void
dbm_page_bysect(const struct dbm_match * match)18061d06d6bSBaptiste Daroussin dbm_page_bysect(const struct dbm_match *match)
18161d06d6bSBaptiste Daroussin {
18261d06d6bSBaptiste Daroussin assert(match != NULL);
18361d06d6bSBaptiste Daroussin page_bytitle(ITER_SECT, match);
18461d06d6bSBaptiste Daroussin }
18561d06d6bSBaptiste Daroussin
18661d06d6bSBaptiste Daroussin void
dbm_page_byarch(const struct dbm_match * match)18761d06d6bSBaptiste Daroussin dbm_page_byarch(const struct dbm_match *match)
18861d06d6bSBaptiste Daroussin {
18961d06d6bSBaptiste Daroussin assert(match != NULL);
19061d06d6bSBaptiste Daroussin page_byarch(match);
19161d06d6bSBaptiste Daroussin }
19261d06d6bSBaptiste Daroussin
19361d06d6bSBaptiste Daroussin void
dbm_page_bydesc(const struct dbm_match * match)19461d06d6bSBaptiste Daroussin dbm_page_bydesc(const struct dbm_match *match)
19561d06d6bSBaptiste Daroussin {
19661d06d6bSBaptiste Daroussin assert(match != NULL);
19761d06d6bSBaptiste Daroussin page_bytitle(ITER_DESC, match);
19861d06d6bSBaptiste Daroussin }
19961d06d6bSBaptiste Daroussin
20061d06d6bSBaptiste Daroussin void
dbm_page_bymacro(int32_t im,const struct dbm_match * match)20161d06d6bSBaptiste Daroussin dbm_page_bymacro(int32_t im, const struct dbm_match *match)
20261d06d6bSBaptiste Daroussin {
20361d06d6bSBaptiste Daroussin assert(im >= 0);
20461d06d6bSBaptiste Daroussin assert(im < MACRO_MAX);
20561d06d6bSBaptiste Daroussin assert(match != NULL);
20661d06d6bSBaptiste Daroussin page_bymacro(im, match);
20761d06d6bSBaptiste Daroussin }
20861d06d6bSBaptiste Daroussin
20961d06d6bSBaptiste Daroussin /*
21061d06d6bSBaptiste Daroussin * Return the number of the next manual page in the current iteration.
21161d06d6bSBaptiste Daroussin */
21261d06d6bSBaptiste Daroussin struct dbm_res
dbm_page_next(void)21361d06d6bSBaptiste Daroussin dbm_page_next(void)
21461d06d6bSBaptiste Daroussin {
21561d06d6bSBaptiste Daroussin struct dbm_res res = {-1, 0};
21661d06d6bSBaptiste Daroussin
21761d06d6bSBaptiste Daroussin switch(iteration) {
21861d06d6bSBaptiste Daroussin case ITER_NONE:
21961d06d6bSBaptiste Daroussin return res;
22061d06d6bSBaptiste Daroussin case ITER_ARCH:
22161d06d6bSBaptiste Daroussin return page_byarch(NULL);
22261d06d6bSBaptiste Daroussin case ITER_MACRO:
22361d06d6bSBaptiste Daroussin return page_bymacro(0, NULL);
22461d06d6bSBaptiste Daroussin default:
22561d06d6bSBaptiste Daroussin return page_bytitle(iteration, NULL);
22661d06d6bSBaptiste Daroussin }
22761d06d6bSBaptiste Daroussin }
22861d06d6bSBaptiste Daroussin
22961d06d6bSBaptiste Daroussin /*
23061d06d6bSBaptiste Daroussin * Functions implementing the iteration over manual pages.
23161d06d6bSBaptiste Daroussin */
23261d06d6bSBaptiste Daroussin static struct dbm_res
page_bytitle(enum iter arg_iter,const struct dbm_match * arg_match)23361d06d6bSBaptiste Daroussin page_bytitle(enum iter arg_iter, const struct dbm_match *arg_match)
23461d06d6bSBaptiste Daroussin {
23561d06d6bSBaptiste Daroussin static const struct dbm_match *match;
23661d06d6bSBaptiste Daroussin static const char *cp;
23761d06d6bSBaptiste Daroussin static int32_t ip;
23861d06d6bSBaptiste Daroussin struct dbm_res res = {-1, 0};
23961d06d6bSBaptiste Daroussin
24061d06d6bSBaptiste Daroussin assert(arg_iter == ITER_NAME || arg_iter == ITER_DESC ||
24161d06d6bSBaptiste Daroussin arg_iter == ITER_SECT);
24261d06d6bSBaptiste Daroussin
24361d06d6bSBaptiste Daroussin /* Initialize for a new iteration. */
24461d06d6bSBaptiste Daroussin
24561d06d6bSBaptiste Daroussin if (arg_match != NULL) {
24661d06d6bSBaptiste Daroussin iteration = arg_iter;
24761d06d6bSBaptiste Daroussin match = arg_match;
24861d06d6bSBaptiste Daroussin switch (iteration) {
24961d06d6bSBaptiste Daroussin case ITER_NAME:
25061d06d6bSBaptiste Daroussin cp = dbm_get(pages[0].name);
25161d06d6bSBaptiste Daroussin break;
25261d06d6bSBaptiste Daroussin case ITER_SECT:
25361d06d6bSBaptiste Daroussin cp = dbm_get(pages[0].sect);
25461d06d6bSBaptiste Daroussin break;
25561d06d6bSBaptiste Daroussin case ITER_DESC:
25661d06d6bSBaptiste Daroussin cp = dbm_get(pages[0].desc);
25761d06d6bSBaptiste Daroussin break;
25861d06d6bSBaptiste Daroussin default:
25961d06d6bSBaptiste Daroussin abort();
26061d06d6bSBaptiste Daroussin }
26161d06d6bSBaptiste Daroussin if (cp == NULL) {
26261d06d6bSBaptiste Daroussin iteration = ITER_NONE;
26361d06d6bSBaptiste Daroussin match = NULL;
26461d06d6bSBaptiste Daroussin cp = NULL;
26561d06d6bSBaptiste Daroussin ip = npages;
26661d06d6bSBaptiste Daroussin } else
26761d06d6bSBaptiste Daroussin ip = 0;
26861d06d6bSBaptiste Daroussin return res;
26961d06d6bSBaptiste Daroussin }
27061d06d6bSBaptiste Daroussin
27161d06d6bSBaptiste Daroussin /* Search for a name. */
27261d06d6bSBaptiste Daroussin
27361d06d6bSBaptiste Daroussin while (ip < npages) {
27461d06d6bSBaptiste Daroussin if (iteration == ITER_NAME)
27561d06d6bSBaptiste Daroussin cp++;
27661d06d6bSBaptiste Daroussin if (dbm_match(match, cp))
27761d06d6bSBaptiste Daroussin break;
27861d06d6bSBaptiste Daroussin cp = strchr(cp, '\0') + 1;
27961d06d6bSBaptiste Daroussin if (iteration == ITER_DESC)
28061d06d6bSBaptiste Daroussin ip++;
28161d06d6bSBaptiste Daroussin else if (*cp == '\0') {
28261d06d6bSBaptiste Daroussin cp++;
28361d06d6bSBaptiste Daroussin ip++;
28461d06d6bSBaptiste Daroussin }
28561d06d6bSBaptiste Daroussin }
28661d06d6bSBaptiste Daroussin
28761d06d6bSBaptiste Daroussin /* Reached the end without a match. */
28861d06d6bSBaptiste Daroussin
28961d06d6bSBaptiste Daroussin if (ip == npages) {
29061d06d6bSBaptiste Daroussin iteration = ITER_NONE;
29161d06d6bSBaptiste Daroussin match = NULL;
29261d06d6bSBaptiste Daroussin cp = NULL;
29361d06d6bSBaptiste Daroussin return res;
29461d06d6bSBaptiste Daroussin }
29561d06d6bSBaptiste Daroussin
29661d06d6bSBaptiste Daroussin /* Found a match; save the quality for later retrieval. */
29761d06d6bSBaptiste Daroussin
29861d06d6bSBaptiste Daroussin res.page = ip;
29961d06d6bSBaptiste Daroussin res.bits = iteration == ITER_NAME ? cp[-1] : 0;
30061d06d6bSBaptiste Daroussin
30161d06d6bSBaptiste Daroussin /* Skip the remaining names of this page. */
30261d06d6bSBaptiste Daroussin
30361d06d6bSBaptiste Daroussin if (++ip < npages) {
30461d06d6bSBaptiste Daroussin do {
30561d06d6bSBaptiste Daroussin cp++;
30661d06d6bSBaptiste Daroussin } while (cp[-1] != '\0' ||
30761d06d6bSBaptiste Daroussin (iteration != ITER_DESC && cp[-2] != '\0'));
30861d06d6bSBaptiste Daroussin }
30961d06d6bSBaptiste Daroussin return res;
31061d06d6bSBaptiste Daroussin }
31161d06d6bSBaptiste Daroussin
31261d06d6bSBaptiste Daroussin static struct dbm_res
page_byarch(const struct dbm_match * arg_match)31361d06d6bSBaptiste Daroussin page_byarch(const struct dbm_match *arg_match)
31461d06d6bSBaptiste Daroussin {
31561d06d6bSBaptiste Daroussin static const struct dbm_match *match;
31661d06d6bSBaptiste Daroussin struct dbm_res res = {-1, 0};
31761d06d6bSBaptiste Daroussin static int32_t ip;
31861d06d6bSBaptiste Daroussin const char *cp;
31961d06d6bSBaptiste Daroussin
32061d06d6bSBaptiste Daroussin /* Initialize for a new iteration. */
32161d06d6bSBaptiste Daroussin
32261d06d6bSBaptiste Daroussin if (arg_match != NULL) {
32361d06d6bSBaptiste Daroussin iteration = ITER_ARCH;
32461d06d6bSBaptiste Daroussin match = arg_match;
32561d06d6bSBaptiste Daroussin ip = 0;
32661d06d6bSBaptiste Daroussin return res;
32761d06d6bSBaptiste Daroussin }
32861d06d6bSBaptiste Daroussin
32961d06d6bSBaptiste Daroussin /* Search for an architecture. */
33061d06d6bSBaptiste Daroussin
33161d06d6bSBaptiste Daroussin for ( ; ip < npages; ip++)
33261d06d6bSBaptiste Daroussin if (pages[ip].arch)
33361d06d6bSBaptiste Daroussin for (cp = dbm_get(pages[ip].arch);
33461d06d6bSBaptiste Daroussin *cp != '\0';
33561d06d6bSBaptiste Daroussin cp = strchr(cp, '\0') + 1)
33661d06d6bSBaptiste Daroussin if (dbm_match(match, cp)) {
33761d06d6bSBaptiste Daroussin res.page = ip++;
33861d06d6bSBaptiste Daroussin return res;
33961d06d6bSBaptiste Daroussin }
34061d06d6bSBaptiste Daroussin
34161d06d6bSBaptiste Daroussin /* Reached the end without a match. */
34261d06d6bSBaptiste Daroussin
34361d06d6bSBaptiste Daroussin iteration = ITER_NONE;
34461d06d6bSBaptiste Daroussin match = NULL;
34561d06d6bSBaptiste Daroussin return res;
34661d06d6bSBaptiste Daroussin }
34761d06d6bSBaptiste Daroussin
34861d06d6bSBaptiste Daroussin static struct dbm_res
page_bymacro(int32_t arg_im,const struct dbm_match * arg_match)34961d06d6bSBaptiste Daroussin page_bymacro(int32_t arg_im, const struct dbm_match *arg_match)
35061d06d6bSBaptiste Daroussin {
35161d06d6bSBaptiste Daroussin static const struct dbm_match *match;
35261d06d6bSBaptiste Daroussin static const int32_t *pp;
35361d06d6bSBaptiste Daroussin static const char *cp;
35461d06d6bSBaptiste Daroussin static int32_t im, iv;
35561d06d6bSBaptiste Daroussin struct dbm_res res = {-1, 0};
35661d06d6bSBaptiste Daroussin
35761d06d6bSBaptiste Daroussin assert(im >= 0);
35861d06d6bSBaptiste Daroussin assert(im < MACRO_MAX);
35961d06d6bSBaptiste Daroussin
36061d06d6bSBaptiste Daroussin /* Initialize for a new iteration. */
36161d06d6bSBaptiste Daroussin
36261d06d6bSBaptiste Daroussin if (arg_match != NULL) {
36361d06d6bSBaptiste Daroussin iteration = ITER_MACRO;
36461d06d6bSBaptiste Daroussin match = arg_match;
36561d06d6bSBaptiste Daroussin im = arg_im;
36661d06d6bSBaptiste Daroussin cp = nvals[im] ? dbm_get(macros[im]->value) : NULL;
36761d06d6bSBaptiste Daroussin pp = NULL;
36861d06d6bSBaptiste Daroussin iv = -1;
36961d06d6bSBaptiste Daroussin return res;
37061d06d6bSBaptiste Daroussin }
37161d06d6bSBaptiste Daroussin if (iteration != ITER_MACRO)
37261d06d6bSBaptiste Daroussin return res;
37361d06d6bSBaptiste Daroussin
37461d06d6bSBaptiste Daroussin /* Find the next matching macro value. */
37561d06d6bSBaptiste Daroussin
37661d06d6bSBaptiste Daroussin while (pp == NULL || *pp == 0) {
37761d06d6bSBaptiste Daroussin if (++iv == nvals[im]) {
37861d06d6bSBaptiste Daroussin iteration = ITER_NONE;
37961d06d6bSBaptiste Daroussin return res;
38061d06d6bSBaptiste Daroussin }
38161d06d6bSBaptiste Daroussin if (iv)
38261d06d6bSBaptiste Daroussin cp = strchr(cp, '\0') + 1;
38361d06d6bSBaptiste Daroussin if (dbm_match(match, cp))
38461d06d6bSBaptiste Daroussin pp = dbm_get(macros[im][iv].pages);
38561d06d6bSBaptiste Daroussin }
38661d06d6bSBaptiste Daroussin
38761d06d6bSBaptiste Daroussin /* Found a matching page. */
38861d06d6bSBaptiste Daroussin
38961d06d6bSBaptiste Daroussin res.page = (struct page *)dbm_get(*pp++) - pages;
39061d06d6bSBaptiste Daroussin return res;
39161d06d6bSBaptiste Daroussin }
39261d06d6bSBaptiste Daroussin
39361d06d6bSBaptiste Daroussin
39461d06d6bSBaptiste Daroussin /*** functions for handling macros ************************************/
39561d06d6bSBaptiste Daroussin
39661d06d6bSBaptiste Daroussin int32_t
dbm_macro_count(int32_t im)39761d06d6bSBaptiste Daroussin dbm_macro_count(int32_t im)
39861d06d6bSBaptiste Daroussin {
39961d06d6bSBaptiste Daroussin assert(im >= 0);
40061d06d6bSBaptiste Daroussin assert(im < MACRO_MAX);
40161d06d6bSBaptiste Daroussin return nvals[im];
40261d06d6bSBaptiste Daroussin }
40361d06d6bSBaptiste Daroussin
40461d06d6bSBaptiste Daroussin struct dbm_macro *
dbm_macro_get(int32_t im,int32_t iv)40561d06d6bSBaptiste Daroussin dbm_macro_get(int32_t im, int32_t iv)
40661d06d6bSBaptiste Daroussin {
40761d06d6bSBaptiste Daroussin static struct dbm_macro macro;
40861d06d6bSBaptiste Daroussin
40961d06d6bSBaptiste Daroussin assert(im >= 0);
41061d06d6bSBaptiste Daroussin assert(im < MACRO_MAX);
41161d06d6bSBaptiste Daroussin assert(iv >= 0);
41261d06d6bSBaptiste Daroussin assert(iv < nvals[im]);
41361d06d6bSBaptiste Daroussin macro.value = dbm_get(macros[im][iv].value);
41461d06d6bSBaptiste Daroussin macro.pp = dbm_get(macros[im][iv].pages);
41561d06d6bSBaptiste Daroussin return ¯o;
41661d06d6bSBaptiste Daroussin }
41761d06d6bSBaptiste Daroussin
41861d06d6bSBaptiste Daroussin /*
41961d06d6bSBaptiste Daroussin * Filtered iteration over macro entries.
42061d06d6bSBaptiste Daroussin */
42161d06d6bSBaptiste Daroussin void
dbm_macro_bypage(int32_t im,int32_t ip)42261d06d6bSBaptiste Daroussin dbm_macro_bypage(int32_t im, int32_t ip)
42361d06d6bSBaptiste Daroussin {
42461d06d6bSBaptiste Daroussin assert(im >= 0);
42561d06d6bSBaptiste Daroussin assert(im < MACRO_MAX);
42661d06d6bSBaptiste Daroussin assert(ip != 0);
42761d06d6bSBaptiste Daroussin macro_bypage(im, ip);
42861d06d6bSBaptiste Daroussin }
42961d06d6bSBaptiste Daroussin
43061d06d6bSBaptiste Daroussin char *
dbm_macro_next(void)43161d06d6bSBaptiste Daroussin dbm_macro_next(void)
43261d06d6bSBaptiste Daroussin {
43361d06d6bSBaptiste Daroussin return macro_bypage(MACRO_MAX, 0);
43461d06d6bSBaptiste Daroussin }
43561d06d6bSBaptiste Daroussin
43661d06d6bSBaptiste Daroussin static char *
macro_bypage(int32_t arg_im,int32_t arg_ip)43761d06d6bSBaptiste Daroussin macro_bypage(int32_t arg_im, int32_t arg_ip)
43861d06d6bSBaptiste Daroussin {
43961d06d6bSBaptiste Daroussin static const int32_t *pp;
44061d06d6bSBaptiste Daroussin static int32_t im, ip, iv;
44161d06d6bSBaptiste Daroussin
44261d06d6bSBaptiste Daroussin /* Initialize for a new iteration. */
44361d06d6bSBaptiste Daroussin
44461d06d6bSBaptiste Daroussin if (arg_im < MACRO_MAX && arg_ip != 0) {
44561d06d6bSBaptiste Daroussin im = arg_im;
44661d06d6bSBaptiste Daroussin ip = arg_ip;
44761d06d6bSBaptiste Daroussin pp = dbm_get(macros[im]->pages);
44861d06d6bSBaptiste Daroussin iv = 0;
44961d06d6bSBaptiste Daroussin return NULL;
45061d06d6bSBaptiste Daroussin }
45161d06d6bSBaptiste Daroussin if (im >= MACRO_MAX)
45261d06d6bSBaptiste Daroussin return NULL;
45361d06d6bSBaptiste Daroussin
45461d06d6bSBaptiste Daroussin /* Search for the next value. */
45561d06d6bSBaptiste Daroussin
45661d06d6bSBaptiste Daroussin while (iv < nvals[im]) {
45761d06d6bSBaptiste Daroussin if (*pp == ip)
45861d06d6bSBaptiste Daroussin break;
45961d06d6bSBaptiste Daroussin if (*pp == 0)
46061d06d6bSBaptiste Daroussin iv++;
46161d06d6bSBaptiste Daroussin pp++;
46261d06d6bSBaptiste Daroussin }
46361d06d6bSBaptiste Daroussin
46461d06d6bSBaptiste Daroussin /* Reached the end without a match. */
46561d06d6bSBaptiste Daroussin
46661d06d6bSBaptiste Daroussin if (iv == nvals[im]) {
46761d06d6bSBaptiste Daroussin im = MACRO_MAX;
46861d06d6bSBaptiste Daroussin ip = 0;
46961d06d6bSBaptiste Daroussin pp = NULL;
47061d06d6bSBaptiste Daroussin return NULL;
47161d06d6bSBaptiste Daroussin }
47261d06d6bSBaptiste Daroussin
47361d06d6bSBaptiste Daroussin /* Found a match; skip the remaining pages of this entry. */
47461d06d6bSBaptiste Daroussin
47561d06d6bSBaptiste Daroussin if (++iv < nvals[im])
47661d06d6bSBaptiste Daroussin while (*pp++ != 0)
47761d06d6bSBaptiste Daroussin continue;
47861d06d6bSBaptiste Daroussin
47961d06d6bSBaptiste Daroussin return dbm_get(macros[im][iv - 1].value);
48061d06d6bSBaptiste Daroussin }
481