Files
Mozilla/mozilla/db/tripledb/src/windex.c
terry%mozilla.org 981fe96b56 TripleDB has been completely rewritten. Now requires Sleepycat Berkeley DB.
git-svn-id: svn://10.0.0.236/trunk@72984 18797224-902f-48f8-a5cc-f745e15eee43
2000-06-22 23:11:37 +00:00

403 lines
11 KiB
C

/* -*- Mode: C; indent-tabs-mode: nil; -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is the TripleDB database library.
*
* The Initial Developer of the Original Code is Geocast Network Systems.
* Portions created by Geocast are
* Copyright (C) 2000 Geocast Network Systems. All
* Rights Reserved.
*
* Contributor(s): Terry Weissman <terry@mozilla.org>
*/
#include <ctype.h>
#include "tdbtypes.h"
#include "tdb.h"
#include "util.h"
#include "vector.h"
#include "windex.h"
#define MAXWORDLEN 10
typedef struct {
char word[MAXWORDLEN + 1];
TDBInt32 length;
TDBUint16 position;
} WordInfo;
struct _TDBWindex {
TDBBase* base;
DB* db;
};
struct _TDBWindexCursor {
TDBWindex* windex;
char* string;
DBC* cursor;
WordInfo* winfo;
TDBInt32 numwinfo;
TDBInt32 main;
int cmdflag;
};
TDBWindex*
tdbWindexNew(TDBBase* base)
{
TDBWindex* windex;
int dbstatus;
windex = tdb_NEWZAP(TDBWindex);
if (!windex) return NULL;
windex->base = base;
dbstatus = db_create(&(windex->db), tdbGetDBEnv(base), 0);
if (dbstatus != DB_OK) goto FAIL;
dbstatus = windex->db->open(windex->db, "windex", NULL, DB_BTREE,
DB_CREATE, 0666);
if (dbstatus != DB_OK) goto FAIL;
return windex;
FAIL:
tdbWindexFree(windex);
return NULL;
}
void
tdbWindexFree(TDBWindex* windex)
{
if (windex == NULL) {
tdb_ASSERT(0);
return;
}
if (windex->db) {
windex->db->close(windex->db, 0);
}
tdb_Free(windex);
}
TDBStatus
tdbWindexSync(TDBWindex* windex)
{
if (windex == NULL) {
tdb_ASSERT(0);
return TDB_FAILURE;
}
if (windex->db->sync(windex->db, 0) != DB_OK) return TDB_FAILURE;
return TDB_SUCCESS;
}
static WordInfo*
splitIntoWords(char* str, WordInfo* winfobuf, TDBInt32 winfobuflen)
{
WordInfo* winfo;
WordInfo* tmp;
TDBInt32 cur;
TDBInt32 max;
char* ptr;
char* ptr1;
char* ptr2;
TDBInt32 i;
TDBInt32 length;
winfo = winfobuf;
max = winfobuflen - 1;
cur = 0;
for (ptr1 = str ; *ptr1 ; ptr1++) {
if (!isalnum(*ptr1)) continue;
for (ptr2 = ptr1 + 1 ; *ptr2 && isalnum(*ptr2) ; ptr2++) { }
if (ptr2 - ptr1 > 2) {
/* Should check for stopwords here. XXX */
if (cur >= max) {
max = cur + 20;
tmp = tdb_Calloc(max + 1, sizeof(WordInfo));
for (i=0 ; i<cur ; i++) {
tmp[i] = winfo[i];
}
if (winfo != winfobuf) tdb_Free(winfo);
winfo = tmp;
}
length = ptr2 - ptr1;
if (length > MAXWORDLEN) length = MAXWORDLEN;
winfo[cur].length = length;
winfo[cur].position = ptr1 - str;
for (ptr = winfo[cur].word ; length > 0 ; length--) {
*ptr++ = tolower(*ptr1++);
}
*ptr = '\0';
cur++;
}
ptr1 = ptr2;
if (!*ptr1) break;
}
if (winfo) winfo[cur].length = 0;
return winfo;
}
TDBStatus
tdbWindexAdd(TDBWindex* windex, TDBVector* vector)
{
TDBNodePtr node;
WordInfo winfobuf[20];
WordInfo* winfo;
WordInfo* wptr;
char buf[100];
DBT key;
DBT data;
char* ptr;
char* endptr;
int dbstatus;
if (windex == NULL || vector == NULL) {
tdb_ASSERT(0);
return TDB_FAILURE;
}
node = tdbVectorGetNonInternedNode(vector, 2 /* XXX Stupid hardcoding */);
if (node == NULL) return TDB_FAILURE;
if (node->type != TDBTYPE_STRING) {
return TDB_SUCCESS; /* Quietly do nothing if it's not a string. */
}
winfo = splitIntoWords(node->d.str.string, winfobuf,
sizeof(winfobuf) / sizeof(winfobuf[0]));
if (!winfo) return TDB_FAILURE;
memset(&key, 0, sizeof(key));
memset(&data, 0, sizeof(data));
for (wptr = winfo ; wptr->length > 0 ; wptr++) {
ptr = buf;
endptr = buf + sizeof(buf);
tdbPutString(&ptr, wptr->word, endptr);
tdbPutPtr(&ptr, tdbVectorGetRecordNumber(vector), endptr);
tdbPutUInt16(&ptr, (TDBUint16) wptr->position, endptr);
if (ptr >= endptr) {
tdb_ASSERT(0);
} else {
key.size = ptr - buf;
key.data = buf;
dbstatus = windex->db->put(windex->db,
tdbGetTransaction(windex->base),
&key, &data, 0);
if (dbstatus != DB_OK) return TDB_FAILURE;
}
}
if (winfo != winfobuf) {
tdb_Free(winfo);
}
return TDB_SUCCESS;
}
TDBStatus
tdbWindexRemove(TDBWindex* windex, TDBVector* vector)
{
TDBNodePtr node;
WordInfo winfobuf[20];
WordInfo* winfo;
WordInfo* wptr;
DBT key;
DBT data;
char* ptr;
char* endptr;
char buf[100];
int dbstatus;
if (windex == NULL || vector == NULL) {
tdb_ASSERT(0);
return TDB_FAILURE;
}
node = tdbVectorGetNonInternedNode(vector, 2 /* XXX Stupid hardcoding */);
if (node == NULL) return TDB_FAILURE;
if (node->type != TDBTYPE_STRING) {
return TDB_SUCCESS; /* Quietly do nothing if it's not a string. */
}
winfo = splitIntoWords(node->d.str.string, winfobuf,
sizeof(winfobuf) / sizeof(winfobuf[0]));
if (!winfo) return TDB_FAILURE;
memset(&key, 0, sizeof(key));
memset(&data, 0, sizeof(data));
for (wptr = winfo ; wptr->length > 0 ; wptr++) {
ptr = buf;
endptr = buf + sizeof(buf);
tdbPutString(&ptr, wptr->word, endptr);
tdbPutPtr(&ptr, tdbVectorGetRecordNumber(vector), endptr);
tdbPutUInt16(&ptr, (TDBUint16) wptr->position, endptr);
if (ptr >= endptr) {
tdb_ASSERT(0);
} else {
key.size = ptr - buf;
key.data = buf;
dbstatus = windex->db->del(windex->db,
tdbGetTransaction(windex->base),
&key, 0);
if (dbstatus != DB_OK) return TDB_FAILURE;
}
}
if (winfo != winfobuf) {
tdb_Free(winfo);
}
return TDB_SUCCESS;
}
TDBWindexCursor*
tdbWindexGetCursor(TDBWindex* windex, const char* string)
{
DBT key;
DBT data;
int dbstatus;
TDBWindexCursor* cursor;
TDBInt32 i;
TDBInt32 l;
if (windex == NULL || string == NULL) {
tdb_ASSERT(0);
return NULL;
}
cursor = tdb_NEWZAP(TDBWindexCursor);
if (!cursor) return NULL;
cursor->windex = windex;
cursor->string = tdb_strdup(string);
if (!cursor->string) goto FAIL;
cursor->winfo = splitIntoWords(cursor->string, NULL, 0);
if (cursor->winfo == NULL) goto FAIL;
cursor->main = 0;
cursor->cmdflag = DB_CURRENT;
for (i=0 ; cursor->winfo[i].length > 0 ; i++) {
l = cursor->winfo[i].length;
if (l > cursor->winfo[cursor->main].length) {
cursor->main = i;
}
cursor->numwinfo = i + 1;
}
if (cursor->numwinfo == 0) goto FAIL;
dbstatus = windex->db->cursor(windex->db, NULL,
&(cursor->cursor), 0);
if (dbstatus != DB_OK) goto FAIL;
memset(&key, 0, sizeof(key));
memset(&data, 0, sizeof(data));
key.data = cursor->winfo[cursor->main].word;
key.size = cursor->winfo[cursor->main].length + 1;
dbstatus = cursor->cursor->c_get(cursor->cursor, &key, &data,
DB_SET_RANGE);
if (dbstatus != DB_OK && dbstatus != DB_NOTFOUND) goto FAIL;
return cursor;
FAIL:
tdbWindexCursorFree(cursor);
return NULL;
}
TDBStatus
tdbWindexCursorFree(TDBWindexCursor* cursor)
{
if (!cursor) {
tdb_ASSERT(0);
return TDB_FAILURE;
}
if (cursor->string) tdb_Free(cursor->string);
if (cursor->cursor) cursor->cursor->c_close(cursor->cursor);
if (cursor->winfo) tdb_Free(cursor->winfo);
tdb_Free(cursor);
return TDB_SUCCESS;
}
TDBVector*
tdbWindexGetCursorValue(TDBWindexCursor* cursor)
{
TDBInt32 l;
DBT key;
DBT data;
TDBBool match;
TDBPtr recordnum;
TDBInt32 position;
TDBInt32 p;
char* ptr;
char* endptr;
TDBInt32 i;
char buf[MAXWORDLEN + 20];
int dbstatus;
TDBWindex* windex;
TDBVector* vector;
TDBNodePtr node;
if (cursor == NULL) {
tdb_ASSERT(0);
return NULL;
}
windex = cursor->windex;
while (1) {
memset(&key, 0, sizeof(key));
memset(&data, 0, sizeof(data));
dbstatus = cursor->cursor->c_get(cursor->cursor, &key, &data,
cursor->cmdflag);
cursor->cmdflag = DB_NEXT;
if (dbstatus != DB_OK) return NULL;
l = cursor->winfo[cursor->main].length;
if (key.size <= l ||
memcmp(key.data, cursor->winfo[cursor->main].word, l + 1) != 0) {
/* We're past the end of matching things. */
return NULL;
}
ptr = key.data + l + 1;
endptr = key.data + key.size;
recordnum = tdbGetPtr(&ptr, endptr);
position = tdbGetUInt16(&ptr, endptr);
position -= cursor->winfo[cursor->main].position;
match = TDB_TRUE;
for (i=0 ; i<cursor->numwinfo ; i++) {
if (i == cursor->main) continue;
p = position + cursor->winfo[i].position;
if (p < 0) {
match = TDB_FALSE;
break;
}
ptr = buf;
endptr = buf + sizeof(buf);
tdbPutString(&ptr, cursor->winfo[i].word, endptr);
tdbPutPtr(&ptr, recordnum, endptr);
tdbPutUInt16(&ptr, p, endptr);
key.data = buf;
key.size = ptr - buf;
memset(&data, 0, sizeof(data));
dbstatus = windex->db->get(windex->db,
tdbGetTransaction(windex->base),
&key, &data, 0);
if (dbstatus != DB_OK) {
match = TDB_FALSE;
break;
}
}
if (match) {
vector = tdbVectorNewFromRecord(windex->base, recordnum);
node = tdbVectorGetNonInternedNode(vector, 2);
if (node && node->type == TDBTYPE_STRING &&
tdb_strcasestr(node->d.str.string, cursor->string) != NULL) {
return vector;
}
tdbVectorFree(vector);
}
}
}