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