summaryrefslogtreecommitdiffstats
path: root/lib/catalog/catalog.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/catalog/catalog.cpp')
-rw-r--r--lib/catalog/catalog.cpp462
1 files changed, 462 insertions, 0 deletions
diff --git a/lib/catalog/catalog.cpp b/lib/catalog/catalog.cpp
new file mode 100644
index 00000000..b3438f1e
--- /dev/null
+++ b/lib/catalog/catalog.cpp
@@ -0,0 +1,462 @@
+/* This file is part of KDevelop
+ Copyright (C) 2003 Roberto Raggi <[email protected]>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+#include "catalog.h"
+#include <qdir.h>
+#include <qfile.h>
+#include <qfileinfo.h>
+#include <qdatastream.h>
+
+#include <krandomsequence.h>
+#include <kdebug.h>
+
+
+#include <cstring>
+#include <cstdlib>
+#include <db.h>
+
+#include <config.h>
+
+struct _Catalog_Private
+{
+ QString dbName;
+
+ DB* dbp;
+ QMap<QCString, DB*> indexList;
+ KRandomSequence rnd;
+ bool enabled;
+
+ _Catalog_Private()
+ : dbp( 0 ), enabled( true )
+ {
+ }
+
+ bool hasIndex( const QCString& name ) const
+ {
+ return indexList.contains( name );
+ }
+
+ DB* index( const QCString& name )
+ {
+ return indexList[ name ];
+ }
+
+ bool addItem( DB* dbp, const QCString& id, const Tag& tag )
+ {
+ Q_ASSERT( dbp != 0 );
+
+ DBT key, data;
+ int ret;
+
+ std::memset( &key, 0, sizeof(key) );
+ std::memset( &data, 0, sizeof(data) );
+
+ QByteArray a1;
+ {
+ QDataStream stream( a1, IO_WriteOnly );
+ stream << id;
+ key.data = a1.data();
+ key.size = a1.size();
+ }
+
+ QByteArray a2;
+ {
+ QDataStream stream( a2, IO_WriteOnly );
+ tag.store( stream );
+ data.data = a2.data();
+ data.size = a2.size();
+ }
+
+ ret = dbp->put( dbp, 0, &key, &data, 0 );
+
+ return ret == 0;
+ }
+
+ bool addItem( DB* dbp, const QVariant& id, const QCString& v )
+ {
+ Q_ASSERT( dbp != 0 );
+
+ DBT key, data;
+ int ret;
+
+ std::memset( &key, 0, sizeof(key) );
+ std::memset( &data, 0, sizeof(data) );
+
+ QByteArray a1;
+ {
+ QDataStream stream( a1, IO_WriteOnly );
+ stream << id;
+ key.data = a1.data();
+ key.size = a1.size();
+ }
+
+ QByteArray a2;
+ {
+ QDataStream stream( a2, IO_WriteOnly );
+ stream << v;
+ data.data = a2.data();
+ data.size = a2.size();
+ }
+
+ ret = dbp->put( dbp, 0, &key, &data, 0 );
+
+ return ret == 0;
+ }
+
+};
+
+
+/*!
+ \fn Catalog::Catalog
+ */
+ Catalog::Catalog()
+ : d( new _Catalog_Private() )
+{
+}
+
+/*!
+ \fn Catalog::~Catalog
+ */
+ Catalog::~Catalog()
+{
+ close();
+ delete( d );
+ d = 0;
+}
+
+/*!
+ \fn Catalog::indexList() const
+ */
+ QValueList<QCString> Catalog::indexList() const
+{
+ QValueList<QCString> l;
+ QMap<QCString, DB*>::Iterator it = d->indexList.begin();
+ while( it != d->indexList.end() ){
+ l << it.key();
+ ++it;
+ }
+
+ return l;
+}
+
+bool Catalog::enabled() const
+{
+ return d->enabled;
+}
+
+void Catalog::setEnabled( bool isEnabled )
+{
+ d->enabled = isEnabled;
+}
+
+/*!
+ \fn Catalog::addIndex( const QString& name )
+ @todo document these functions
+ */
+ void Catalog::addIndex( const QCString& name )
+{
+ Q_ASSERT( d->dbp != 0 );
+
+ QMap<QCString, DB*>::Iterator it = d->indexList.find( name );
+ if( it == d->indexList.end() ){
+ DB* dbp = 0;
+
+ int ret;
+
+ if ((ret = db_create(&dbp, 0, 0)) != 0) {
+ kdDebug() << "db_create: " << db_strerror(ret) << endl;
+ return /*false*/;
+ }
+
+ if ((ret = dbp->set_flags(dbp, DB_DUP | DB_DUPSORT)) != 0) {
+ dbp->err(dbp, ret, "set_flags: DB_DUP | DB_DUPSORT");
+ dbp->close( dbp, 0 );
+ return;
+ }
+
+ QFileInfo fileInfo( d->dbName );
+ QString indexName = fileInfo.dirPath(true) + "/" + fileInfo.baseName(true) + "." + QString(name) + ".idx";
+
+ if( (ret = dbp->set_cachesize( dbp, 0, 2 * 1024 * 1024, 0 )) != 0 ){
+ kdDebug() << "set_cachesize: " << db_strerror(ret) << endl;
+ }
+
+ if ((ret = dbp->open(
+ dbp, NULL, QFile::encodeName( indexName ).data(), 0, DB_BTREE, DB_CREATE, 0664)) != 0) {
+ kdDebug() << "db_open: " << db_strerror(ret) << endl;
+ dbp->close( dbp, 0 );
+ return;
+ }
+
+ d->indexList[ name ] = dbp;
+ }
+}
+
+/*!
+ \fn Catalog::close()
+ */
+
+ void Catalog::close()
+{
+ d->dbName = QString::null;
+
+ QMap<QCString, DB*>::Iterator it = d->indexList.begin();
+ while( it != d->indexList.end() ){
+ if( it.data() ){
+ it.data()->close( it.data(), 0 );
+ }
+ ++it;
+ }
+ d->indexList.clear();
+
+ if( d->dbp != 0 ){
+ d->dbp->close( d->dbp, 0 );
+ d->dbp = 0;
+ }
+}
+
+/*!
+ \fn Catalog::open( const QString& dbName )
+ */
+
+ void Catalog::open( const QString& dbName )
+{
+ Q_ASSERT( d->dbp == 0 );
+
+ d->dbName = dbName;
+
+ int ret;
+
+ if ((ret = db_create(&d->dbp, 0, 0)) != 0) {
+ kdDebug() << "db_create: " << db_strerror(ret) << endl;
+ return /*false*/;
+ }
+
+ if ((ret = d->dbp->set_flags(d->dbp, DB_RECNUM)) != 0) {
+ d->dbp->err(d->dbp, ret, "set_flags: DB_RECNUM");
+ close();
+ return;
+ }
+
+ if( (ret = d->dbp->set_cachesize( d->dbp, 0, 2 * 1024 * 1024, 0 )) != 0 ){
+ kdDebug() << "set_cachesize: " << db_strerror(ret) << endl;
+ }
+
+ if ((ret = d->dbp->open(
+ d->dbp, NULL, d->dbName.local8Bit(), 0, DB_BTREE, DB_CREATE, 0664)) != 0) {
+ kdDebug() << "db_open: " << db_strerror(ret) << endl;
+ close();
+ return;
+ }
+}
+
+/*!
+ \fn Catalog::dbName() const
+ */
+
+ QString Catalog::dbName() const
+{
+ return d->dbName;
+}
+
+/*!
+ \fn Catalog::isValid() const
+ */
+
+ bool Catalog::isValid() const
+{
+ return d->dbp != 0;
+}
+
+/*!
+ \fn Catalog::addItem( Tag& tag )
+ */
+
+ void Catalog::addItem( Tag& tag )
+{
+ if( tag.name().isEmpty() )
+ return;
+
+ QCString id = generateId();
+
+ tag.setId( id );
+ if( d->addItem(d->dbp, id, tag) ){
+ QMap<QCString, DB*>::Iterator it = d->indexList.begin();
+ while( it != d->indexList.end() ){
+ if( tag.hasAttribute(it.key()) )
+ d->addItem( it.data(), tag.attribute(it.key()), id );
+ ++it;
+ }
+ }
+}
+
+/*!
+ \fn Catalog::getItemById( const QString& id )
+ */
+
+ Tag Catalog::getItemById( const QCString& id )
+{
+ Q_ASSERT( d->dbp != 0 );
+
+ DBT key, data;
+ std::memset( &key, 0, sizeof(key) );
+ std::memset( &data, 0, sizeof(data) );
+
+ QByteArray a1;
+ {
+ QDataStream stream( a1, IO_WriteOnly );
+ stream << id;
+ key.data = a1.data();
+ key.size = a1.size();
+ }
+
+ int ret = d->dbp->get( d->dbp, 0, &key, &data, 0 );
+ Q_ASSERT( ret == 0 );
+
+ Tag tag;
+
+ if( ret == 0 ){
+ QByteArray a;
+ a.setRawData( (const char*) data.data, data.size );
+ QDataStream stream( a, IO_ReadOnly );
+ tag.load( stream );
+ a.resetRawData( (const char*) data.data, data.size );
+ }
+
+ return tag;
+}
+
+/*!
+ \fn Catalog::sync()
+*/
+
+ void Catalog::sync()
+{
+ Q_ASSERT( d->dbp != 0 );
+ d->dbp->sync( d->dbp, 0 );
+
+ QMap<QCString, DB*>::Iterator it = d->indexList.begin();
+ while( it != d->indexList.end() ){
+ it.data()->sync( it.data(), 0 );
+ ++it;
+ }
+}
+
+/*!
+ \fn Catalog::query( const QValueList<QueryArgument>& args )
+*/
+
+ QValueList<Tag> Catalog::query( const QValueList<QueryArgument>& args )
+{
+ QValueList<Tag> tags;
+
+ DBT key, data;
+
+ DBC** cursors = new DBC* [ args.size() + 1 ];
+
+ QValueList< QPair<QCString,QVariant> >::ConstIterator it = args.begin();
+ int current = 0;
+ while( it != args.end() ){
+ QCString indexName = (*it).first;
+ QVariant value = (*it).second;
+
+ if( d->hasIndex(indexName) ) {
+ DB* dbp = d->index( indexName );
+ Q_ASSERT( dbp != 0 );
+
+ std::memset( &key, 0, sizeof(key) );
+ std::memset( &data, 0, sizeof(data) );
+
+ QByteArray a1;
+ {
+ QDataStream stream( a1, IO_WriteOnly );
+ stream << value;
+ key.data = a1.data();
+ key.size = a1.size();
+ }
+
+ DBC* cursor = 0;
+ int rtn = dbp->cursor( dbp, 0, &cursor, 0 );
+
+ if ( rtn == 0 ) {
+
+ rtn = cursor->c_get( cursor, &key, &data, DB_SET );
+
+ if ( rtn == 0 ) {
+ cursors[ current++ ] = cursor;
+ }
+ else if ( rtn != DB_NOTFOUND) {
+ kdDebug() << "fetching cursor failed: " << db_strerror(rtn) << endl;
+ cursor->c_close(cursor);
+ }
+ }
+ else {
+ kdDebug() << "creating cursor failed: " << db_strerror(rtn) << endl;
+ }
+ }
+ ++it;
+ }
+
+ cursors[ current ] = 0;
+
+ if( current == args.size() ) {
+
+ DBC* join_curs = 0;
+ int rtn = d->dbp->join( d->dbp, cursors, &join_curs, 0 );
+
+ if ( rtn == 0 ) {
+
+ std::memset( &key, 0, sizeof(key) );
+ std::memset( &data, 0, sizeof(data) );
+
+ while( join_curs->c_get(join_curs, &key, &data, 0) == 0 ) {
+
+ QByteArray a2;
+ a2.setRawData( (const char*) data.data, data.size );
+ QDataStream s( a2, IO_ReadOnly );
+ Tag tag;
+ tag.load( s );
+ a2.resetRawData( (const char*) data.data, data.size );
+ tags << tag;
+ }
+
+ join_curs->c_close( join_curs );
+ }
+ else {
+ kdDebug() << "joining results failed: " << db_strerror(rtn) << endl;
+ }
+ }
+
+ DBC** c = cursors;
+ while( *c != 0 ){
+ (*c)->c_close( *c );
+ ++c;
+ }
+ delete[] cursors;
+
+ return tags;
+}
+
+ QCString Catalog::generateId()
+{
+ static int n = 1;
+ QCString asStr;
+ asStr.sprintf( "%05d", n++ );
+ return asStr;
+}
+