version 1.5, 2011/10/09 10:35:12 |
version 1.7, 2011/10/09 10:46:38 |
Line 152 static int sort_title(const void *, const void *); |
|
Line 152 static int sort_title(const void *, const void *); |
|
static int state_getrecord(struct state *, |
static int state_getrecord(struct state *, |
recno_t, struct rec *); |
recno_t, struct rec *); |
static void state_output(const struct res *, int); |
static void state_output(const struct res *, int); |
static void state_search(struct state *, |
static int state_search(struct state *, |
const struct opts *, char *); |
const struct opts *, char *); |
static void usage(void); |
static void usage(void); |
|
|
Line 275 main(int argc, char *argv[]) |
|
Line 275 main(int argc, char *argv[]) |
|
|
|
/* Main search function. */ |
/* Main search function. */ |
|
|
state_search(&state, &opts, q); |
rc = state_search(&state, &opts, q) ? |
|
EXIT_SUCCESS : EXIT_FAILURE; |
rc = EXIT_SUCCESS; |
|
out: |
out: |
if (state.db) |
if (state.db) |
(*state.db->close)(state.db); |
(*state.db->close)(state.db); |
|
|
return(rc); |
return(rc); |
} |
} |
|
|
static void |
static int |
state_search(struct state *p, const struct opts *opts, char *q) |
state_search(struct state *p, const struct opts *opts, char *q) |
{ |
{ |
int leaf, root, len, ch, rflags, dflag; |
int leaf, root, len, ch, dflag, rc; |
struct mchars *mc; |
struct mchars *mc; |
char *buf; |
char *buf; |
size_t bufsz; |
size_t bufsz; |
Line 303 state_search(struct state *p, const struct opts *opts, |
|
Line 302 state_search(struct state *p, const struct opts *opts, |
|
char filebuf[10]; |
char filebuf[10]; |
struct rec record; |
struct rec record; |
|
|
|
rc = 0; |
root = leaf = -1; |
root = leaf = -1; |
res = NULL; |
res = NULL; |
len = 0; |
len = 0; |
buf = NULL; |
buf = NULL; |
bufsz = 0; |
bufsz = 0; |
ch = 0; |
|
regp = NULL; |
regp = NULL; |
|
|
/* |
/* |
Line 318 state_search(struct state *p, const struct opts *opts, |
|
Line 317 state_search(struct state *p, const struct opts *opts, |
|
|
|
switch (opts->match) { |
switch (opts->match) { |
case (MATCH_REGEX): |
case (MATCH_REGEX): |
rflags = REG_EXTENDED | REG_NOSUB | |
ch = REG_EXTENDED | REG_NOSUB | |
(opts->insens ? REG_ICASE : 0); |
(opts->insens ? REG_ICASE : 0); |
|
|
if (0 != regcomp(®, q, rflags)) { |
if (0 != regcomp(®, q, ch)) { |
fprintf(stderr, "%s: Bad pattern\n", q); |
fprintf(stderr, "%s: Bad pattern\n", q); |
return; |
return(0); |
} |
} |
|
|
regp = ® |
regp = ® |
Line 339 state_search(struct state *p, const struct opts *opts, |
|
Line 338 state_search(struct state *p, const struct opts *opts, |
|
break; |
break; |
} |
} |
|
|
if (NULL == (mc = mchars_alloc())) { |
mc = mchars_alloc(); |
perror(NULL); |
|
exit(EXIT_FAILURE); |
|
} |
|
|
|
/* |
/* |
* Iterate over the entire keyword database. |
* Iterate over the entire keyword database. |
Line 362 state_search(struct state *p, const struct opts *opts, |
|
Line 358 state_search(struct state *p, const struct opts *opts, |
|
*/ |
*/ |
|
|
if (key.size < 2 || 8 != val.size) { |
if (key.size < 2 || 8 != val.size) { |
fprintf(stderr, "%s: Corrupt database\n", p->dbf); |
fprintf(stderr, "%s: Bad database\n", p->dbf); |
exit(EXIT_FAILURE); |
goto out; |
} |
} |
|
|
buf_redup(mc, &buf, &bufsz, (char *)key.data); |
buf_redup(mc, &buf, &bufsz, (char *)key.data); |
Line 400 state_search(struct state *p, const struct opts *opts, |
|
Line 396 state_search(struct state *p, const struct opts *opts, |
|
memcpy(&rec, val.data + 4, sizeof(recno_t)); |
memcpy(&rec, val.data + 4, sizeof(recno_t)); |
|
|
if ( ! state_getrecord(p, rec, &record)) |
if ( ! state_getrecord(p, rec, &record)) |
exit(EXIT_FAILURE); |
goto out; |
|
|
/* If we're in a different section, skip... */ |
/* If we're in a different section, skip... */ |
|
|
Line 460 state_search(struct state *p, const struct opts *opts, |
|
Line 456 state_search(struct state *p, const struct opts *opts, |
|
len++; |
len++; |
} |
} |
|
|
send: |
|
if (ch < 0) { |
if (ch < 0) { |
perror(p->dbf); |
perror(p->dbf); |
exit(EXIT_FAILURE); |
goto out; |
} |
} |
|
send: |
|
/* Sort our results. */ |
|
|
/* |
if (SORT_CAT == opts->sort) |
* Sort our results. |
|
* We do this post-scan (instead of an in-line sort) because |
|
* it's more or less the same in terms of run-time. Assuming we |
|
* sort in-line with a tree versus post: |
|
* |
|
* In-place: n * O(lg n) |
|
* After: n + O(n lg n) |
|
* |
|
* Whatever. This also buys us simplicity. |
|
*/ |
|
|
|
switch (opts->sort) { |
|
case (SORT_CAT): |
|
qsort(res, len, sizeof(struct res), sort_cat); |
qsort(res, len, sizeof(struct res), sort_cat); |
break; |
else |
default: |
|
qsort(res, len, sizeof(struct res), sort_title); |
qsort(res, len, sizeof(struct res), sort_title); |
break; |
|
} |
|
|
|
state_output(res, len); |
state_output(res, len); |
|
rc = 1; |
|
out: |
for (len-- ; len >= 0; len--) { |
for (len-- ; len >= 0; len--) { |
free(res[len].keyword); |
free(res[len].keyword); |
free(res[len].title); |
free(res[len].title); |
|
|
|
|
if (regp) |
if (regp) |
regfree(regp); |
regfree(regp); |
|
|
|
return(rc); |
} |
} |
|
|
/* |
/* |