You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdesdk/kbabel/kbabeldict/modules/dbsearchengine/database.cpp

1534 lines
31 KiB

/***************************************************************************
database.cpp -
-------------------
begin : Fri Sep 8 2000
copyright : (C) 2000 by Andrea Rizzi
email : rizzi@kde.org
***************************************************************************/
/*
Translation search engine
Copyright 2000
Andrea Rizzi rizzi@kde.org
Copyright 2003 Stanislav Visnovsky visnovsky@kde.org
License GPL v 2.0
* *
* In addition, as a special exception, the copyright holders give *
* permission to link the code of this program with any edition of *
* the TQt library by Trolltech AS, Norway (or with modified versions *
* of TQt that use the same license as TQt), and distribute linked *
* combinations including the two. You must obey the GNU General *
* Public License in all respects for all of the code used other than *
* TQt. If you modify this file, you may extend this exception to *
* your version of the file, but you are not obligated to do so. If *
* you do not wish to do so, delete this exception statement from *
* your version. *
*/
#include <stdlib.h>
#include <kdebug.h>
#include <string.h>
#include <resources.h>
#include "database.h"
#include <unistd.h>
#include <tqfile.h>
#include <tdetempfile.h>
#include <tdeio/netaccess.h>
WordItem::WordItem (char *data, TQString w)
{
word = w;
count = *(uint32 *) data;
data += 4;
//score=*(int *)data;
data += 4;
locations = (uint32 *) malloc (4 * count);
memcpy (locations, data, 4 * count);
}
WordItem::WordItem (TQString w)
{
locations = NULL;
count = 0;
word = w;
score = -1; // it means no references found.
}
/*
WordItem::WordItem(const WordItem &wi)
{
count=wi.count;
score=wi.score;
word=wi.word;
locations.duplicate(wi.locations);
locations.detach();
}
WordItem& WordItem::operator=(const WordItem & wi )
{
WordItem *i=new WordItem(wi);
i->locations.detach();
return *i;
}
*/
bool
WordItem::notFound ()
{
return (score == -1);
}
InfoItem::InfoItem ()
{
catalogName = "No catalog";
lastTranslator = "No translator";
lastFullPath = "";
charset = "No charset";
language = "No language";
}
InfoItem::InfoItem (const char *rawData, TQString lang)
{
const char *rd;
rd = rawData;
int len;
unsigned int secs;
// I'll change the charset handling if needed
charset = "Utf8";
catalogName = TQString::fromUtf8 (rd);
len = strlen (rd) + 1;
rd += len;
lastTranslator = TQString::fromUtf8 (rd);
len = strlen (rd) + 1;
rd += len;
secs = *(unsigned int *) rd;
revisionDate.setTime_t (secs);
rd += 4;
lastFullPath = TQString::fromUtf8 (rd);
len = strlen (rd) + 1;
rd += len;
language = lang;
}
void
InfoItem::rawData (char *rawData)
{
char *rd;
rd = rawData;
strcpy (rd, catalogName.utf8 ());
rd += strlen (rd) + 1;
strcpy (rd, lastTranslator.utf8 ());
rd += strlen (rd) + 1;
//TQDate Time problem!!!!!!!!!!!
TQDateTime zeroDate;
zeroDate.setTime_t (0);
*(unsigned int *) rd = -revisionDate.secsTo (zeroDate);
rd += 4;
strcpy (rd, lastFullPath.utf8 ());
rd += strlen (rd) + 1;
*rd = 0; //Empty for further info
}
int
InfoItem::size ()
{
int _size;
_size = 0;
_size += 1; // 1 Empty field;
_size += 3; // Terminating \0 of next 3 strings
_size += 4; // Int size (date)
_size += strlen (catalogName.utf8 ());
_size += strlen (lastTranslator.utf8 ());
_size += strlen (lastFullPath.utf8 ());
return _size;
}
// this is a quick hack to copy a local file
int
copy_hack (TQFile & input, TQFile & output)
{
if (!input.isOpen ())
{
if (!input.open (IO_ReadOnly))
return -1;
}
if (!output.isOpen ())
{
if (!output.open (IO_WriteOnly))
return -1;
}
char buffer[10240];
int s = 0;
while (!input.atEnd ())
{
s = input.readBlock (buffer, 10240);
output.writeBlock (buffer, s);
}
output.close ();
input.close ();
return 0;
}
DataBaseItem::DataBaseItem ()
{
numTra = 0;
location = 0;
}
DataBaseItem::DataBaseItem (char *_key, char *_data)
{
char *data = _data;
key = TQString::fromUtf8 (_key);
unsigned int i, r;
numTra = *(uint32 *) data;
data += 4;
location = *(uint32 *) data;
data += 4;
for (i = 0; i < numTra; i++)
{
TranslationItem tr;
tr.numRef = *(uint32 *) data;
data += 4;
for (r = 0; r < tr.numRef; r++)
{
int ref;
ref = *(uint32 *) data;
data += 4;
tr.infoRef.append (ref);
}
tr.translation = TQString::fromUtf8 ((const char *) data);
translations.append (tr);
data += strlen (data) + 1;
}
}
uint32
DataBaseItem::sizeKey ()
{
return strlen (key.utf8 ()) + 1;
}
uint32
DataBaseItem::sizeData ()
{
unsigned int i, _size = 4;
_size += numTra * 4;
_size += 4; // location
for (i = 0; i < numTra; i++)
{
_size += strlen (translations[i].translation.utf8 ()) + 1; // +1 is for \0
_size += translations[i].numRef * 4;
}
return _size;
}
void
DataBaseItem::toRawKey (char *_key)
{
strcpy (_key, key.utf8 ());
}
void
DataBaseItem::toRawData (char *_data)
{
char *data = _data;
unsigned int i, r;
*(uint32 *) data = numTra;
data += 4;
*(uint32 *) data = location;
data += 4;
for (i = 0; i < numTra; i++)
{
TranslationItem tr (translations[i]);
*(uint32 *) data = tr.numRef;
data += 4;
for (r = 0; r < tr.numRef; r++)
{
*(uint32 *) data = tr.infoRef[r]; //sub i with r
data += 4;
}
strcpy ((char *) data, tr.translation.utf8 ());
data += strlen (tr.translation.utf8 ()) + 1;
}
}
DataBaseManager::DataBaseManager (TQString directory, TQString lang,
TQObject * parent, const char *name):
TQObject (parent, name)
{
TQString filename;
language = lang;
iAmOk = true;
basedir = directory;
indexDb = wordDb = infoDb = db = 0;
openDataBase ();
}
void
DataBaseManager::openDataBase ()
{
kdDebug () << "Opendatabase" << endl;
TQString directory;
directory = basedir;
TQString ll = "." + language;
if (ll == ".")
ll = ".NOLANG";
TQString transfilename = "%1/translations%2.db";
transfilename = transfilename.arg (directory).arg (ll);
TQString infofilename = "%1/catalogsinfo%2.db";
infofilename = infofilename.arg (directory).arg (ll);
TQString wordsfilename = "%1/wordsindex%2.db";
wordsfilename = wordsfilename.arg (directory).arg (ll);
TQString keysfilename = "%1/keysindex%2.db";
keysfilename = keysfilename.arg (directory).arg (ll);
cursor = 0;
int ret;
if (!db)
db_create (&db, 0, 0);
db_create (&infoDb, 0, 0);
db_create (&wordDb, 0, 0);
db_create (&indexDb, 0, 0);
ret = db->open (db,
#if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR > 0) || (DB_VERSION_MAJOR >= 5)
NULL,
#endif
transfilename.local8Bit (), 0, DB_BTREE, 0, 0644);
if (ret == DB_OLD_VERSION)
{
kdDebug (KBABEL_SEARCH) << "Trying upgrade" << endl;
// try upgrade
KTempFile transFile, infoFile, keysFile, wordsFile;
// do the upgrade on the translation file
TQFile transfilenameFile (transfilename);
if ((ret = copy_hack (transfilenameFile, *transFile.file ())) == 0)
{
ret = db->upgrade (db, transFile.name ().local8Bit (), 0);
}
if (ret != 0)
{
kdDebug (KBABEL_SEARCH) << "Cannot upgrade translations, " <<
ret << endl;
// cleanup
transFile.unlink ();
iAmOk = false;
emit cannotOpenDB (ret);
return;
}
// do the upgrade on the info file
TQFile infofilenameFile (infofilename);
if ((ret = copy_hack (infofilenameFile, *infoFile.file ())) == 0)
{
ret =
infoDb->upgrade (infoDb, infoFile.name ().local8Bit (),
0);
}
if (ret != 0)
{
kdDebug (KBABEL_SEARCH) << "Cannot upgrade catalogsinfo" <<
endl;
// cleanup
transFile.unlink ();
infoFile.unlink ();
iAmOk = false;
emit cannotOpenDB (ret);
return;
}
// do the upgrade on the words file
TQFile wordfilenameFile (wordsfilename);
if ((ret = copy_hack (wordfilenameFile, *wordsFile.file ())) == 0)
{
ret =
wordDb->upgrade (wordDb, wordsFile.name ().local8Bit (),
0);
}
if (ret != 0)
{
kdDebug (KBABEL_SEARCH) << "Cannot upgrade words" << endl;
// cleanup
transFile.unlink ();
infoFile.unlink ();
wordsFile.unlink ();
iAmOk = false;
emit cannotOpenDB (ret);
return;
}
// do the upgrade on the keys file
TQFile keysfilenameFile (keysfilename);
if ((ret = copy_hack (keysfilenameFile, *keysFile.file ())) == 0)
{
ret =
indexDb->upgrade (indexDb, keysFile.name ().local8Bit (),
0);
}
if (ret != 0)
{
kdDebug (KBABEL_SEARCH) << "Cannot upgrade keys" << endl;
// cleanup
transFile.unlink ();
infoFile.unlink ();
wordsFile.unlink ();
keysFile.unlink ();
iAmOk = false;
emit cannotOpenDB (ret);
return;
}
kdDebug (KBABEL_SEARCH) << "Files upgraded, copying" << endl;
// use temporary file instead
if (ret == 0)
{
TDEIO::NetAccess::del (KURL::fromPathOrURL (transfilename));
copy_hack (*transFile.file (), transfilenameFile);
transFile.unlink ();
TDEIO::NetAccess::del (KURL::fromPathOrURL (infofilename));
copy_hack (*infoFile.file (), infofilenameFile);
infoFile.unlink ();
TDEIO::NetAccess::del (KURL::fromPathOrURL (wordsfilename));
copy_hack (*wordsFile.file (), wordfilenameFile);
wordsFile.unlink ();
TDEIO::NetAccess::del (KURL::fromPathOrURL (keysfilename));
copy_hack (*keysFile.file (), keysfilenameFile);
keysFile.unlink ();
ret = db->open (db,
#if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR > 0) || (DB_VERSION_MAJOR >= 5)
NULL,
#endif
transfilename.local8Bit (), 0, DB_BTREE, 0,
0644);
if (ret != 0)
{
kdWarning (KBABEL_SEARCH) <<
"transFilename database can't be opened." << endl;
kdWarning (KBABEL_SEARCH) <<
"Please, report this incident and how to reproduce it to kbabel@kde.org."
<< endl;
iAmOk = false;
emit cannotOpenDB (ret);
return;
}
}
kdDebug (KBABEL_SEARCH) << "Upgrade done OK" << endl;
}
// Open catalogs information database
ret = infoDb->open (infoDb,
#if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR > 0) || (DB_VERSION_MAJOR >= 5)
NULL,
#endif
infofilename.local8Bit (), 0, DB_RECNO, 0, 0644);
if (ret != 0)
{
iAmOk = false;
emit cannotOpenDB (ret);
//Process error here.
}
else
loadInfo ();
// Words index database
ret = wordDb->open (wordDb,
#if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR > 0) || (DB_VERSION_MAJOR >= 5)
NULL,
#endif
wordsfilename.local8Bit (), 0, DB_BTREE, 0, 0644);
if (ret != 0)
{
iAmOk = false;
emit cannotOpenDB (ret);
//Process error here.
}
//Index of keys.
ret = indexDb->open (indexDb,
#if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR > 0) || (DB_VERSION_MAJOR >= 5)
NULL,
#endif
keysfilename.local8Bit (), 0, DB_RECNO, 0, 0644);
if (ret != 0)
{
iAmOk = false;
emit cannotOpenDB (ret);
//Process error here.
}
}
void
DataBaseManager::closeDataBase ()
{
if (iAmOk)
{
db->sync (db, 0);
db->close (db, 0);
infoDb->sync (infoDb, 0);
infoDb->close (infoDb, 0);
wordDb->sync (wordDb, 0);
wordDb->close (wordDb, 0);
indexDb->sync (indexDb, 0);
indexDb->close (indexDb, 0);
// can not be opened again
indexDb = wordDb = infoDb = db = 0;
}
}
// I'm not sure this is a good function !!!
void
DataBaseManager::sync ()
{
// if(iAmOk)
// {
// db->sync(db,0);
// infoDb->sync(infoDb,0);
// cursor=0;
// }
// closeDataBase();
// openDataBase();
db->sync (db, 0);
infoDb->sync (infoDb, 0);
wordDb->sync (wordDb, 0);
indexDb->sync (indexDb, 0);
loadInfo ();
}
DataBaseManager::~DataBaseManager ()
{
closeDataBase ();
}
int
DataBaseManager::putItem (DataBaseItem * item, bool ow)
{
DBT key, data;
memset (&key, 0, sizeof (DBT));
memset (&data, 0, sizeof (DBT));
bool ret;
uint32 loc = 0;
if (item->location == 0)
{
loc = item->location = appendKey (item->key);
// kdDebug(0) << "New key " << item->location << endl;
}
key.size = item->sizeKey ();
data.size = item->sizeData ();
key.data = malloc (key.size);
data.data = malloc (data.size);
item->toRawKey ((char *) key.data);
item->toRawData ((char *) data.data);
if (ow)
ret = db->put (db, 0, &key, &data, 0);
else
ret = db->put (db, 0, &key, &data, DB_NOOVERWRITE);
//check ret
if (loc != 0) //I'm new!
{
uint32 location = loc;
TQValueList < TQString > wlist;
wlist = wordsIn (item->key);
TQValueList < TQString >::Iterator wlistit;
for (wlistit = wlist.begin (); wlistit != wlist.end (); ++wlistit)
{
addLocation (*wlistit, location);
}
}
free (key.data);
free (data.data); //READ DOCU !!!!
return ret;
}
DataBaseItem
DataBaseManager::getItem (TQString key)
{
if (!iAmOk)
return DataBaseItem ();
DBT _key, data;
memset (&_key, 0, sizeof (DBT));
memset (&data, 0, sizeof (DBT));
int len = strlen (key.utf8 ());
_key.data = malloc (len + 1);
_key.size = len + 1;
strcpy ((char *) _key.data, key.utf8 ());
int ret;
ret = db->get (db, 0, &_key, &data, 0);
if (ret != 0)
{
free (_key.data);
return DataBaseItem (); //return an empty database item
}
DataBaseItem returnItem =
DataBaseItem ((char *) _key.data, (char *) data.data);
free (_key.data);
return returnItem;
}
DataBaseItem
DataBaseManager::cursorGet (uint32 flags)
{
if (!iAmOk)
return DataBaseItem ();
int re;
DBT key, data;
memset (&key, 0, sizeof (DBT));
memset (&data, 0, sizeof (DBT));
if (cursor == 0)
re = db->cursor (db, 0, &cursor, 0);
int ret;
if ((ret = cursor->c_get (cursor, &key, &data, flags)) == 0)
{
return DataBaseItem ((char *) key.data, (char *) data.data);
}
else
{
kdDebug (KBABEL_SEARCH) << TQString ("...cursor getting...%1").
arg (ret) << endl;
return DataBaseItem ();
}
}
DataBaseItem
DataBaseManager::firstItem ()
{
return cursorGet (DB_FIRST);
}
DataBaseItem
DataBaseManager::currentItem ()
{
return cursorGet (DB_CURRENT);
}
DataBaseItem
DataBaseManager::nextItem ()
{
return cursorGet (DB_NEXT);
}
bool
DataBaseManager::isOk ()
{
return iAmOk;
}
int
DataBaseManager::count ()
{
DB_BTREE_STAT *dstat = 0;
#if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 3) || (DB_VERSION_MAJOR >= 5)
db->stat (db, NULL, &dstat, DB_FAST_STAT);
#else
db->stat (db, &dstat, DB_FAST_STAT);
#endif
int ret = dstat->bt_nkeys;
free (dstat);
return ret;
}
int
DataBaseManager::current ()
{
// THIS FUNCTION SEEM TO NOT WORK (not used)
if (!iAmOk)
return 0;
DBT key, data;
memset (&key, 0, sizeof (DBT));
memset (&data, 0, sizeof (DBT));
if (cursor != 0)
db->cursor (db, 0, &cursor, 0);
cursor->c_get (cursor, &key, &data, DB_GET_RECNO);
return *(uint32 *) (data.data);
}
int
DataBaseManager::createDataBase (TQString directory,
TQString language, int mode)
{
TQString filename;
TQString ll = "." + language;
if (ll == ".")
ll = ".NOLANG";
filename = "%1/translations%2.db";
filename = filename.arg (directory).arg (ll);
rename (filename.local8Bit (), filename.local8Bit () + ",old");
//kdDebug(0) << TQString("Creating %1").arg(filename) << endl;
iAmOk = true;
int ret;
if (!db)
{
if (db_create (&db, 0, 0) != 0)
{
kdDebug() << "db_create db failed" << endl;
iAmOk = false;
return false;
}
}
db->set_flags (db, DB_RECNUM);
ret = db->open (db,
#if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR > 0) || (DB_VERSION_MAJOR >= 5)
NULL,
#endif
filename.local8Bit (), 0, DB_BTREE, DB_CREATE | DB_EXCL,
mode);
if (ret != 0)
{
kdDebug() << "db->open " << filename << " " << mode << " failed" << endl;
iAmOk = false;
}
filename = "%1/catalogsinfo%2.db";
filename = filename.arg (directory).arg (ll);
rename (filename.local8Bit (), filename.local8Bit () + ",old");
db_create (&infoDb, 0, 0);
ret = infoDb->open (infoDb,
#if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR > 0) || (DB_VERSION_MAJOR >= 5)
NULL,
#endif
filename.local8Bit (), 0, DB_RECNO, DB_CREATE, mode);
if (ret != 0)
iAmOk = false;
filename = "%1/wordsindex%2.db";
filename = filename.arg (directory).arg (ll);
rename (filename.local8Bit (), filename.local8Bit () + ",old");
db_create (&wordDb, 0, 0);
ret = wordDb->open (wordDb,
#if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR > 0) || (DB_VERSION_MAJOR >= 5)
NULL,
#endif
filename.local8Bit (), 0, DB_BTREE, DB_CREATE, mode);
if (ret != 0)
iAmOk = false;
filename = "%1/keysindex%2.db";
filename = filename.arg (directory).arg (ll);
rename (filename.local8Bit (), filename.local8Bit () + ",old");
db_create (&indexDb, 0, 0);
ret = indexDb->open (indexDb,
#if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR > 0) || (DB_VERSION_MAJOR >= 5)
NULL,
#endif
filename.local8Bit (), 0, DB_RECNO, DB_CREATE, mode);
if (ret != 0)
iAmOk = false;
if (iAmOk)
loadInfo ();
else
kdDebug (KBABEL_SEARCH) << TQString ("I am NOT ok : %1").
arg (ret) << endl;
//THIS IS WRONG, rewrite the error handling.
return iAmOk;
}
InfoItem
DataBaseManager::getCatalogInfo (int n)
{
DBT key;
DBT data;
memset (&key, 0, sizeof (DBT));
memset (&data, 0, sizeof (DBT));
key.data = &n;
key.size = 4;
//Check for errors
int ret = infoDb->get (infoDb, 0, &key, &data, 0); //DB_SET_RECNO);
if (ret)
{
return InfoItem ();
}
// kdDebug(0) << TQString("Trad %1").arg(ret) << endl;
InfoItem it ((char *) data.data, language);
//free(data.data); // Read docu for this!!!!
return it;
}
int
DataBaseManager::addCatalogInfo (InfoItem * catInfo, int cat = -1)
{
DBT data;
DBT key;
// clean up data
memset (&data, 0, sizeof (DBT));
memset (&key, 0, sizeof (DBT));
int ret = 0, err;
if (cat >= 0)
ret = cat;
key.size = 4;
key.data = &ret;
data.size = catInfo->size ();
data.data = malloc (data.size);
catInfo->rawData ((char *) data.data);
// store the catalog data into database
if (cat >= 0)
err = infoDb->put (infoDb, 0, &key, &data, 0);
else
err = infoDb->put (infoDb, 0, &key, &data, DB_APPEND);
ret = *(int *) key.data;
// Append to the list of catalogInfo
info.append (*catInfo);
// cleanup unneeded data memory
free (data.data);
return ret;
}
int
DataBaseManager::searchCatalogInfo (TQString location)
{
int n = 0;
TQValueList < InfoItem >::Iterator it;
for (it = info.begin (); it != info.end (); ++it)
{
n++;
if ((*it).catalogName == location)
return n;
}
return -1;
}
bool
DataBaseManager::putCatalogInfo (int refnum, InfoItem * catInfo)
{
DBT data;
DBT key;
memset (&key, 0, sizeof (DBT));
memset (&data, 0, sizeof (DBT));
int ret;
key.size = 4;
key.data = &refnum;
data.size = catInfo->size ();
data.data = malloc (data.size);
catInfo->rawData ((char *) data.data);
ret = infoDb->put (infoDb, 0, &key, &data, 0);
free (data.data);
return (ret == 0);
}
void
DataBaseManager::loadInfo ()
{
int nrec;
DB_BTREE_STAT *stat;
// memset(&stat,0,sizeof(DB_BTREE_STAT));
#if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 3) || (DB_VERSION_MAJOR >= 5)
if (infoDb->stat (infoDb, NULL, &stat, DB_FAST_STAT))
fprintf (stderr, "Cannot stat\n");
#else
if (infoDb->stat (infoDb, &stat, DB_FAST_STAT))
fprintf (stderr, "Cannot stat\n");
#endif
nrec = stat->bt_nkeys;
free (stat);
info.clear ();
for (int i = 1; i <= nrec; i++) // I think DB2 Recno are 1 based.
{
info.append (getCatalogInfo (i));
}
}
TQValueList < TQString > DataBaseManager::wordsIn (TQString string)
{
TQString
a;
TQValueList < TQString > words;
int
i,
l;
a = string.simplifyWhiteSpace ();
a = a.stripWhiteSpace ();
a = a.lower ();
l = a.length ();
int
c = 0;
//words.setAutoDelete(true); //Not sure... check if it is en.
TQString
m;
for (i = 0; i < l; i++)
if (a[i].isLetterOrNumber ())
{
m += a[i];
}
else if (a[i].isSpace ())
{
words.append (m);
c++; // C++ ;-)
m = "";
}
words.append (m);
return words;
}
WordItem
DataBaseManager::getWordLocations (TQString word)
{
TQString keystring = word.lower ();
DBT key;
DBT data;
char *keydata;
int intlen = strlen (keystring.utf8 ());
keydata = (char *) malloc (intlen + 1);
strcpy (keydata, keystring.utf8 ());
memset (&key, 0, sizeof (DBT));
memset (&data, 0, sizeof (DBT));
key.data = keydata;
key.size = intlen + 1;
//Check for errors
int ret = wordDb->get (wordDb, 0, &key, &data, 0); //DB_SET_RECNO);
//MAYBE THIS WORD IS NO WHERE!!
if (ret)
{
free (keydata);
return WordItem (keystring);
}
WordItem it ((char *) data.data, keystring);
free (keydata);
// kdDebug(0) << ((uint32 *)it.locations.data())[0] << endl;
return it;
}
bool
DataBaseManager::addLocation (TQString word, unsigned int location)
{
TQString keystring = word.lower ();
DBT key;
DBT data;
char *keydata;
char *newdata;
int intlen = strlen (keystring.utf8 ());
keydata = (char *) malloc (intlen + 1);
strcpy (keydata, keystring.utf8 ());
memset (&key, 0, sizeof (DBT));
memset (&data, 0, sizeof (DBT));
key.data = keydata;
key.size = intlen + 1;
strcpy ((char *) key.data, keystring.utf8 ());
//Check for errors
int ret = wordDb->get (wordDb, 0, &key, &data, 0); //DB_SET_RECNO);
//Check if you get something or not
if (ret == 0) // CHANGE IT!!!!! if found something
{
uint32 *d;
d = (uint32 *) data.data;
uint32 num = d[0];
uint32 loc = 0; //Position from 0 to num-1
int totalrecord = count ();
uint32 step = 1;
int antibounce = 0;
//d+=4;
//int score=d[1];
//d+=4;
bool forward, end = false;
d[1] = 0; //Before the begin...
d += 2; //1 uint32!
//Try to guess...
loc = location * num / totalrecord + 1;
if (loc >= num)
loc = num - 1;
//Continue if next is smaller or if previous is greater
//before the while check if it is ok
if (loc == 0)
{
if (d[loc] > location)
end = true;
else
loc = 1;
}
if ((loc == num) && !end)
{
if (d[loc - 1] < location)
end = true;
else
loc = num - 1;
}
while ((!end) && ((forward = (d[loc]) < location)
|| ((loc > 0) && (d[loc - 1] > location))))
{
antibounce++;
//calculate step or use antibounce
if (labs ((int) d[loc] - (int) location) < 50
|| antibounce > 100)
step = 1; //Go linear...
else
{
step =
(labs (d[loc] - location) * num) / totalrecord + 1;
}
kdDebug (KBABEL_SEARCH) << "Insert:" << location <<
" We are at: " << loc << " i.e. " << d[loc] << " Step:"
<< step << endl;
if (loc > 0)
{
if (forward)
kdDebug (KBABEL_SEARCH) << "Go " << "forward" <<
" prev is " << d[loc - 1] << endl;
else
kdDebug (KBABEL_SEARCH) << "Go " << "backward" <<
" prev is " << d[loc - 1] << endl;
}
if (forward)
{
if (loc + step < num)
loc += step; // Go forward
else
loc = num; // Go to num
}
else
{
if (loc > step)
loc -= step; //Go backward
else
loc = 0; // Go to 0
}
//Now check if I am in the right place [THIS IS NOT NECESSARY]
//check if loc and loc -1 are well defined 1<loc<num-1
if (loc > num)
loc = num; //Must not happen, idem
if (loc == 0)
{
if (d[loc] > location)
end = true;
else
loc = 1;
}
if ((loc == num) && !end)
{
if (d[loc - 1] < location)
end = true;
else
loc = num - 1;
}
}
if (loc == num)
kdDebug (KBABEL_SEARCH) << "END" << endl;
if (loc == 0)
kdDebug (KBABEL_SEARCH) << "BEGIN" << endl;
if (loc > 0)
kdDebug (KBABEL_SEARCH) << location << " inserted between " <<
d[loc - 1] << " and " << d[loc] << endl;
if ((loc < num && location == d[loc]) || (loc > 0 && location == d[loc - 1])) //What about word repetition
{
free (keydata);
return true; //Why true ??
}
//Now insert and put back in the database!
newdata = (char *) malloc (4 * (num + 3)); //uint32*(num+score+1..NUM+new)
memcpy (newdata, data.data, 4 + 4 + 4 * loc);
char *secondpart = (char *) data.data;
secondpart += 4 * (loc + 2);
memcpy ((newdata + 4 * (loc + 3)), secondpart, (num - loc) * 4);
uint32 *intdata = (uint32 *) newdata;
intdata[0] = num + 1;
//ADD HERE code to recalc score
intdata[loc + 2] = location;
//ok send it to database!
memset (&data, 0, sizeof (DBT));
data.data = newdata;
data.size = 4 * (3 + num);
} //found sounthing
else
{ //found nothing
newdata = (char *) malloc (4 * 3);
uint32 *intdata = (uint32 *) newdata;
intdata[0] = 1;
intdata[1] = 1;
intdata[2] = location;
memset (&data, 0, sizeof (DBT));
data.data = newdata;
data.size = 4 * 3;
}
memset (&key, 0, sizeof (DBT));
//memset(&data,0,sizeof(DBT));
key.data = keydata;
key.size = intlen + 1;
ret = wordDb->put (wordDb, 0, &key, &data, 0); //DB_SET_RECNO);
free (newdata);
free (keydata);
//return it;
return true;
}
bool
DataBaseManager::removeLocation (TQString /*word */ , int /*location */ )
{
//#warning TODO: REMOVE LOCATION
return true;
}
uint32
DataBaseManager::appendKey (TQString _key)
{
DBT key;
DBT data;
memset (&key, 0, sizeof (DBT));
memset (&data, 0, sizeof (DBT));
uint32 ret = 0, err;
key.size = 4;
key.data = &ret;
data.size = strlen (_key.utf8 ()) + 1;
data.data = malloc (data.size);
strcpy ((char *) data.data, _key.utf8 ());
err = indexDb->put (indexDb, 0, &key, &data, DB_APPEND);
if (err)
ret = 0;
else
ret = *(uint32 *) key.data;
//kdDebug(0) << TQString("Append result %1,err = %1").arg(ret).arg(err) << endl;
free (data.data);
return ret;
}
TQString
DataBaseManager::getKey (uint32 n)
{
DBT key;
DBT data;
memset (&key, 0, sizeof (DBT));
memset (&data, 0, sizeof (DBT));
key.data = &n;
key.size = 4;
//Check for errors
int ret = indexDb->get (indexDb, 0, &key, &data, 0); //DB_SET_RECNO);
if (ret)
return TQString();
return TQString::fromUtf8 ((char *) data.data);
// kdDebug(0) << TQString("Trad %1").arg(ret) << endl;
}
int
DataBaseManager::catalogRef (TQString location, TQString author, TQString path)
{
InfoItem cinfo;
int cat, catnum;
cat = searchCatalogInfo (location);
if (cat == -1) //Not exist
{
cinfo.catalogName = location;
cinfo.lastTranslator = author;
cinfo.lastFullPath = path;
//TO DO:
// //Add date info
kdDebug (0) << "New catalog " << endl;
catnum = addCatalogInfo (&cinfo);
//sync();
kdDebug (0) << "Ref " << catnum << endl;
}
else
{
cinfo = getCatalogInfo (cat);
//Update date.
//last path must be updated
cinfo.lastFullPath = path;
kdDebug (0) << "New full path " << path << endl;
kdDebug (0) << "Ref " << cat << endl;
catnum = addCatalogInfo (&cinfo, cat);
kdDebug (0) << " must be equal to " << catnum << endl;
catnum = cat;
}
return catnum;
}
int
DataBaseManager::putNewTranslation (TQString key, TQString tran, int catalog,
bool ow)
{
int catnum = catalog;
int count = 0;
TQString msgid = key;
DataBaseItem dbit = getItem (msgid);
if (dbit.numTra == 0) //Not found
{
dbit.numTra += 1;
// use local variable, dbit.translations is TQValueList and
// will create own copy
TranslationItem tra;
tra.numRef = 1;
tra.translation = tran;
tra.infoRef.append (catnum);
dbit.translations.append (tra);
dbit.key = key;
//Check ret value
count++;
int aa = putItem (&dbit);
if (aa)
kdDebug (0) << TQString ("-----------put code ") << aa << endl;
}
else
{
// key exists
TQString msgstr = tran;
bool found_catalog_info = false, foundTr = false, isThisOne = false;
TQValueList < TranslationItem >::Iterator ittr;
bool rem = false;
// check all translations in the list
for (ittr = dbit.translations.begin ();
ittr != dbit.translations.end (); rem ? ittr : ++ittr)
{
rem = false;
found_catalog_info = false;
// is the translation one we should put there?
isThisOne = (*ittr).translation == msgstr;
// is there the catnum we are looking for?
if ((*ittr).infoRef.find (catnum) != (*ittr).infoRef.end ())
{
found_catalog_info = true;
if (ow && !isThisOne)
{
// I'll look for my catalog reference to del old
kdDebug (0) << "Removing the old translation " << endl;
(*ittr).numRef -= 1;
(*ittr).infoRef.remove (catnum);
if ((*ittr).numRef == 0)
{
dbit.numTra -= 1;
// point the iterator to the next valid item
ittr = dbit.translations.remove (ittr);
rem = true;
}
}
}
if (isThisOne)
{
if (!found_catalog_info)
{
//There are no reference of this catalog for this translation => add it
(*ittr).infoRef.append (catnum);
(*ittr).numRef += 1;
}
foundTr = true; // Ok, we found this translation, no need to add it.
}
}
if (!foundTr) //This translation is new => Add it !
{
count++;
TranslationItem tra;
tra.numRef = 1;
tra.translation = msgstr;
tra.infoRef.append (catnum);
dbit.translations.append (tra);
dbit.numTra += 1;
}
//put the new item in database overwriting the old one.
//Check ret value
int aa = putItem (&dbit, true);
if (aa)
kdDebug (0) << TQString ("-----------put code ") << aa << endl;
}
return count;
}
void
DataBaseManager::rebuildIndexes ()
{
// uint32 loc;
#if 0
//Reset the 2 databases here.
while (0 /*browse keys here */ )
{
loc = item->location = appendKey (item->key);
uint32 location = loc;
TQValueList < TQString > wlist;
wlist = wordsIn (item->key);
TQValueList < TQString >::Iterator wlistit;
for (wlistit = wlist.begin (); wlistit != wlist.end (); ++wlistit)
{
addLocation (*wlistit, location);
}
}
#endif
}
#include "database.moc"