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