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