source: gsdl/trunk/runtime-src/src/colservr/mgq.c@ 20939

Last change on this file since 20939 was 1285, checked in by sjboddie, 24 years ago

Removed CVS logging information from source files

  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 19.3 KB
Line 
1/**********************************************************************
2 *
3 * mgq.c -- cut-dowm version of mgquery
4 * Copyright (C) 1999 The New Zealand Digital Library Project
5 *
6 * A component of the Greenstone digital library software
7 * from the New Zealand Digital Library Project at the
8 * University of Waikato, New Zealand.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *
24 *********************************************************************/
25
26#include "mgq.h"
27
28
29#include <stdio.h>
30#include <string.h>
31/* #include <io.h> */
32#include <fcntl.h>
33
34#ifdef __cplusplus
35extern "C" {
36#endif
37
38#include "sysfuncs.h"
39
40#include "messages.h"
41#include "memlib.h"
42
43#include "invf.h"
44#include "text.h"
45#include "lists.h"
46#include "backend.h"
47#include "environment.h"
48#include "globals.h"
49#include "mg_errors.h"
50#include "commands.h"
51#include "text_get.h"
52#include "term_lists.h"
53#include "local_strings.h"
54
55#include "words.h"
56#include "stemmer.h"
57#include "stem_search.h"
58
59#ifdef __cplusplus
60}
61#endif
62
63
64#include "mgq.h"
65
66/* get a reasonable database cache size */
67#ifndef MAXNUMDATABASEINFO
68# ifdef GSDLSERVER
69# define MAXNUMDATABASEINFO 10
70# else
71# define MAXNUMDATABASEINFO 2
72# endif
73#endif
74
75#define MAXCOLLECTIONLEN 16
76#define MAXMGDIRLEN 256
77#define MAXGENSUFFIXLEN 256
78#define MAXTEXTSUFFIXLEN 256
79
80typedef struct DatabaseInfo {
81 int accessnum; /* -1 = invalid record */
82 char collection[MAXCOLLECTIONLEN];
83 char mgdir[MAXMGDIRLEN];
84 char gensuffix[MAXGENSUFFIXLEN];
85 char textsuffix[MAXTEXTSUFFIXLEN];
86 query_data *qd;
87} DatabaseInfo;
88
89
90/* globals needed by some vague part of mg... */
91FILE *OutFile = NULL, *InFile = NULL;
92int OutPipe = 0, InPipe = 0;
93int Quitting = 0;
94
95/* globals needed to handle loading of databases */
96static int cur_cachenum = -1;
97
98/* globals needed by the database cache */
99static DatabaseInfo dbcache[MAXNUMDATABASEINFO];
100static int cache_nextaccessnum = 0;
101static int cache_numloaded = 0;
102
103
104
105#if defined(PARADOCNUM) || defined(NZDL)
106static int GetDocNumFromParaNum(query_data *qd, int paranum) {
107 int Documents = qd->td->cth.num_of_docs;
108 int *Paragraph = qd->paragraph;
109 int low = 1, high = Documents;
110 int mid = (low+high)/2;
111
112 while ((mid = (low+high)/2) >=1 && mid <= Documents)
113 {
114 if (paranum > Paragraph[mid])
115 low = mid+1;
116 else if (paranum <= Paragraph[mid-1])
117 high = mid-1;
118 else
119 return mid;
120 }
121 FatalError(1, "Bad paragraph number.\n");
122 return 0;
123}
124
125static int GetParaNumFromDocNum(query_data *qd, int docnum) {
126 int Documents = qd->td->cth.num_of_docs;
127 int *Paragraph = qd->paragraph;
128
129 if (docnum > 0 && docnum <= Documents)
130 return Paragraph[docnum-1]+1;
131 return 0;
132}
133#endif
134
135
136/*****************************************************************************/
137
138static void MGQError(char *emsg)
139{
140 fprintf(stderr,"Fatal error: %s\n", emsg);
141 exit(1);
142}
143
144static int ProcessDocs (query_data * qd, int skip, int howmany,
145 enum result_kinds kind,
146 int (*sender)(char *,int,int,float,void *), void *ptr) {
147 int max_buf = 0, output_failure = 0;
148 int DocCount = 0;
149 int need_text = (kind == result_docs);
150
151 /* skip the requested number of documents */
152 while (skip > 0) {
153 if (!NextDoc(qd)) return 0;
154 skip--;
155 }
156
157 /* find out the maximum size for the text buffer */
158 if (need_text) max_buf = atoi (GetDefEnv ("buffer", "1048576"));
159
160 /* process each document */
161 do {
162 u_char *UDoc = NULL;
163 unsigned long ULen=0;
164
165#if defined(PARADOCNUM) || defined(NZDL)
166 /* adjust the document number for paragraph level result_docs */
167 /* this is a bit of a hack ... */
168 if (kind==result_docs && qd->id->ifh.InvfLevel == 3 &&
169 qd->DL != NULL && (int)qd->doc_pos < (int)qd->DL->num)
170 qd->DL->DE[qd->doc_pos].DocNum = GetParaNumFromDocNum(qd, qd->DL->DE[qd->doc_pos].DocNum);
171#endif
172
173 if (need_text) {
174 /* load the compressed text */
175 if (LoadCompressedText (qd, max_buf))
176 MGQError("Unable to load compressed text(memory?).");
177
178 /* uncompress the loaded text */
179 UDoc = GetDocText (qd, &ULen);
180 if (UDoc == NULL) MGQError("UDoc is unexpectedly NULL");
181 }
182
183 if (UDoc != NULL || kind == result_docnums) {
184 int docnum = GetDocNum(qd);
185#if defined(PARADOCNUM) || defined(NZDL)
186 if (qd->id->ifh.InvfLevel == 3) docnum = GetDocNumFromParaNum(qd, docnum);
187#endif
188 switch (kind) {
189 case result_docnums:
190 if (sender != NULL)
191 output_failure = (*sender)("",0,docnum,GetDocWeight(qd),ptr);
192 break;
193 case result_docs:
194 if (sender != NULL)
195 output_failure = (*sender)((char *)UDoc,ULen,docnum,GetDocWeight(qd),ptr);
196 break;
197 default:
198 break;
199 }
200 }
201 DocCount++;
202
203 } while (NextDoc (qd) && output_failure == 0 && --howmany > 0);
204
205 /* if (need_text) FreeTextBuffer (qd);*/
206
207 return (DocCount);
208}
209
210
211static void send_query_term_freqs(QueryTermList *qtl,
212 int (*sender)(char *,int,int,float,void *), void *ptr)
213{
214 int i = 0;
215 for (i = 0; i < qtl->num; i++)
216 if (sender != NULL) {
217 /* word = word2str(qtl->QTE[i].Term);
218 (* sender)(word, strlen(word), qtl->QTE[i].Count, (float)0.0, ptr); */
219 (* sender)((char *)(qtl->QTE[i].Term+1), qtl->QTE[i].Term[0],
220 qtl->QTE[i].Count, (float)0.0, ptr);
221 }
222}
223
224
225static void send_terms (TermList * qtl,
226 int (*sender)(char *,int,int,float,void *), void *ptr)
227{
228 int i = 0;
229 if (sender == NULL) return;
230 for (i = 0; i < qtl->num; i++)
231 {
232 /* word = word2str(qtl->TE[i].Word);
233 (* sender)(word, strlen(word), qtl->TE[i].Count, (float)0.0, ptr);*/
234 (* sender)((char *)(qtl->TE[i].Word+1), qtl->TE[i].Word[0],
235 qtl->TE[i].Count, (float)0.0, ptr);
236 }
237}
238
239
240/* MoreDocs () */
241/* Displays all documents in list DocList. */
242/* Documents are fetched, then decompressed and displayed according to the */
243/* format implied in FormString(). */
244
245static void
246MoreDocs (query_data * qd, enum result_kinds kind,
247 int skip, int howmany,
248 int (*sender)(char *,int,int,float,void *), void *ptr)
249{
250 qd->num_of_ans = qd->DL->num;
251 switch (kind) {
252 case result_docs:
253 case result_docnums:
254 if (qd->num_of_ans > 0)
255 ProcessDocs (qd, skip, howmany, kind, sender, ptr);
256 break;
257 case result_termfreqs:
258 send_query_term_freqs(qd->QTL, sender, ptr);
259 break;
260 case result_terms:
261 send_terms(qd->TL, sender, ptr);
262 break;
263 }
264}
265
266
267
268
269
270
271/******************************************
272 * functions to handle the database cache *
273 ******************************************/
274
275/* init_dbcache should be called at the start of each */
276/* function which deals with the database cache */
277static void init_dbcache (void) {
278 static int dbcacheinited = 0;
279 int i = 0;
280
281 if (dbcacheinited) return;
282
283 cache_numloaded = 0;
284
285 for (i=0; i<MAXNUMDATABASEINFO; i++) {
286 dbcache[i].accessnum = -1;
287 dbcache[i].collection[0] = '\0';
288 dbcache[i].mgdir[0] = '\0';
289 dbcache[i].gensuffix[0] = '\0';
290 dbcache[i].textsuffix[0] = '\0';
291 dbcache[i].qd = NULL;
292 }
293
294 dbcacheinited = 1;
295}
296
297/* returns the next cache access number and increments it */
298static int get_next_accessnum (void) {
299 return cache_nextaccessnum++;
300}
301
302/* get_free_dbcache returns the cache number which */
303/* was used the longest time ago */
304/* init_dbcache should be called before this function */
305static int get_free_dbcache (void) {
306 int i = 0;
307 int minaccessnum = cache_nextaccessnum; /* the current max */
308 int minpos = 0;
309
310 for (i=0; i<MAXNUMDATABASEINFO; i++) {
311 if (dbcache[i].accessnum < minaccessnum) {
312 minaccessnum = dbcache[i].accessnum;
313 minpos = i;
314 }
315 }
316
317 return minpos;
318}
319
320/* search_collect will search for an index which */
321/* belongs to a certain collection It returns -1 if none could be found. */
322/* init_dbcache should be called before this function */
323static int search_collect (char *collection) {
324 int i = 0;
325
326 for (i=0; i<MAXNUMDATABASEINFO; i++) {
327 if ((dbcache[i].accessnum >= 0) &&
328 (dbcache[i].qd != NULL) &&
329 (strcmp (collection, dbcache[i].collection) == 0)
330 /* && (dbcache[i].qd->id->ifh.InvfLevel == 2)*/
331 ) {
332 dbcache[i].accessnum = get_next_accessnum ();
333 return i;
334 }
335 }
336
337 return -1;
338}
339
340/* search_gensuffix will search for an index which */
341/* has a certain gensuffix. It returns -1 if none could be found. */
342/* init_dbcache should be called before this function */
343static int search_gensuffix (char *gensuffix) {
344 int i = 0;
345
346 for (i=0; i<MAXNUMDATABASEINFO; i++) {
347 if ((dbcache[i].accessnum >= 0) &&
348 (dbcache[i].qd != NULL) &&
349 (strcmp (gensuffix, dbcache[i].gensuffix) == 0)) {
350 dbcache[i].accessnum = get_next_accessnum ();
351 return i;
352 }
353 }
354
355 return -1;
356}
357
358/* unload_database will unload a certain entry within */
359/* the database cache, clearing it for furture use. */
360static void unload_database (int i) {
361 /* check to see if it contains anything */
362 if (dbcache[i].accessnum < 0 || dbcache[i].qd == NULL)
363 return;
364
365 /* unload all the query information */
366 FinishQuerySystem(dbcache[i].qd);
367
368 /* reset all the db info */
369 dbcache[i].accessnum = -1;
370 dbcache[i].collection[0] = '\0';
371 dbcache[i].mgdir[0] = '\0';
372 dbcache[i].gensuffix[0] = '\0';
373 dbcache[i].textsuffix[0] = '\0';
374 dbcache[i].qd = NULL;
375
376 cache_numloaded--;
377 if (cache_numloaded < 0) cache_numloaded = 0;
378}
379
380/* cache_database will store the information about */
381/* a database in the database cache. */
382static void cache_database (int i, char *collection, char *mgdir, char *gensuffix,
383 char *textsuffix, query_data *qd) {
384 /* make sure this entry has been unloaded first */
385 if (dbcache[i].accessnum >= 0 && dbcache[i].qd != NULL)
386 unload_database (i);
387
388 /* store the db info */
389 dbcache[i].accessnum = get_next_accessnum ();
390 strcpy (dbcache[i].collection, collection);
391 strcpy (dbcache[i].mgdir, mgdir);
392 strcpy (dbcache[i].gensuffix, gensuffix);
393 strcpy (dbcache[i].textsuffix, textsuffix);
394 dbcache[i].qd = qd;
395
396 cache_numloaded++;
397}
398
399static void make_current (int i) {
400 /* see if it is the current index */
401 if (i == cur_cachenum) return;
402
403 /* unload the old index */
404 if (cur_cachenum >= 0) UninitEnv ();
405 cur_cachenum = -1;
406
407 /* make sure the new one is ok */
408 if (i < 0 || dbcache[i].accessnum < 0 || dbcache[i].qd == NULL)
409 return;
410
411 /* load the new one */
412
413 /* Initialise the environment with default values */
414 InitEnv ();
415
416 SetEnv("mgdir",dbcache[i].mgdir,NULL);
417 SetEnv("mgname",dbcache[i].gensuffix,NULL);
418 SetEnv("textname",dbcache[i].textsuffix,NULL);
419
420 PushEnv ();
421
422 cur_cachenum = i;
423}
424
425
426
427/********************
428 * public functions *
429 ********************/
430
431int mgq_ask(char *line)
432{
433 query_data *qd = (query_data *)NULL;
434 char QueryType = QUERY_BOOLEAN;
435 char OutputType = QUERY_DOCNUMS;
436 char *LinePtr = (char *)NULL;
437
438 if (cur_cachenum == -1) return 0;
439 qd = dbcache[cur_cachenum].qd;
440 if (qd == NULL) return 0;
441
442 ResetFileStats (qd);
443 qd->max_mem_in_use = qd->mem_in_use = 0;
444 qd->tot_hops_taken += qd->hops_taken;
445 qd->tot_num_of_ptrs += qd->num_of_ptrs;
446 qd->tot_num_of_accum += qd->num_of_accum;
447 qd->tot_num_of_terms += qd->num_of_terms;
448 qd->tot_num_of_ans += qd->num_of_ans;
449 qd->tot_text_idx_lookups += qd->text_idx_lookups;
450 qd->hops_taken = qd->num_of_ptrs = 0;
451 qd->num_of_accum = qd->num_of_ans = qd->num_of_terms = 0;
452 qd->text_idx_lookups = 0;
453
454 LinePtr = ProcessCommands (line, qd);
455 if (CommandsErrorStr) {
456 fprintf (stderr, "%s\n", CommandsErrorStr);
457 return 0;
458 }
459 if (*LinePtr == '\0') return 1;
460
461 FreeQueryDocs (qd);
462
463 QueryType = get_query_type ();
464 OutputType = get_output_type ();
465 /* No point in hiliting words on a docnum query */
466 if (OutputType == OUTPUT_HILITE && QueryType == QUERY_DOCNUMS)
467 OutputType = OUTPUT_TEXT;
468
469 switch (QueryType)
470 {
471 case QUERY_BOOLEAN:
472 {
473 char *maxdocs = (char *)NULL;
474 BooleanQueryInfo bqi;
475 maxdocs = GetDefEnv ("maxdocs", "all");
476 bqi.MaxDocsToRetrieve = strcmp (maxdocs, "all") ? atoi (maxdocs) : -1;
477 if (qd->sd->sdh.indexed)
478 BooleanQuery (qd, line, &bqi, (BooleanEnv (GetEnv ("casefold"), 0) |
479 (BooleanEnv (GetEnv ("stem"), 0) << 1)));
480 else
481 BooleanQuery (qd, line, &bqi, qd->sd->sdh.stem_method);
482 /* if (qd->sd->sdh.indexed) BooleanQuery (qd, line, &bqi, 3);
483 else BooleanQuery (qd, line, &bqi, qd->sd->sdh.stem_method); */
484 break;
485 }
486 case QUERY_APPROX:
487 case QUERY_RANKED:
488 {
489 char *maxdocs = (char *)NULL;
490 char *maxterms = (char *)NULL;
491 char *maxaccum = (char *)NULL;
492 RankedQueryInfo rqi;
493 maxdocs = GetDefEnv ("maxdocs", "all");
494 maxterms = GetDefEnv ("max_terms", "all");
495 maxaccum = GetDefEnv ("max_accumulators", "all");
496 rqi.Sort = BooleanEnv (GetEnv ("sorted_terms"), 0);
497 rqi.QueryFreqs = BooleanEnv (GetEnv ("qfreq"), 1);
498 rqi.Exact = QueryType == QUERY_RANKED;
499 rqi.MaxDocsToRetrieve = strcmp (maxdocs, "all") ? atoi (maxdocs) : -1;
500 rqi.MaxTerms = strcmp (maxterms, "all") ? atoi (maxterms) : -1;
501 rqi.MaxParasToRetrieve = rqi.MaxDocsToRetrieve;
502 if (qd->id->ifh.InvfLevel == 3 && GetEnv ("maxparas"))
503 rqi.MaxParasToRetrieve = atoi (GetEnv ("maxparas"));
504 rqi.AccumMethod = toupper (*GetDefEnv ("accumulator_method", "A"));
505 rqi.MaxAccums = strcmp (maxaccum, "all") ? atoi (maxaccum) : -1;
506 rqi.HashTblSize = IntEnv (GetEnv ("hash_tbl_size"), 1000);
507 rqi.StopAtMaxAccum = BooleanEnv (GetEnv ("stop_at_max_accum"), 0);
508 rqi.skip_dump = GetEnv ("skip_dump");
509 RankedQuery (qd, line, &rqi);
510 break;
511 }
512 case QUERY_DOCNUMS:
513 {
514 DocnumsQuery (qd, line);
515 break;
516 }
517 }
518
519 return 1;
520}
521
522int mgq_numdocs(void)
523{
524 query_data *qd = NULL;
525 if (cur_cachenum == -1) return 0;
526 qd = dbcache[cur_cachenum].qd;
527 if (qd == NULL) return 0;
528
529 if (qd->DL) return qd->DL->num;
530 else return 0;
531}
532
533int mgq_numterms(void)
534{
535 query_data *qd = NULL;
536 if (cur_cachenum == -1) return 0;
537 qd = dbcache[cur_cachenum].qd;
538 if (qd == NULL) return 0;
539
540 if (qd->QTL) return qd->QTL->num;
541 else return 0;
542}
543
544int mgq_results(enum result_kinds kind,int skip,int howmany, int (*sender)(char *, int, int, float, void *), void *ptr)
545{
546 query_data *qd = NULL;
547 if (cur_cachenum == -1) return 0;
548 qd = dbcache[cur_cachenum].qd;
549 if (qd == NULL) return 0;
550
551 if (qd->DL) {
552 qd->doc_pos = 0;
553 MoreDocs(qd, kind, skip, howmany, sender, ptr);
554 }
555 return 0;
556}
557
558/* get all the terms that match wordstem using the current stemmer and */
559/* stemming method. The callback is the same style used by mgq_results */
560int mgq_equivterms (unsigned char *wordstem, int (*sender)(char *, int, int, float, void *),
561 void *ptr) {
562 int stem_method = 0;
563 query_data *qd = NULL;
564 TermList *equivterms = NULL; /* used for equivalent terms */
565
566 if (cur_cachenum == -1) return 0;
567 qd = dbcache[cur_cachenum].qd;
568 if (qd == NULL || wordstem == NULL || sender == NULL) return 0;
569
570 if (qd->sd->sdh.indexed) {
571 stem_method = BooleanEnv(GetEnv("casefold"),0) | (BooleanEnv(GetEnv("stem"),0) << 1);
572 } else {
573 stem_method = qd->sd->sdh.stem_method;
574 }
575
576 /* make the term list */
577 equivterms = MakeTermList (0);
578
579 /* expand out this word */
580 if (FindWords (qd->sd, wordstem, stem_method, &equivterms) > 0) {
581 int i;
582 for (i=0; i < equivterms->num; i++) {
583 (* sender)((char *)(equivterms->TE[i].Word+1), equivterms->TE[i].Word[0],
584 equivterms->TE[i].Count, (float)0.0, ptr);
585 }
586 }
587
588 /* free the term list */
589 if (equivterms != NULL) FreeTermList (&equivterms);
590
591 return 0;
592}
593
594/* gets the total number of documents retrieved. If this is not available */
595/* it will set total_retrieved to 0 (even when it obviously isn't) */
596int mgq_docsretrieved (int *total_retrieved, int *is_approx) {
597 query_data *qd = NULL;
598
599 if (cur_cachenum == -1) return 0;
600 qd = dbcache[cur_cachenum].qd;
601 if (qd == NULL || total_retrieved == NULL || is_approx == NULL) return 0;
602
603 /* set default values */
604 *total_retrieved = 0;
605 *is_approx = 0;
606
607 if (qd->DL == NULL) return 0;
608
609 *total_retrieved = qd->DL->total_retrieved;
610 *is_approx = qd->DL->is_approx;
611
612 return 0;
613}
614
615
616/* use mgq_getmaxstemlen to determine the length of the word stems to pass */
617/* to mgq_stemword */
618int mgq_getmaxstemlen () {
619 return MAXSTEMLEN;
620}
621
622/* note: the stemming method and the stemmer come from the last query */
623/* "word" should be at least maxstemlen+1 long and it is a string that */
624/* starts with the string length */
625void mgq_stemword (unsigned char *word) {
626 int stem_method = 0;
627 query_data *qd = NULL;
628
629 if (cur_cachenum == -1) return;
630 qd = dbcache[cur_cachenum].qd;
631 if (qd == NULL || word == NULL) return;
632
633 if (qd->sd->sdh.indexed) {
634 stem_method = BooleanEnv(GetEnv("casefold"),0) | (BooleanEnv(GetEnv("stem"),0) << 1);
635 } else {
636 stem_method = qd->sd->sdh.stem_method;
637 }
638
639 stemmer (stem_method, qd->sd->sdh.stemmer_num, word);
640}
641
642
643
644int is_dbcache_full (void) {
645 init_dbcache ();
646 if (cache_numloaded >= MAXNUMDATABASEINFO) return 1;
647 return 0;
648}
649
650int load_database (char *collection, char *mgdir,
651 char *gensuffix, char *textsuffix) {
652 int i = 0;
653 query_data *qd = NULL;
654 /* FILE *deb = NULL; */
655 init_dbcache ();
656
657 /* print out some debug information */
658/* deb = fopen ("/home/rjmcnab/gsdl/etc/deb.txt", "a");
659 fprintf (deb, "\ncache_nextaccessnum: %i\n", cache_nextaccessnum);
660 fprintf (deb, "cache_numloaded: %i\n", cache_numloaded);
661 fprintf (deb, "cur_cachenum: %i\n", cur_cachenum);
662 fprintf (deb, "MAXNUMDATABASEINFO: %i\n\n", MAXNUMDATABASEINFO);
663 for (i=0; i<MAXNUMDATABASEINFO; i++) {
664 fprintf (deb, "Entry %i\n", i);
665 fprintf (deb, " accessnum: %i\n", dbcache[i].accessnum);
666 fprintf (deb, " collection: %s\n", dbcache[i].collection);
667 fprintf (deb, " mgdir: %s\n", dbcache[i].mgdir);
668 fprintf (deb, " gensuffix: %s\n", dbcache[i].gensuffix);
669 fprintf (deb, " textsuffix: %s\n", dbcache[i].textsuffix);
670 fprintf (deb, " qd: %x\n", (int)(dbcache[i].qd));
671 }
672 fclose (deb); */
673
674 /* search for the index */
675 i = search_gensuffix (gensuffix);
676 if (i >= 0) {
677 make_current (i);
678 return 1;
679 }
680
681 /* if there was a current database then the */
682 /* environment needs uninitialising */
683 make_current (-1);
684
685 /* get a free cache number */
686 i = get_free_dbcache ();
687 unload_database (i);
688
689 /* load the index */
690 qd = InitQuerySystem (mgdir, gensuffix, textsuffix, NULL);
691 if (qd == NULL) return 0;
692
693 /* cache this index */
694 cache_database (i, collection, mgdir, gensuffix, textsuffix, qd);
695
696 /* make this index current */
697 make_current (i);
698
699 return 1;
700}
701
702/* load_text_database tries to make an index of the */
703/* specified collection current */
704int load_text_database (char *collection) {
705 int i = 0;
706 init_dbcache ();
707
708 /* search for the index */
709 i = search_collect (collection);
710
711 /* return if none were found */
712 if (i < 0) return 0;
713
714 /* make this index current */
715 make_current (i);
716 return 1;
717}
718
719void close_all_databases (void) {
720 int i = 0;
721 init_dbcache ();
722
723 /* unload all active databases */
724 for (i=0; i<MAXNUMDATABASEINFO; i++) {
725 unload_database (i);
726 }
727
728 /* if there was a current database then the */
729 /* environment needs uninitialising */
730 make_current (-1);
731}
Note: See TracBrowser for help on using the repository browser.