diff options
Diffstat (limited to 'kbabel/kbabeldict/modules/dbsearchengine/database.cpp')
-rw-r--r-- | kbabel/kbabeldict/modules/dbsearchengine/database.cpp | 1533 |
1 files changed, 1533 insertions, 0 deletions
diff --git a/kbabel/kbabeldict/modules/dbsearchengine/database.cpp b/kbabel/kbabeldict/modules/dbsearchengine/database.cpp new file mode 100644 index 00000000..003a3a95 --- /dev/null +++ b/kbabel/kbabeldict/modules/dbsearchengine/database.cpp @@ -0,0 +1,1533 @@ +/*************************************************************************** + 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 Qt library by Trolltech AS, Norway (or with modified versions * + * of Qt that use the same license as Qt), 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 * + * Qt. 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 <qfile.h> + +#include <ktempfile.h> +#include <kio/netaccess.h> + +WordItem::WordItem (char *data, QString 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 (QString 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, QString lang) +{ + const char *rd; + rd = rawData; + int len; + unsigned int secs; + // I'll change the charset handling if needed + + charset = "Utf8"; + + catalogName = QString::fromUtf8 (rd); + len = strlen (rd) + 1; + rd += len; + lastTranslator = QString::fromUtf8 (rd); + len = strlen (rd) + 1; + rd += len; + secs = *(unsigned int *) rd; + revisionDate.setTime_t (secs); + rd += 4; + lastFullPath = QString::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; + + + //QDate Time problem!!!!!!!!!!! + QDateTime 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 (QFile & input, QFile & 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 = QString::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 = QString::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 (QString directory, QString lang, + QObject * parent, const char *name): +QObject (parent, name) +{ + QString filename; + + language = lang; + iAmOk = true; + basedir = directory; + indexDb = wordDb = infoDb = db = 0; + openDataBase (); + + +} + +void +DataBaseManager::openDataBase () +{ + kdDebug () << "Opendatabase" << endl; + QString directory; + directory = basedir; + QString ll = "." + language; + if (ll == ".") + ll = ".NOLANG"; + + QString transfilename = "%1/translations%2.db"; + transfilename = transfilename.arg (directory).arg (ll); + + QString infofilename = "%1/catalogsinfo%2.db"; + infofilename = infofilename.arg (directory).arg (ll); + + QString wordsfilename = "%1/wordsindex%2.db"; + wordsfilename = wordsfilename.arg (directory).arg (ll); + + QString 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_MINOR > 0 + 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 + QFile 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 + QFile 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 + QFile 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 + QFile 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) + { + KIO::NetAccess::del (KURL::fromPathOrURL (transfilename)); + copy_hack (*transFile.file (), transfilenameFile); + transFile.unlink (); + + KIO::NetAccess::del (KURL::fromPathOrURL (infofilename)); + copy_hack (*infoFile.file (), infofilenameFile); + infoFile.unlink (); + + KIO::NetAccess::del (KURL::fromPathOrURL (wordsfilename)); + copy_hack (*wordsFile.file (), wordfilenameFile); + wordsFile.unlink (); + + KIO::NetAccess::del (KURL::fromPathOrURL (keysfilename)); + copy_hack (*keysFile.file (), keysfilenameFile); + keysFile.unlink (); + + ret = db->open (db, +#if DB_VERSION_MINOR > 0 + 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_MINOR > 0 + 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_MINOR > 0 + 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_MINOR > 0 + 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; + + QValueList < QString > wlist; + + wlist = wordsIn (item->key); + + QValueList < QString >::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 (QString 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) << QString ("...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->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 (QString directory, + QString language, int mode) +{ + QString filename; + QString 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) << QString("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_MINOR > 0 + 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_MINOR > 0 + 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_MINOR > 0 + 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_MINOR > 0 + NULL, +#endif + filename.local8Bit (), 0, DB_RECNO, DB_CREATE, mode); + if (ret != 0) + iAmOk = false; + + + + if (iAmOk) + loadInfo (); + else + kdDebug (KBABEL_SEARCH) << QString ("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) << QString("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 (QString location) +{ + int n = 0; + QValueList < 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 + 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)); + } + +} + + +QValueList < QString > DataBaseManager::wordsIn (QString string) +{ + QString + a; + QValueList < QString > 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. + QString + 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 (QString word) +{ + + QString 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 (QString word, unsigned int location) +{ + + QString 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 (abs ((int) d[loc] - (int) location) < 50 + || antibounce > 100) + step = 1; //Go linear... + else + { + step = + (abs (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 (QString /*word */ , int /*location */ ) +{ + +//#warning TODO: REMOVE LOCATION + return true; + +} + +uint32 +DataBaseManager::appendKey (QString _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) << QString("Append result %1,err = %1").arg(ret).arg(err) << endl; + + + free (data.data); + + return ret; + +} + +QString +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 QString::null; + + return QString::fromUtf8 ((char *) data.data); + +// kdDebug(0) << QString("Trad %1").arg(ret) << endl; + +} + +int +DataBaseManager::catalogRef (QString location, QString author, QString 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 (QString key, QString tran, int catalog, + bool ow) +{ + int catnum = catalog; + int count = 0; + QString msgid = key; + DataBaseItem dbit = getItem (msgid); + + if (dbit.numTra == 0) //Not found + { + dbit.numTra += 1; + + // use local variable, dbit.translations is QValueList 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) << QString ("-----------put code ") << aa << endl; + } + else + { + // key exists + + QString msgstr = tran; + bool found_catalog_info = false, foundTr = false, isThisOne = false; + + QValueList < 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) << QString ("-----------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; + + QValueList < QString > wlist; + + wlist = wordsIn (item->key); + + QValueList < QString >::Iterator wlistit; + + for (wlistit = wlist.begin (); wlistit != wlist.end (); ++wlistit) + { + addLocation (*wlistit, location); + } + + } +#endif +} + + + +#include "database.moc" |