]>
git.cameronkatri.com Git - mandoc.git/blob - dbm.c
1 /* $Id: dbm.c,v 1.2 2016/07/20 00:23:14 schwarze Exp $ */
3 * Copyright (c) 2016 Ingo Schwarze <schwarze@openbsd.org>
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 * Map-based version of the mandoc database, for read-only access.
18 * The interface is defined in "dbm.h".
34 #include "mansearch.h"
60 static struct macro
*macros
[MACRO_MAX
];
61 static int32_t nvals
[MACRO_MAX
];
62 static struct page
*pages
;
63 static int32_t npages
;
64 static enum iter iteration
;
66 static struct dbm_res
page_bytitle(enum iter
, const struct dbm_match
*);
67 static struct dbm_res
page_byarch(const struct dbm_match
*);
68 static struct dbm_res
page_bymacro(int32_t, const struct dbm_match
*);
69 static char *macro_bypage(int32_t, int32_t);
72 /*** top level functions **********************************************/
75 * Open a disk-based mandoc database for read-only access.
76 * Map the pages and macros[] arrays.
77 * Return 0 on success. Return -1 and set errno on failure.
80 dbm_open(const char *fname
)
82 const int32_t *mp
, *ep
;
85 if (dbm_map(fname
) == -1)
88 if ((npages
= be32toh(*dbm_getint(4))) < 0) {
89 warnx("dbm_open(%s): Invalid number of pages: %d",
93 pages
= (struct page
*)dbm_getint(5);
95 if ((mp
= dbm_get(*dbm_getint(2))) == NULL
) {
96 warnx("dbm_open(%s): Invalid offset of macros array", fname
);
99 if (be32toh(*mp
) != MACRO_MAX
) {
100 warnx("dbm_open(%s): Invalid number of macros: %d",
101 fname
, be32toh(*mp
));
104 for (im
= 0; im
< MACRO_MAX
; im
++) {
105 if ((ep
= dbm_get(*++mp
)) == NULL
) {
106 warnx("dbm_open(%s): Invalid offset of macro %d",
110 nvals
[im
] = be32toh(*ep
);
111 macros
[im
] = (struct macro
*)++ep
;
128 /*** functions for handling pages *************************************/
137 * Give the caller pointers to the data for one manual page.
140 dbm_page_get(int32_t ip
)
142 static struct dbm_page res
;
146 res
.name
= dbm_get(pages
[ip
].name
);
147 res
.sect
= dbm_get(pages
[ip
].sect
);
148 res
.arch
= pages
[ip
].arch
? dbm_get(pages
[ip
].arch
) : NULL
;
149 res
.desc
= dbm_get(pages
[ip
].desc
);
150 res
.file
= dbm_get(pages
[ip
].file
);
151 res
.addr
= dbm_addr(pages
+ ip
);
156 * Functions to start filtered iterations over manual pages.
159 dbm_page_byname(const struct dbm_match
*match
)
161 assert(match
!= NULL
);
162 page_bytitle(ITER_NAME
, match
);
166 dbm_page_bysect(const struct dbm_match
*match
)
168 assert(match
!= NULL
);
169 page_bytitle(ITER_SECT
, match
);
173 dbm_page_byarch(const struct dbm_match
*match
)
175 assert(match
!= NULL
);
180 dbm_page_bydesc(const struct dbm_match
*match
)
182 assert(match
!= NULL
);
183 page_bytitle(ITER_DESC
, match
);
187 dbm_page_bymacro(int32_t im
, const struct dbm_match
*match
)
190 assert(im
< MACRO_MAX
);
191 assert(match
!= NULL
);
192 page_bymacro(im
, match
);
196 * Return the number of the next manual page in the current iteration.
201 struct dbm_res res
= {-1, 0};
207 return page_byarch(NULL
);
209 return page_bymacro(0, NULL
);
211 return page_bytitle(iteration
, NULL
);
216 * Functions implementing the iteration over manual pages.
218 static struct dbm_res
219 page_bytitle(enum iter arg_iter
, const struct dbm_match
*arg_match
)
221 static const struct dbm_match
*match
;
222 static const char *cp
;
224 struct dbm_res res
= {-1, 0};
226 assert(arg_iter
== ITER_NAME
|| arg_iter
== ITER_DESC
||
227 arg_iter
== ITER_SECT
);
229 /* Initialize for a new iteration. */
231 if (arg_match
!= NULL
) {
232 iteration
= arg_iter
;
236 cp
= dbm_get(pages
[0].name
);
239 cp
= dbm_get(pages
[0].sect
);
242 cp
= dbm_get(pages
[0].desc
);
251 /* Search for a name. */
253 while (ip
< npages
) {
254 if (iteration
== ITER_NAME
)
256 if (dbm_match(match
, cp
))
258 cp
= strchr(cp
, '\0') + 1;
259 if (iteration
== ITER_DESC
)
261 else if (*cp
== '\0') {
267 /* Reached the end without a match. */
270 iteration
= ITER_NONE
;
276 /* Found a match; save the quality for later retrieval. */
279 res
.bits
= iteration
== ITER_NAME
? cp
[-1] : 0;
281 /* Skip the remaining names of this page. */
286 } while (cp
[-1] != '\0' ||
287 (iteration
!= ITER_DESC
&& cp
[-2] != '\0'));
292 static struct dbm_res
293 page_byarch(const struct dbm_match
*arg_match
)
295 static const struct dbm_match
*match
;
296 struct dbm_res res
= {-1, 0};
300 /* Initialize for a new iteration. */
302 if (arg_match
!= NULL
) {
303 iteration
= ITER_ARCH
;
309 /* Search for an architecture. */
311 for ( ; ip
< npages
; ip
++)
313 for (cp
= dbm_get(pages
[ip
].arch
);
315 cp
= strchr(cp
, '\0') + 1)
316 if (dbm_match(match
, cp
)) {
321 /* Reached the end without a match. */
323 iteration
= ITER_NONE
;
328 static struct dbm_res
329 page_bymacro(int32_t im
, const struct dbm_match
*match
)
331 static const int32_t *pp
;
332 struct dbm_res res
= {-1, 0};
337 assert(im
< MACRO_MAX
);
339 /* Initialize for a new iteration. */
342 iteration
= ITER_MACRO
;
343 cp
= nvals
[im
] ? dbm_get(macros
[im
]->value
) : NULL
;
344 for (iv
= 0; iv
< nvals
[im
]; iv
++) {
345 if (dbm_match(match
, cp
))
347 cp
= strchr(cp
, '\0') + 1;
349 pp
= iv
== nvals
[im
] ? NULL
: dbm_get(macros
[im
][iv
].pages
);
352 if (iteration
!= ITER_MACRO
)
355 /* No more matches. */
357 if (pp
== NULL
|| *pp
== 0) {
358 iteration
= ITER_NONE
;
365 res
.page
= (struct page
*)dbm_get(*pp
++) - pages
;
370 /*** functions for handling macros ************************************/
373 dbm_macro_count(int32_t im
)
376 assert(im
< MACRO_MAX
);
381 dbm_macro_get(int32_t im
, int32_t iv
)
383 static struct dbm_macro macro
;
386 assert(im
< MACRO_MAX
);
388 assert(iv
< nvals
[im
]);
389 macro
.value
= dbm_get(macros
[im
][iv
].value
);
390 macro
.pp
= dbm_get(macros
[im
][iv
].pages
);
395 * Filtered iteration over macro entries.
398 dbm_macro_bypage(int32_t im
, int32_t ip
)
401 assert(im
< MACRO_MAX
);
403 macro_bypage(im
, ip
);
409 return macro_bypage(MACRO_MAX
, 0);
413 macro_bypage(int32_t arg_im
, int32_t arg_ip
)
415 static const int32_t *pp
;
416 static int32_t im
, ip
, iv
;
418 /* Initialize for a new iteration. */
420 if (arg_im
< MACRO_MAX
&& arg_ip
!= 0) {
423 pp
= dbm_get(macros
[im
]->pages
);
430 /* Search for the next value. */
432 while (iv
< nvals
[im
]) {
440 /* Reached the end without a match. */
442 if (iv
== nvals
[im
]) {
449 /* Found a match; skip the remaining pages of this entry. */
451 if (++iv
< nvals
[im
])
455 return dbm_get(macros
[im
][iv
- 1].value
);