/* open.c -- Copyright 1994, 1995, 1996 Liam R. Quin. * All Rights Reserved. * This code is NOT in the public domain. * See the file COPYRIGHT for full details. * * $Id: open.c,v 1.8 1996/08/14 16:55:25 lee Exp $ * * Open a database... */ #include "error.h" #include #include #include #include "globals.h" #ifdef HAVE_STRING_H # include #else # include #endif #ifdef HAVE_FCNTL_H # ifdef HAVE_SYSV_FCNTL_H # include # endif # include #endif #include "lqutil.h" #include "liblqtext.h" #include "lqconfig.h" #include "emalloc.h" #include "lqtrace.h" LIBRARY void LQTp_InitialiseCharacterTypes( # ifdef HAVE_PROTO t_LQTEXT_Database *db # endif ); LIBRARY t_LQTEXT_Database * LQTpCreateLQTEXTDatabase(Options, flags, modes) t_lqdbOptions *Options; int flags; int modes; { t_LQTEXT_Database *db; db = (t_LQTEXT_Database *) emalloc("new database object", sizeof(t_LQTEXT_Database)); db->UsedInternally = (unsigned char *) Options; db->FileFlags = flags; db->FileModes = modes; db->LQTp__LastNextWIDVal = (t_WID) 0; db->LQTp__LastNextFIDVal = (t_FID) 0; db->DatabaseDirectory = Options->directory.Value; db->DataBase = LQU_joinstr2(db->DatabaseDirectory, "/data"); db->WidIndexFile = LQU_joinstr2(db->DatabaseDirectory, "/widindex"); db->FreeFileName = LQU_joinstr2(db->DatabaseDirectory, "/freelist"); db->LastBlockFile = LQU_joinstr2(db->DatabaseDirectory, "/lastblks"); db->DocPath = Options->filesearchpath.Value; db->MinWordLength = LQC_DEFAULT_MinWordLength; /* 2 */ db->MaxWordLength = LQC_DEFAULT_MaxWordLength; /* 18 */ db->CommonWordsLow = 0; /* no common words yet */ db->CommonWordsHigh = 0; db->WordsInWordIndex = 1; /* 1 = Yes, 0 = No */ db->IndexNumbers = 1; /* 1 = Yes, 0 = No */ db->PhraseMatchLevel = Options->phrasematchlevel.Value; db->IgnoreHTMLhead = 0; /* 1 = Yes, ignore it, 0 = No, index it */ db->ConfigurationFile = "config"; db->Options = *Options; /* structure copy */ db->FileBlockSize = 0; LQTpReadDefaultFile(db); /* may change some members */ if (db->Options.stoplist.Value) { if (db->Options.stoplist.Value[0] != '/' && db->Options.stoplist.Value[0] != '.' ) { db->CommonWordFile = LQU_joinstr3( db->DatabaseDirectory, "/", db->Options.stoplist.Value ); } else { db->CommonWordFile = db->Options.stoplist.Value; } } else { db->CommonWordFile = 0; } /* The Following is for *.WordPlace.BlockInFile. If words are * constrained to be 3 or more characters long, there can be at most * (FileBlockSize / 4) of them in a block (since words must be separated * by at least one character). * Hence, 7 bits, which allows 0..127 giving 128 distinct values, * gives us a block that is 128 * (MinWordLength + 1) bytes long. * In practice, that's an unlikely worst case, and we should optimise * for the normal case, which says about 6 letters per word. * This is possible because WordInBlock is actually stored as a long. */ if (!db->FileBlockSize) { if (db->MinWordLength <= 5) { db->FileBlockSize = 6 * 128; } else { db->FileBlockSize = ((db)->MinWordLength + 1) * 128; } } db->FileIndex = LQTp_CreateEmptyKeyValueDatabase( db, db->DatabaseDirectory, "filelist" ); db->WordIndex = LQTp_CreateEmptyKeyValueDatabase( db, db->DatabaseDirectory, "wordlist" ); /* TODO: include this in db, not as a static variable! */ (void) LQTp_MakeDocPath(db, db->DocPath); if (db->CommonWordFile) { (void) LQT_ReadStopList(db, db->CommonWordFile); } /** Arrange for the database to be closed again... ** Actions are performed in _reverse_ order, so we register ** first ones that use lower-level routines... **/ LQT_AddActionOnClose( db, "Write out cached low-level data blocks", LQT_FlushBlockCache, LQT_ON_CLOSE|LQT_ON_SYNC ); LQT_AddActionOnClose( db, "Write out largest allocated WID", LQT_WriteCurrentMaxWID, LQT_ON_CLOSE|LQT_ON_SYNC ); LQT_AddActionOnClose( db, "Write out cached WID index blocks", LQTpFlushWIDCache, LQT_ON_CLOSE|LQT_ON_SYNC ); /* the Last Block Cache is independent of other Actions */ LQT_AddActionOnClose( db, "Write out cached lastblock data", LQTp_FlushLastBlockCache, LQT_ON_CLOSE|LQT_ON_SYNC ); /* DBM databases are independent of other files, do them first */ LQT_AddActionOnClose( db, "Flush and close dbm key-value databases", LQT_SyncAndCloseAllKeyValueDatabases, LQT_ON_CLOSE|LQT_ON_SYNC ); return db; } /* * LQT_OpenDatabase * Database/Database * *

Opens the lq-text database referred to in the given Options object; * flags and modes are as for open(2), although in all cases the * lq-text directory must already exist.

*

The only valid Options object at the moment is the * value returned by LQT_InitFromArgv, which can only be called once * during the lifetime of a process.

* * Since you can currently only have a single database open in any * given program, there is not yet a need for a way to open a * specific database; this will change in the next release. * * A pointer to an opaque object describing the database. * The pointer is suitable for use with LQT_CloseDatabase. * * LQT_InitFromArgv * LQT_CloseDatabase *
*/ API t_LQTEXT_Database * LQT_OpenDatabase(Options, flags, modes) t_lqdbOptions *Options; int flags; int modes; { t_LQTEXT_Database *db = 0; if (!Options) { Error(E_FATAL|E_INTERNAL, "LQT_OpenDatabase called with null database options pointer" ); } if (!Options->directory.Value || !*Options->directory.Value) { Error(E_FATAL|E_INTERNAL, "LQT_OpenDatabase: no LQTEXT directory given in Options argument" ); } if (!LQU_IsDir(Options->directory.Value)) { Error(E_FATAL|E_SYS, "lq-text database \"%s\" is not a directory", Options->directory.Value ); } LQT_Trace(LQTRACE_VERBOSE|LQTRACE_DEBUG, "open database \"%s\"", Options->directory.Value ); db = LQTpCreateLQTEXTDatabase(Options, flags, modes); /* this is always here -- it's only checked once, and is actually * rather useful. */ #ifdef ASCIITRACE if (LQT_TraceFlagsSet(LQTRACE_DEBUG)) { fprintf(stderr, "%s: DatabaseDirectory = \"%s\"\n", progname, db->DatabaseDirectory); if (db->CommonWordFile) { fprintf(stderr, "%s: CommonWordFile = \"%s\"\n", progname, db->CommonWordFile); } else { fprintf(stderr, "%s: CommonWordFile unset\n", progname); } fprintf(stderr, "%s: DocPath = \"%s\"\n", progname, db->DocPath); } #endif /* prepare isupper, islower, etc... */ LQTp_InitialiseCharacterTypes(db); if ((modes & O_WRONLY) || (modes & O_RDWR)) { (void) LQT_ObtainWriteAccess(db); } else { (void) LQT_ObtainReadOnlyAccess(db); } return db; }