From b9aad1f15dc600e4dbe4c62d3fcced6363188ba3 Mon Sep 17 00:00:00 2001 From: zautrix Date: Sat, 26 Jun 2004 19:01:18 +0000 Subject: Initial revision --- (limited to 'microkde/kdecore') diff --git a/microkde/kdecore/kcatalogue.cpp b/microkde/kdecore/kcatalogue.cpp new file mode 100644 index 0000000..97ac326 --- a/dev/null +++ b/microkde/kdecore/kcatalogue.cpp @@ -0,0 +1,131 @@ +/* This file is part of the KDE libraries + Copyright (c) 2001 Hans Petter Bieker + + 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. +*/ + +//US #include + +#include + +#include + +#include "kcatalogue.h" + +char *k_nl_find_msg(struct kde_loaded_l10nfile *domain_file, + const char *msgid); +void k_nl_unload_domain (struct loaded_domain *domain); + +#ifndef KDE_USE_FINAL // with --enable-final, we're getting this from libintl.cpp +struct kde_loaded_l10nfile +{ + const char *filename; + int decided; + + const void *data; + + kde_loaded_l10nfile() : filename(0), decided(0), data(0) {} +}; +#endif + +class KCataloguePrivate +{ +public: + QString name; + + kde_loaded_l10nfile domain; +}; + +KCatalogue::KCatalogue(const QString & name) + : d( new KCataloguePrivate ) +{ + d->name = name; +} + +KCatalogue::KCatalogue(const KCatalogue & rhs) + : d( new KCataloguePrivate ) +{ + *this = rhs; +} + +KCatalogue & KCatalogue::operator=(const KCatalogue & rhs) +{ + d->name = rhs.d->name; + setFileName( rhs.fileName() ); + + return *this; +} + +KCatalogue::~KCatalogue() +{ + doUnload(); + + delete d; +} + +QString KCatalogue::name() const +{ + return d->name; +} + +void KCatalogue::setFileName( const QString & fileName ) +{ + // nothing to do if the file name is already the same + if ( this->fileName() == fileName ) return; + + doUnload(); + + QCString newFileName = QFile::encodeName( fileName ); + + if ( !fileName.isEmpty() ) + { + // set file name + char *filename = new char[ newFileName.length() + 1 ]; + ::qstrcpy( filename, newFileName ); + d->domain.filename = filename; + } +} + +QString KCatalogue::fileName() const +{ + return QFile::decodeName( d->domain.filename ); +} + +const char * KCatalogue::translate(const char * msgid) const +{ + qDebug("KCatalogue::translate has to be fixed %s",msgid ); +//US return ::k_nl_find_msg( &d->domain, msgid ); + return msgid; + +} + +void KCatalogue::doUnload() +{ + // use gettext's unloader + if ( d->domain.data ) + { +//US ::k_nl_unload_domain( (struct loaded_domain *)d->domain.data ); + qDebug("KCatalogue::doUnload has to be fixed" ); + + } + d->domain.data = 0; + + // free name + delete [] const_cast(d->domain.filename); + d->domain.filename = 0; + + d->domain.decided = 0; +} diff --git a/microkde/kdecore/kcatalogue.h b/microkde/kdecore/kcatalogue.h new file mode 100644 index 0000000..e229cc8 --- a/dev/null +++ b/microkde/kdecore/kcatalogue.h @@ -0,0 +1,104 @@ +/* This file is part of the KDE libraries + Copyright (c) 2001 Hans Petter Bieker + + 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. +*/ + +#ifndef KCATALOGUE_H +#define KCATALOGUE_H + +#include + +struct kde_loaded_l10nfile; + +class KCataloguePrivate; + +/** + * This class abstracts a gettext message catalogue. It will take care of + * opening the file and reading the catalogue. + * + * @see KLocale + */ +//REVISED: hausmann +class KCatalogue +{ +public: + /** + * Constructor. + * + * @param name The name of the catalogue + */ + explicit KCatalogue(const QString & name = QString::null); + + /** + * Copy constructor. + */ + KCatalogue(const KCatalogue & rhs); + + /** + * Assignment operator. + */ + KCatalogue & operator = ( const KCatalogue & rhs); + + /** + * Destructor. + */ + virtual ~KCatalogue(); + + /** + * Returns the name of the catalogue. + * + * @return The name of the catalogue + */ + QString name() const; + + /** + * Changes the current file name. + * + * @param fileName The new file name + */ + + void setFileName( const QString & fileName ); + + /** + * Retrieves a translation of the specified message id. + * + * Do not pass 0 or "" strings as message ids. + * + * @param msgid The message id + * + * @return The translated message, in utf8 encoding, or 0 if not found + */ + const char * translate( const char * msgid ) const; + +private: + /** + * @internal Retrieves the current file name. + * + * @return The current file name, if any. + */ + QString fileName() const; + + /** + * @internal Unloads the current file. + */ + void doUnload(); + +private: + KCataloguePrivate * d; +}; + +#endif diff --git a/microkde/kdecore/kconfigbase.h b/microkde/kdecore/kconfigbase.h new file mode 100644 index 0000000..7e56d11 --- a/dev/null +++ b/microkde/kdecore/kconfigbase.h @@ -0,0 +1,102 @@ +/* + This file is part of the KDE libraries + Copyright (c) 1999 Preston Brown + Copyright (c) 1997 Matthias Kalle Dalheimer + Copyright (c) 2001 Waldo Bastian + + 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. +*/ + +// $Id$ + +#ifndef _KCONFIGBASE_H +#define _KCONFIGBASE_H + +#include "kconfig.h" + +/** + * Helper class to facilitate working with @ref KConfig / @ref KSimpleConfig + * groups. + * + * Careful programmers always set the group of a + * @ref KConfig @ref KSimpleConfig object to the group they want to read from + * and set it back to the old one of afterwards. This is usually + * written as: + *
+  *
+  * QString oldgroup config->group();
+  * config->setGroup( "TheGroupThatIWant" );
+  * ...
+  * config->writeEntry( "Blah", "Blubb" );
+  *
+  * config->setGroup( oldgroup );
+  * 
+ * + * In order to facilitate this task, you can use + * KConfigGroupSaver. Simply construct such an object ON THE STACK + * when you want to switch to a new group. Then, when the object goes + * out of scope, the group will automatically be restored. If you + * want to use several different groups within a function or method, + * you can still use KConfigGroupSaver: Simply enclose all work with + * one group (including the creation of the KConfigGroupSaver object) + * in one block. + * + * @author Matthias Kalle Dalheimer + * @version $Id$ + * @see KConfigBase, KConfig, KSimpleConfig + * @short Helper class for easier use of KConfig/KSimpleConfig groups + */ +//US I converted the class in a way that it can be used with KConfig objects of microkde + +class KConfigGroupSaver +{ +public: + /** + * Constructor. You pass a pointer to the KConfigBase-derived + * object you want to work with and a string indicating the _new_ + * group. + * + * @param config The KConfigBase-derived object this + * KConfigGroupSaver works on. + * @param group The new group that the config object should switch to. + */ + KConfigGroupSaver( KConfig* config, QString group ) + /* KDE 4 : make the second parameter const QString & */ + : _config(config), _oldgroup(config->group()) + { _config->setGroup( group ); } + + KConfigGroupSaver( KConfig* config, const char *group ) + : _config(config), _oldgroup(config->group()) + { _config->setGroup( group ); } + + KConfigGroupSaver( KConfig* config, const QCString &group ) + : _config(config), _oldgroup(config->group()) + { _config->setGroup( group ); } + + ~KConfigGroupSaver() { _config->setGroup( _oldgroup ); } + + KConfig* config() { return _config; }; + +private: + KConfig* _config; + QString _oldgroup; + + KConfigGroupSaver(const KConfigGroupSaver&); + KConfigGroupSaver& operator=(const KConfigGroupSaver&); + +}; + +#endif diff --git a/microkde/kdecore/klibloader.cpp b/microkde/kdecore/klibloader.cpp new file mode 100644 index 0000000..1410308 --- a/dev/null +++ b/microkde/kdecore/klibloader.cpp @@ -0,0 +1,626 @@ +/* This file is part of the KDE libraries + Copyright (C) 1999 Torben Weis + Copyright (C) 2000 Michael Matz + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + 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. +*/ +//US #include +#include +#include +#include +#include +#include +#include + +#include "kapplication.h" +#include "klibloader.h" +#include "kstandarddirs.h" +#include "kdebug.h" +#include "klocale.h" + +//US #include "ltdl.h" + +//US do everything through qlibrary +#ifndef DESKTOP_VERSION +#include +#include +#endif + +/*US +#ifdef Q_WS_X11 +#include +#include +#endif +*/ +template class QAsciiDict; + +#include //getenv + +/*US +#if HAVE_DLFCN_H +# include +#endif + +#ifdef RTLD_GLOBAL +# define LT_GLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_GLOBAL DL_GLOBAL +# endif +#endif +#ifndef LT_GLOBAL +# define LT_GLOBAL 0 +#endif +*/ + +/*US +extern "C" { +extern int lt_dlopen_flag; +} +*/ + +KLibFactory::KLibFactory( QObject* parent, const char* name ) + : QObject( parent, name ) +{ +} + +KLibFactory::~KLibFactory() +{ +// kdDebug(150) << "Deleting KLibFactory " << this << endl; +} + +QObject* KLibFactory::create( QObject* parent, const char* name, const char* classname, const QStringList &args ) +{ + QObject* obj = createObject( parent, name, classname, args ); + if ( obj ) + emit objectCreated( obj ); + return obj; +} + + +QObject* KLibFactory::createObject( QObject*, const char*, const char*, const QStringList &) +{ + return 0; +} + + +// ----------------------------------------------- + +//US KLibrary::KLibrary( const QString& libname, const QString& filename, void * handle ) +KLibrary::KLibrary( const QString& libname, const QString& filename, QLibrary* handle ) +{ + /* Make sure, we have a KLibLoader */ + (void) KLibLoader::self(); + m_libname = libname; + m_filename = filename; + m_handle = handle; + m_factory = 0; + m_timer = 0; +} + +KLibrary::~KLibrary() +{ +// kdDebug(150) << "Deleting KLibrary " << this << " " << m_libname << endl; + if ( m_timer && m_timer->isActive() ) + m_timer->stop(); + + // If any object is remaining, delete + if ( m_objs.count() > 0 ) + { + QPtrListIterator it( m_objs ); + for ( ; it.current() ; ++it ) + { + kdDebug(150) << "Factory still has object " << it.current() << " " << it.current()->name () << " Library = " << m_libname << endl; + disconnect( it.current(), SIGNAL( destroyed() ), + this, SLOT( slotObjectDestroyed() ) ); + } + m_objs.setAutoDelete(true); + m_objs.clear(); + } + + if ( m_factory ) { +// kdDebug(150) << " ... deleting the factory " << m_factory << endl; + delete m_factory; + } +} + +QString KLibrary::name() const +{ + return m_libname; +} + +QString KLibrary::fileName() const +{ + return m_filename; +} + +KLibFactory* KLibrary::factory() +{ + if ( m_factory ) + return m_factory; + + QCString symname; + symname.sprintf("init_%s", name().latin1() ); + + void* sym = symbol( symname ); + if ( !sym ) + { + kdWarning(150) << "KLibrary: The library " << name() << " does not offer an init_" << name() << " function" << endl; + return 0; + } + + typedef KLibFactory* (*t_func)(); + t_func func = (t_func)sym; + m_factory = func(); + + if( !m_factory ) + { + kdWarning(150) << "KLibrary: The library " << name() << " does not offer a KDE compatible factory" << endl; + return 0; + } + + connect( m_factory, SIGNAL( objectCreated( QObject * ) ), + this, SLOT( slotObjectCreated( QObject * ) ) ); + + return m_factory; +} + +void* KLibrary::symbol( const char* symname ) const +{ +//US void* sym = lt_dlsym( (lt_dlhandle) m_handle, symname ); + void* sym = m_handle->resolve( symname ); + if ( !sym ) + { +//US kdWarning(150) << "KLibrary: " << lt_dlerror() << endl; + kdWarning(150) << "KLibrary: " << m_libname << ", symbol:" << symname << " not found " << endl; + return 0; + } + + return sym; +} + +bool KLibrary::hasSymbol( const char* symname ) const +{ +//US void* sym = lt_dlsym( (lt_dlhandle) m_handle, symname ); + void* sym = m_handle->resolve( symname ); + return (sym != 0L ); +} + +void KLibrary::unload() const +{ + if (KLibLoader::s_self) + KLibLoader::s_self->unloadLibrary(QFile::encodeName(name())); +} + +void KLibrary::slotObjectCreated( QObject *obj ) +{ + if ( !obj ) + return; + + if ( m_timer && m_timer->isActive() ) + m_timer->stop(); + + if ( m_objs.containsRef( obj ) ) + return; // we know this object already + + connect( obj, SIGNAL( destroyed() ), + this, SLOT( slotObjectDestroyed() ) ); + + m_objs.append( obj ); +} + +void KLibrary::slotObjectDestroyed() +{ + m_objs.removeRef( sender() ); + + if ( m_objs.count() == 0 ) + { +// kdDebug(150) << "KLibrary: shutdown timer for " << name() << " started!" +// << endl; + + if ( !m_timer ) + { + m_timer = new QTimer( this, "klibrary_shutdown_timer" ); + connect( m_timer, SIGNAL( timeout() ), + this, SLOT( slotTimeout() ) ); + } + + // as long as it's not stable make the timeout short, for debugging + // pleasure (matz) + //m_timer->start( 1000*60, true ); + m_timer->start( 1000*10, true ); + } +} + +void KLibrary::slotTimeout() +{ + if ( m_objs.count() != 0 ) + return; + + /* Don't go through KLibLoader::unloadLibrary(), because that uses the + ref counter, but this timeout means to unconditionally close this library + The destroyed() signal will take care to remove us from all lists. + */ + delete this; +} + +// ------------------------------------------------- + +/* This helper class is needed, because KLibraries can go away without + being unloaded. So we need some info about KLibraries even after its + death. */ +class KLibWrapPrivate +{ +public: +//US KLibWrapPrivate(KLibrary *l, lt_dlhandle h); + KLibWrapPrivate(KLibrary *l, QLibrary* h); + + KLibrary *lib; + enum {UNKNOWN, UNLOAD, DONT_UNLOAD} unload_mode; + int ref_count; +//US lt_dlhandle handle; + QLibrary *handle; + QString name; + QString filename; +}; + +//US KLibWrapPrivate::KLibWrapPrivate(KLibrary *l, lt_dlhandle h) +KLibWrapPrivate::KLibWrapPrivate(KLibrary *l, QLibrary* h) + : lib(l), ref_count(1), handle(h), name(l->name()), filename(l->fileName()) +{ + unload_mode = UNKNOWN; +/*US + if (lt_dlsym(handle, "__kde_do_not_unload") != 0) { +// kdDebug(150) << "Will not unload " << name << endl; + unload_mode = DONT_UNLOAD; + } else if (lt_dlsym(handle, "__kde_do_unload") != 0) { + unload_mode = UNLOAD; + } +*/ +//US use instead: + if (h->resolve("__kde_do_not_unload") != 0) { +// kdDebug(150) << "Will not unload " << name << endl; + unload_mode = DONT_UNLOAD; + } else if (h->resolve("__kde_do_unload") != 0) { + unload_mode = UNLOAD; + } +} + +class KLibLoaderPrivate +{ +public: + QPtrList loaded_stack; + QPtrList pending_close; + enum {UNKNOWN, UNLOAD, DONT_UNLOAD} unload_mode; + + QString errorMessage; +}; + +KLibLoader* KLibLoader::s_self = 0; + +KLibLoader* KLibLoader::self() +{ + if ( !s_self ) + s_self = new KLibLoader; + return s_self; +} + +void KLibLoader::cleanUp() +{ + if ( !s_self ) + return; + + delete s_self; + s_self = 0; +} + +KLibLoader::KLibLoader( QObject* parent, const char* name ) + : QObject( parent, name ) +{ + s_self = this; + d = new KLibLoaderPrivate; +//US lt_dlinit(); + d->unload_mode = KLibLoaderPrivate::UNKNOWN; + if (getenv("KDE_NOUNLOAD") != 0) + d->unload_mode = KLibLoaderPrivate::DONT_UNLOAD; + else if (getenv("KDE_DOUNLOAD") != 0) + d->unload_mode = KLibLoaderPrivate::UNLOAD; + d->loaded_stack.setAutoDelete( true ); +} + +KLibLoader::~KLibLoader() +{ +// kdDebug(150) << "Deleting KLibLoader " << this << " " << name() << endl; + + QAsciiDictIterator it( m_libs ); + for (; it.current(); ++it ) + { + kdDebug(150) << "The KLibLoader contains the library " << it.current()->name + << " (" << it.current()->lib << ")" << endl; + d->pending_close.append(it.current()); + } + + close_pending(0); + + delete d; +} + +//static +QString KLibLoader::findLibrary( const char * name/*US , const KInstance * instance*/ ) +{ + QCString libname( name ); + + // only append ".la" if there is no extension + // this allows to load non-libtool libraries as well + // (mhk, 20000228) + int pos = libname.findRev('/'); + if (pos < 0) + pos = 0; + if (libname.find('.', pos) < 0) + libname += ".la"; + + // only look up the file if it is not an absolute filename + // (mhk, 20000228) + QString libfile; + if (libname[0] == '/') + libfile = libname; + else + { +//US libfile = instance->dirs()->findResource( "module", libname ); + libfile = KGlobal::dirs()->findResource( "module", libname ); + if ( libfile.isEmpty() ) + { +//US libfile = instance->dirs()->findResource( "lib", libname ); + libfile = KGlobal::dirs()->findResource( "lib", libname ); +#ifndef NDEBUG + if ( !libfile.isEmpty() && libname.left(3) == "lib" ) // don't warn for kdeinit modules + kdDebug(150) << "library " << libname << " not found under 'module' but under 'lib'" << endl; +#endif + } + if ( libfile.isEmpty() ) + { +#ifndef NDEBUG + kdDebug(150) << "library=" << libname << ": No file names " << libname.data() << " found in paths." << endl; +#endif + self()->d->errorMessage = i18n("Library files for \"%1\" not found in paths").arg(libname); + } + else + self()->d->errorMessage = QString::null; + } + return libfile; +} + + +KLibrary* KLibLoader::globalLibrary( const char *name ) +{ +KLibrary *tmp; +/*US +int olt_dlopen_flag = lt_dlopen_flag; + + lt_dlopen_flag |= LT_GLOBAL; + kdDebug(150) << "Loading the next library global with flag " + << lt_dlopen_flag + << "." << endl; +*/ + tmp = library(name); +/*US + lt_dlopen_flag = olt_dlopen_flag; +*/ +return tmp; +} + + +KLibrary* KLibLoader::library( const char *name ) +{ + if (!name) + return 0; + + KLibWrapPrivate* wrap = m_libs[name]; + if (wrap) { + /* Nothing to do to load the library. */ + wrap->ref_count++; + return wrap->lib; + } + + /* Test if this library was loaded at some time, but got + unloaded meanwhile, whithout being dlclose()'ed. */ + QPtrListIterator it(d->loaded_stack); + for (; it.current(); ++it) { + if (it.current()->name == name) + wrap = it.current(); + } + + if (wrap) { + d->pending_close.removeRef(wrap); + if (!wrap->lib) { + /* This lib only was in loaded_stack, but not in m_libs. */ + wrap->lib = new KLibrary( name, wrap->filename, wrap->handle ); + } + wrap->ref_count++; + } else { + QString libfile = findLibrary( name ); + if ( libfile.isEmpty() ) + return 0; + + const QString & qpeDir = QPEApplication::qpeDir(); + libfile = qpeDir + libfile; +//US QLibrary *lib = new QLibrary( qpeDir + "/plugins/korganizer/libopiekabc.so", QLibrary::Immediately ); + QLibrary *qlib = new QLibrary( libfile.latin1(), QLibrary::Immediately ); + +//US lt_dlhandle handle = lt_dlopen( libfile.latin1() ); +//US if ( !handle ) + if ( !qlib ) + { +//US const char* errmsg = lt_dlerror(); + char* errmsg; + sprintf(errmsg, "KLibLoader::library could not load library: %s", libfile.latin1()); + qDebug(errmsg); + + if(errmsg) + d->errorMessage = QString::fromLatin1(errmsg); + else + d->errorMessage = QString::null; + kdWarning(150) << "library=" << name << ": file=" << libfile << ": " << d->errorMessage << endl; + return 0; + } + else + d->errorMessage = QString::null; + + KLibrary *lib = new KLibrary( name, libfile, qlib ); + wrap = new KLibWrapPrivate(lib, qlib); + d->loaded_stack.prepend(wrap); + } + m_libs.insert( name, wrap ); + + connect( wrap->lib, SIGNAL( destroyed() ), + this, SLOT( slotLibraryDestroyed() ) ); + + return wrap->lib; +} + +QString KLibLoader::lastErrorMessage() const +{ + return d->errorMessage; +} + +void KLibLoader::unloadLibrary( const char *libname ) +{ + KLibWrapPrivate *wrap = m_libs[ libname ]; + if (!wrap) + return; + if (--wrap->ref_count) + return; + +// kdDebug(150) << "closing library " << libname << endl; + + m_libs.remove( libname ); + + disconnect( wrap->lib, SIGNAL( destroyed() ), + this, SLOT( slotLibraryDestroyed() ) ); + close_pending( wrap ); +} + +KLibFactory* KLibLoader::factory( const char* name ) +{ + KLibrary* lib = library( name ); + if ( !lib ) + return 0; + + return lib->factory(); +} + +void KLibLoader::slotLibraryDestroyed() +{ + const KLibrary *lib = static_cast( sender() ); + + QAsciiDictIterator it( m_libs ); + for (; it.current(); ++it ) + if ( it.current()->lib == lib ) + { + KLibWrapPrivate *wrap = it.current(); + wrap->lib = 0; /* the KLibrary object is already away */ + m_libs.remove( it.currentKey() ); + close_pending( wrap ); + return; + } +} + +void KLibLoader::close_pending(KLibWrapPrivate *wrap) +{ + if (wrap && !d->pending_close.containsRef( wrap )) + d->pending_close.append( wrap ); + + /* First delete all KLibrary objects in pending_close, but _don't_ unload + the DSO behind it. */ + QPtrListIterator it(d->pending_close); + for (; it.current(); ++it) { + wrap = it.current(); + if (wrap->lib) { + disconnect( wrap->lib, SIGNAL( destroyed() ), + this, SLOT( slotLibraryDestroyed() ) ); + delete wrap->lib; + wrap->lib = 0; + } + } + + if (d->unload_mode == KLibLoaderPrivate::DONT_UNLOAD) return; + + bool deleted_one = false; + while ((wrap = d->loaded_stack.first())) { + /* Let's first see, if we want to try to unload this lib. + If the env. var KDE_DOUNLOAD is set, we try to unload every lib. + If not, we look at the lib itself, and unload it only, if it exports + the symbol __kde_do_unload. */ + if (d->unload_mode != KLibLoaderPrivate::UNLOAD + && wrap->unload_mode != KLibWrapPrivate::UNLOAD) + break; + + /* Now ensure, that the libs are only unloaded in the reverse direction + they were loaded. */ + if (!d->pending_close.containsRef( wrap )) { + if (!deleted_one) + /* Only diagnose, if we really haven't deleted anything. */ +// kdDebug(150) << "try to dlclose " << wrap->name << ": not yet" << endl; + break; + } + +// kdDebug(150) << "try to dlclose " << wrap->name << ": yes, done." << endl; + +#ifndef Q_WS_QWS + if ( !deleted_one ) { + /* Only do the hack once in this loop. + WABA: *HACK* + We need to make sure to clear the clipboard before unloading a DSO + because the DSO could have defined an object derived from QMimeSource + and placed that on the clipboard. */ + /*kapp->clipboard()->clear();*/ + + /* Well.. let's do something more subtle... convert the clipboard context + to text. That should be safe as it only uses objects defined by Qt. */ + + QWidgetList *widgetlist = QApplication::topLevelWidgets(); + QWidget *co = widgetlist->first(); + while (co) { + if (qstrcmp(co->name(), "internal clipboard owner") == 0) { + if (XGetSelectionOwner(co->x11Display(), XA_PRIMARY) == co->winId()) + kapp->clipboard()->setText(kapp->clipboard()->text()); + + break; + } + co = widgetlist->next(); + } + delete widgetlist; + } +#else + // FIXME(E): Implement in Qt Embedded +#endif + + deleted_one = true; +//US lt_dlclose(wrap->handle); + wrap->handle->unload(); + + d->pending_close.removeRef(wrap); + /* loaded_stack is AutoDelete, so wrap is freed */ + d->loaded_stack.remove(); + } +} + +void KLibLoader::virtual_hook( int, void* ) +{ /*BASE::virtual_hook( id, data );*/ } + +void KLibFactory::virtual_hook( int, void* ) +{ /*BASE::virtual_hook( id, data );*/ } + +//US #include "klibloader.moc" diff --git a/microkde/kdecore/klibloader.h b/microkde/kdecore/klibloader.h new file mode 100644 index 0000000..ed57109 --- a/dev/null +++ b/microkde/kdecore/klibloader.h @@ -0,0 +1,405 @@ +/* This file is part of the KDE libraries + Copyright (C) 1999 Torben Weis + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + 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. +*/ +#ifndef KLIBLOADER_H +#define KLIBLOADER_H + +#include +#include +#include +#include +#include +#include + +#include // For backwards compatibility + +class KInstance; +class QTimer; +class KLibrary; +class KLibFactory; +class KLibFactoryPrivate; +class KLibLoaderPrivate; +class KLibraryPrivate; + +class QLibrary; + +#define K_EXPORT_COMPONENT_FACTORY( libname, factory ) \ + extern "C" { void *init_##libname() { return new factory; } } + +/** + * @short Represents a dynamically loaded library. + * + * KLibrary allows you to look up symbols of the shared library. + * Use @ref KLibLoader to create a new instance of KLibrary. + * + * @see KLibLoader + * @author Torben Weis + */ +class KLibrary : public QObject +{ + friend class KLibLoader; + friend class QAsciiDict; + + Q_OBJECT +public: + /** + * @internal + * Don't create KLibrary objects on your own. Instead use @ref KLibLoader. + */ +//US KLibrary( const QString& libname, const QString& filename, void * handle ); + KLibrary( const QString& libname, const QString& filename, QLibrary* handle ); + + /** + * Returns the name of the library. + * @return The name of the library like "libkspread". + */ + QString name() const; + + /** + * Returns the file name of the library. + * @return The filename of the library, for example "/opt/kde2&/lib/libkspread.la" + */ + QString fileName() const; + + /** + * Returns the factory of the library. + * @return The factory of the library if there is any, otherwise 0 + */ + KLibFactory* factory(); + + /** + * Looks up a symbol from the library. This is a very low level + * function that you usually don't want to use. Usually you should + * check using @ref hasSymbol() whether the symbol actually exists, + * otherwise a warning will be printed. + * @param name the name of the symbol to look up + * @return the address of the symbol, or 0 if it does not exist + * @see #hasSymbol + */ + void* symbol( const char* name ) const; + + /** + * Looks up a symbol from the library. This is a very low level + * function that you usually don't want to use. + * Unlike @ref symbol(), this method doesn't warn if the symbol doesn't exist, + * so if the symbol might or might not exist, better use hasSymbol() before symbol(). + * @param name the name of the symbol to check + * @return true if the symbol exists + * @since 3.1 + */ + bool hasSymbol( const char* name ) const; + + /** + * Unloads the library. + * This typically results in the deletion of this object. You should + * not reference its pointer after calling this function. + */ + void unload() const; + +private slots: + void slotObjectCreated( QObject *obj ); + void slotObjectDestroyed(); + void slotTimeout(); + +private: + /** + * @internal + * Don't destruct KLibrary objects yourself. Instead use @ref unload() instead. + */ + ~KLibrary(); + + QString m_libname; + QString m_filename; + KLibFactory* m_factory; +//US void * m_handle; + QLibrary* m_handle; + QPtrList m_objs; + QTimer *m_timer; + KLibraryPrivate *d; +}; + +class KLibWrapPrivate; + +/** + * The KLibLoader allows you to load libraries dynamically at runtime. + * Dependent libraries are loaded automatically. + * + * KLibLoader follows the singleton pattern. You can not create multiple + * instances. Use @ref self() to get a pointer to the loader. + * + * @see KLibrary + * @author Torben Weis + */ +class KLibLoader : public QObject +{ + friend class KLibrary; + + Q_OBJECT +public: + /** + * You should NEVER destruct an instance of KLibLoader + * until you know what you are doing. This will release + * the loaded libraries. + */ + ~KLibLoader(); + + /** + * Loads and initializes a library. Loading a library multiple times is + * handled gracefully. + * + * This is a convenience function that returns the factory immediately + * @param libname This is the library name without extension. Usually that is something like + * "libkspread". The function will then search for a file named + * "libkspread.la" in the KDE library paths. + * The *.la files are created by libtool and contain + * important information especially about the libraries dependencies + * on other shared libs. Loading a "libfoo.so" could not solve the + * dependencies problem. + * + * You can, however, give a library name ending in ".so" + * (or whatever is used on your platform), and the library + * will be loaded without resolving dependencies. USE WITH CARE :) + * @return the @ref KLibFactory, or 0 if the library does not exist or it does + * not have a factory + * @see #library + */ + KLibFactory* factory( const char* libname ); + + /** + * Loads and initializes a library. Loading a library multiple times is + * handled gracefully. + * + * @param libname This is the library name without extension. Usually that is something like + * "libkspread". The function will then search for a file named + * "libkspread.la" in the KDE library paths. + * The *.la files are created by libtool and contain + * important information especially about the libraries dependencies + * on other shared libs. Loading a "libfoo.so" could not solve the + * dependencies problem. + * + * You can, however, give a library name ending in ".so" + * (or whatever is used on your platform), and the library + * will be loaded without resolving dependencies. USE WITH CARE :) + * @return @ref KLibrary is invalid (0) when the library couldn't be dlopened. in such + * a case you can retrieve the error message by calling KLibLoader::lastErrorMessage() + * + * @see #factory + */ + virtual KLibrary* library( const char* libname ); + + /** + * Loads and initializes a library. Loading a library multiple times is + * handled gracefully. The library is loaded such that the symbols are + * globally accessible so libraries with dependencies can be loaded + * sequentially. + * + * @param name This is the library name without extension. Usually that is something like + * "libkspread". The function will then search for a file named + * "libkspread.la" in the KDE library paths. + * The *.la files are created by libtool and contain + * important information especially about the libraries dependencies + * on other shared libs. Loading a "libfoo.so" could not solve the + * dependencies problem. + * + * You can, however, give a library name ending in ".so" + * (or whatever is used on your platform), and the library + * will be loaded without resolving dependencies. USE WITH CARE :) + * @return KLibrariy is invalid (0) when the library couldn't be dlopened. in such + * a case you can retrieve the error message by calling KLibLoader::lastErrorMessage() + * + * @see #factory + */ + KLibrary* globalLibrary( const char *name ); + + /* + * Returns an error message that can be useful to debug the problem. + * Returns QString::null if the last call to @ref #library() was successful. + * You can call this function more than once. The error message is only + * reset by a new call to library(). + * @return the last error message, or QString::null if there was no error + */ + QString lastErrorMessage() const; + + /** + * Unloads the library with the given name. + * @param libname This is the library name without extension. Usually that is something like + * "libkspread". The function will then search for a file named + * "libkspread.la" in the KDE library paths. + * The *.la files are created by libtool and contain + * important information especially about the libraries dependencies + * on other shared libs. Loading a "libfoo.so" could not solve the + * dependencies problem. + * + * You can, however, give a library name ending in ".so" + * (or whatever is used on your platform), and the library + * will be loaded without resolving dependencies. USE WITH CARE :) + */ + virtual void unloadLibrary( const char *libname ); + + /** + * Returns a pointer to the factory. Use this function to get an instance + * of KLibLoader. + * @return a pointer to the loader. If no loader exists until now + * then one is created. + */ + static KLibLoader* self(); + + /** + * @internal + * Internal Method, called by the KApplication destructor. + * Do not call it. + * This is what makes it possible to rely on ~KLibFactory + * being called in all cases, whether the library is unloaded + * while the application is running or when exiting. + */ + static void cleanUp(); + + /** + * Helper method which looks for a library in the standard paths + * ("module" and "lib" resources). + * Made public for code that doesn't use KLibLoader itself, but still + * wants to open modules. + * @param name of the library. If it is not a path, the function searches in + * the "module" and "lib" resources. If there is no extension, + * ".la" will be appended. + * @param instance a KInstance used to get the standard paths + */ + static QString findLibrary( const char * name/*US , const KInstance * instance = KGlobal::instance()*/ ); + +protected: + KLibLoader( QObject* parent = 0, const char* name = 0 ); + +private slots: + void slotLibraryDestroyed(); +private: + void close_pending( KLibWrapPrivate * ); + QAsciiDict m_libs; + + static KLibLoader* s_self; + +protected: + virtual void virtual_hook( int id, void* data ); +private: + KLibLoaderPrivate *d; +}; + +/** + * If you develop a library that is to be loaded dynamically at runtime, then + * you should return a pointer to your factory. The K_EXPORT_COMPONENT_FACTORY + * macro is provided for this purpose: + *
+ *   K_EXPORT_COMPONENT_FACTORY( libkspread, KSpreadFactory )
+ * 
+ * + * The first macro argument is the name of your library, the second specifies the name + * of your factory. + * + * In the constructor of your factory you should create an instance of @ref KInstance + * like this: + *
+ *     s_global = new KInstance( "kspread" );
+ * 
+ * This @ref KInstance is comparable to @ref KGlobal used by normal applications. + * It allows you to find resource files (images, XML, sound etc.) belonging + * to the library. + * + * If you want to load a library, use @ref KLibLoader. You can query @ref KLibLoader + * directly for a pointer to the libraries factory by using the @ref KLibLoader::factory() + * function. + * + * The KLibFactory is used to create the components, the library has to offer. + * The factory of KSpread for example will create instances of KSpreadDoc, + * while the Konqueror factory will create KonqView widgets. + * All objects created by the factory must be derived from @ref QObject, since @ref QObject + * offers type safe casting. + * + * KLibFactory is an abstract class. Reimplement the @ref + * createObject() method to give it functionality. + * + * @author Torben Weis + */ +class KLibFactory : public QObject +{ + Q_OBJECT +public: + /** + * Create a new factory. + * @param parent the parent of the QObject, 0 for no parent + * @param name the name of the QObject, 0 for no name + */ + KLibFactory( QObject* parent = 0, const char* name = 0 ); + virtual ~KLibFactory(); + + /** + * Creates a new object. The returned object has to be derived from + * the requested classname. + * + * It is valid behavior to create different kinds of objects + * depending on the requested @p classname. For example a koffice + * library may usually return a pointer to KoDocument. But + * if asked for a "QWidget", it could create a wrapper widget, + * that encapsulates the Koffice specific features. + * + * create() automatically emits a signal @ref objectCreated to tell + * the library about its newly created object. This is very + * important for reference counting, and allows unloading the + * library automatically once all its objects have been destroyed. + * + * @param parent the parent of the QObject, 0 for no parent + * @param name the name of the QObject, 0 for no name + * @param classname the name of the class + * @param args a list of arguments + */ + + QObject* create( QObject* parent = 0, const char* name = 0, const char* classname = "QObject", const QStringList &args = QStringList() ); + +signals: + /** + * Emitted in #create + * @param obj the new object + */ + void objectCreated( QObject *obj ); + + +protected: + + /** + * Creates a new object. The returned object has to be derived from + * the requested classname. + * + * It is valid behavior to create different kinds of objects + * depending on the requested @p classname. For example a koffice + * library may usually return a pointer to KoDocument. But + * if asked for a "QWidget", it could create a wrapper widget, + * that encapsulates the Koffice specific features. + * + * This function is called by #create() + * @param parent the parent of the QObject, 0 for no parent + * @param name the name of the QObject, 0 for no name + * @param classname the name of the class + * @param args a list of arguments + */ + virtual QObject* createObject( QObject* parent = 0, const char* name = 0, const char* classname = "QObject", const QStringList &args = QStringList() ) = 0; + + +protected: + virtual void virtual_hook( int id, void* data ); +private: + KLibFactoryPrivate *d; +}; + +#endif diff --git a/microkde/kdecore/klocale.cpp b/microkde/kdecore/klocale.cpp new file mode 100644 index 0000000..d77e251 --- a/dev/null +++ b/microkde/kdecore/klocale.cpp @@ -0,0 +1,881 @@ +#include +#include + +#include "kdebug.h" +#include "kcalendarsystemgregorian.h" + +#include "klocale.h" + + +QDict *mLocaleDict = 0; +void setLocaleDict( QDict * dict ) +{ + mLocaleDict = dict; + +} +QString i18n(const char *text) +{ + if ( ! mLocaleDict ) + return QString( text ); + else { + QString* ret = mLocaleDict->find(QString(text)) ; + if ( ret == 0 ) { + return QString( text ); + } + else { + if ( (*ret).isEmpty() ) + return QString( text ); + else + return (*ret); + } + } + +} + +QString i18n(const char *,const char *text) +{ + return i18n( text ); +} + +QString i18n(const char *text1, const char *textn, int num) +{ + if ( num == 1 ) return i18n( text1 ); + else { + QString text = i18n( textn ); + int pos = text.find( "%n" ); + if ( pos >= 0 ) text.replace( pos, 2, QString::number( num ) ); + return text; + } +} + +inline void put_it_in( QChar *buffer, uint& index, const QString &s ) +{ + for ( uint l = 0; l < s.length(); l++ ) + buffer[index++] = s.at( l ); +} + +inline void put_it_in( QChar *buffer, uint& index, int number ) +{ + buffer[index++] = number / 10 + '0'; + buffer[index++] = number % 10 + '0'; +} + +static int readInt(const QString &str, uint &pos) +{ + if (!str.at(pos).isDigit()) return -1; + int result = 0; + for (; str.length() > pos && str.at(pos).isDigit(); pos++) + { + result *= 10; + result += str.at(pos).digitValue(); + } + + return result; +} + +KLocale::KLocale() : mCalendarSystem( 0 ) +{ + + m_decimalSymbol = "."; + m_positiveSign = ""; + m_negativeSign = "-"; + m_thousandsSeparator = ","; + + + + + mWeekStartsMonday = true; + mHourF24Format = true; + mIntDateFormat = 0; + mLanguage = 0; + mDateFormat = "%a %Y %b %d"; + mDateFormatShort = "%Y-%m-%d"; + mTimeZoneList << i18n ("-11:00 US/Samoa") + << i18n ("-10:00 US/Hawaii") + << i18n ("-09:00 US/Alaska") + << i18n ("-08:00 US/Pacific") + << i18n ("-07:00 US/Mountain") + << i18n ("-06:00 US/Central") + << i18n ("-05:00 US/Eastern") + << i18n ("-04:00 Brazil/West") + << i18n ("-03:00 Brazil/East") + << i18n ("-02:00 Brazil/DeNoronha") + << i18n ("-01:00 Atlantic/Azores") + << i18n (" 00:00 Europe/London(UTC)") + << i18n ("+01:00 Europe/Oslo(CET)") + << i18n ("+02:00 Europe/Helsinki") + << i18n ("+03:00 Europe/Moscow") + << i18n ("+04:00 Indian/Mauritius") + << i18n ("+05:00 Indian/Maldives") + << i18n ("+06:00 Indian/Chagos") + << i18n ("+07:00 Asia/Bangkok") + << i18n ("+08:00 Asia/Hongkong") + << i18n ("+09:00 Asia/Tokyo") + << i18n ("+10:00 Asia/Vladivostok") + << i18n ("+11:00 Asia/Magadan") + << i18n ("+12:00 Asia/Kamchatka") + // << i18n (" xx:xx User defined offset") + << i18n (" Local Time"); + mSouthDaylight = false; + mTimeZoneOffset = 0; + daylightEnabled = false; +} + +void KLocale::setDateFormat( QString s ) +{ + mDateFormat = s; +} + +void KLocale::setDateFormatShort( QString s ) +{ + mDateFormatShort = s; +} + +void KLocale::setHore24Format ( bool b ) +{ + mHourF24Format = b; +} +void KLocale::setWeekStartMonday( bool b ) +{ + mWeekStartsMonday = b; +} +int KLocale::getIntDateFormat( ) +{ + return mIntDateFormat ; + +} +void KLocale::setIntDateFormat( int i ) +{ + mIntDateFormat = i; +} +void KLocale::setLanguage( int i ) +{ + mLanguage = i; +} +QString KLocale::translate( const char *index ) const +{ + return i18n( index ); +} + +QString KLocale::translate( const char *, const char *fallback) const +{ + return i18n( fallback ); +} + +QString KLocale::formatTime(const QTime &pTime, bool includeSecs) const +{ + const QString rst = timeFormat(); + + // only "pm/am" here can grow, the rest shrinks, but + // I'm rather safe than sorry + QChar *buffer = new QChar[rst.length() * 3 / 2 + 30]; + + uint index = 0; + bool escape = false; + int number = 0; + + for ( uint format_index = 0; format_index < rst.length(); format_index++ ) + { + if ( !escape ) + { + if ( rst.at( format_index ).unicode() == '%' ) + escape = true; + else + buffer[index++] = rst.at( format_index ); + } + else + { + switch ( rst.at( format_index ).unicode() ) + { + case '%': + buffer[index++] = '%'; + break; + case 'H': + put_it_in( buffer, index, pTime.hour() ); + break; + case 'I': + put_it_in( buffer, index, ( pTime.hour() + 11) % 12 + 1 ); + break; + case 'M': + put_it_in( buffer, index, pTime.minute() ); + break; + case 'S': + if (includeSecs) + put_it_in( buffer, index, pTime.second() ); + else + { + // we remove the seperator sign before the seconds and + // assume that works everywhere + --index; + break; + } + break; + case 'k': + number = pTime.hour(); + case 'l': + // to share the code + if ( rst.at( format_index ).unicode() == 'l' ) + number = (pTime.hour() + 11) % 12 + 1; + if ( number / 10 ) + buffer[index++] = number / 10 + '0'; + buffer[index++] = number % 10 + '0'; + break; + case 'p': + { + QString s; + if ( pTime.hour() >= 12 ) + put_it_in( buffer, index, i18n("pm") ); + else + put_it_in( buffer, index, i18n("am") ); + break; + } + default: + buffer[index++] = rst.at( format_index ); + break; + } + escape = false; + } + } + QString ret( buffer, index ); + delete [] buffer; + return ret; +} + +QString KLocale::formatDate(const QDate &pDate, bool shortFormat) const +{ + const QString rst = shortFormat?dateFormatShort():dateFormat(); + + // I'm rather safe than sorry + QChar *buffer = new QChar[rst.length() * 3 / 2 + 50]; + + unsigned int index = 0; + bool escape = false; + int number = 0; + + for ( uint format_index = 0; format_index < rst.length(); ++format_index ) + { + if ( !escape ) + { + if ( rst.at( format_index ).unicode() == '%' ) + escape = true; + else + buffer[index++] = rst.at( format_index ); + } + else + { + switch ( rst.at( format_index ).unicode() ) + { + case '%': + buffer[index++] = '%'; + break; + case 'Y': + put_it_in( buffer, index, pDate.year() / 100 ); + case 'y': + put_it_in( buffer, index, pDate.year() % 100 ); + break; + case 'n': + number = pDate.month(); + case 'e': + // to share the code + if ( rst.at( format_index ).unicode() == 'e' ) + number = pDate.day(); + if ( number / 10 ) + buffer[index++] = number / 10 + '0'; + buffer[index++] = number % 10 + '0'; + break; + case 'm': + put_it_in( buffer, index, pDate.month() ); + break; + case 'b': + put_it_in( buffer, index, monthName(pDate.month(), true) ); + break; + case 'B': + put_it_in( buffer, index, monthName(pDate.month(), false) ); + break; + case 'd': + put_it_in( buffer, index, pDate.day() ); + break; + case 'a': + put_it_in( buffer, index, weekDayName(pDate.dayOfWeek(), true) ); + break; + case 'A': + put_it_in( buffer, index, weekDayName(pDate.dayOfWeek(), false) ); + break; + default: + buffer[index++] = rst.at( format_index ); + break; + } + escape = false; + } + } + QString ret( buffer, index ); + delete [] buffer; + return ret; +} + +QString KLocale::formatDateTime(const QDateTime &pDateTime, + bool shortFormat, + bool includeSeconds) const +{ + return QString( "%1 %2") + .arg( formatDate( pDateTime.date(), shortFormat ) ) + .arg( formatTime( pDateTime.time(), includeSeconds ) ); +} + +QString KLocale::formatDateTime(const QDateTime &pDateTime) const +{ + return formatDateTime(pDateTime, true); +} + +QDate KLocale::readDate(const QString &intstr, bool* ok) const +{ + QDate date; + date = readDate(intstr, true, ok); + if (date.isValid()) return date; + return readDate(intstr, false, ok); +} + +QDate KLocale::readDate(const QString &intstr, bool shortFormat, bool* ok) const +{ + QString fmt = (shortFormat ? dateFormatShort() : dateFormat()).simplifyWhiteSpace(); + return readDate( intstr, fmt, ok ); +} + +QDate KLocale::readDate(const QString &intstr, const QString &fmt, bool* ok) const +{ + //kdDebug(173) << "KLocale::readDate intstr=" << intstr << " fmt=" << fmt << endl; + QString str = intstr.simplifyWhiteSpace().lower(); + int day = -1, month = -1; + // allow the year to be omitted if not in the format + int year = QDate::currentDate().year(); + uint strpos = 0; + uint fmtpos = 0; + + while (fmt.length() > fmtpos || str.length() > strpos) + { + if ( !(fmt.length() > fmtpos && str.length() > strpos) ) + goto error; + + QChar c = fmt.at(fmtpos++); + + if (c != '%') { + if (c.isSpace()) + strpos++; + else if (c != str.at(strpos++)) + goto error; + continue; + } + + // remove space at the begining + if (str.length() > strpos && str.at(strpos).isSpace()) + strpos++; + + c = fmt.at(fmtpos++); + switch (c) + { + case 'a': + case 'A': + // this will just be ignored + { // Cristian Tache: porting to Win: Block added because of "j" redefinition + for (int j = 1; j < 8; j++) { + QString s = weekDayName(j, c == 'a').lower(); + int len = s.length(); + if (str.mid(strpos, len) == s) + strpos += len; + } + break; + } + case 'b': + case 'B': + { // Cristian Tache: porting to Win: Block added because of "j" redefinition + for (int j = 1; j < 13; j++) { + QString s = monthName(j, c == 'b').lower(); + int len = s.length(); + if (str.mid(strpos, len) == s) { + month = j; + strpos += len; + } + } + break; + } + case 'd': + case 'e': + day = readInt(str, strpos); + if (day < 1 || day > 31) + goto error; + + break; + + case 'n': + case 'm': + month = readInt(str, strpos); + if (month < 1 || month > 12) + goto error; + + break; + + case 'Y': + case 'y': + year = readInt(str, strpos); + if (year < 0) + goto error; + // Qt treats a year in the range 0-100 as 1900-1999. + // It is nicer for the user if we treat 0-68 as 2000-2068 + if (year < 69) + year += 2000; + else if (c == 'y') + year += 1900; + + break; + } + } + //kdDebug(173) << "KLocale::readDate day=" << day << " month=" << month << " year=" << year << endl; + if ( year != -1 && month != -1 && day != -1 ) + { + if (ok) *ok = true; + return QDate(year, month, day); + } + error: + if (ok) *ok = false; + return QDate(); // invalid date +} + +QTime KLocale::readTime(const QString &intstr, bool *ok) const +{ + QTime _time; + _time = readTime(intstr, true, ok); + if (_time.isValid()) return _time; + return readTime(intstr, false, ok); +} + +QTime KLocale::readTime(const QString &intstr, bool seconds, bool *ok) const +{ + QString str = intstr.simplifyWhiteSpace().lower(); + QString Format = timeFormat().simplifyWhiteSpace(); + if (!seconds) + Format.replace(QRegExp(QString::fromLatin1(".%S")), QString::null); + + int hour = -1, minute = -1, second = seconds ? -1 : 0; // don't require seconds + bool g_12h = false; + bool pm = false; + uint strpos = 0; + uint Formatpos = 0; + + while (Format.length() > Formatpos || str.length() > strpos) + { + if ( !(Format.length() > Formatpos && str.length() > strpos) ) goto error; + + QChar c = Format.at(Formatpos++); + + if (c != '%') + { + if (c.isSpace()) + strpos++; + else if (c != str.at(strpos++)) + goto error; + continue; + } + + // remove space at the begining + if (str.length() > strpos && str.at(strpos).isSpace()) + strpos++; + + c = Format.at(Formatpos++); + switch (c) + { + case 'p': + { + QString s; + s = i18n("pm").lower(); + int len = s.length(); + if (str.mid(strpos, len) == s) + { + pm = true; + strpos += len; + } + else + { + s = i18n("am").lower(); + len = s.length(); + if (str.mid(strpos, len) == s) { + pm = false; + strpos += len; + } + else + goto error; + } + } + break; + + case 'k': + case 'H': + g_12h = false; + hour = readInt(str, strpos); + if (hour < 0 || hour > 23) + goto error; + + break; + + case 'l': + case 'I': + g_12h = true; + hour = readInt(str, strpos); + if (hour < 1 || hour > 12) + goto error; + + break; + + case 'M': + minute = readInt(str, strpos); + if (minute < 0 || minute > 59) + goto error; + + break; + + case 'S': + second = readInt(str, strpos); + if (second < 0 || second > 59) + goto error; + + break; + } + } + if (g_12h) + { + hour %= 12; + if (pm) hour += 12; + } + + if (ok) *ok = true; + return QTime(hour, minute, second); + + error: + if (ok) *ok = false; + return QTime(-1, -1, -1); // return invalid date if it didn't work + // This will be removed in the near future, since it gives a warning on stderr. + // The presence of the bool* (since KDE-3.0) removes the need for an invalid QTime. +} + +bool KLocale::use12Clock() const +{ + return !mHourF24Format ;; +} + +bool KLocale::weekStartsMonday() const +{ + return mWeekStartsMonday; +} + +int KLocale::weekStartDay() const +{ + if ( mWeekStartsMonday ) + return 1; + return 7; +} + +QString KLocale::weekDayName(int i,bool shortName) const +{ + if ( shortName ) + switch ( i ) + { + case 1: return i18n("Monday", "Mon"); + case 2: return i18n("Tuesday", "Tue"); + case 3: return i18n("Wednesday", "Wed"); + case 4: return i18n("Thursday", "Thu"); + case 5: return i18n("Friday", "Fri"); + case 6: return i18n("Saturday", "Sat"); + case 7: return i18n("Sunday", "Sun"); + } + else + switch ( i ) + { + case 1: return i18n("Monday"); + case 2: return i18n("Tuesday"); + case 3: return i18n("Wednesday"); + case 4: return i18n("Thursday"); + case 5: return i18n("Friday"); + case 6: return i18n("Saturday"); + case 7: return i18n("Sunday"); + } + + return QString::null; +} + +QString KLocale::monthName(int i,bool shortName) const +{ + if ( shortName ) + switch ( i ) + { + case 1: return i18n("January", "Jan"); + case 2: return i18n("February", "Feb"); + case 3: return i18n("March", "Mar"); + case 4: return i18n("April", "Apr"); + case 5: return i18n("May short", "May"); + case 6: return i18n("June", "Jun"); + case 7: return i18n("July", "Jul"); + case 8: return i18n("August", "Aug"); + case 9: return i18n("September", "Sep"); + case 10: return i18n("October", "Oct"); + case 11: return i18n("November", "Nov"); + case 12: return i18n("December", "Dec"); + } + else + switch (i) + { + case 1: return i18n("January"); + case 2: return i18n("February"); + case 3: return i18n("March"); + case 4: return i18n("April"); + case 5: return i18n("May long", "May"); + case 6: return i18n("June"); + case 7: return i18n("July"); + case 8: return i18n("August"); + case 9: return i18n("September"); + case 10: return i18n("October"); + case 11: return i18n("November"); + case 12: return i18n("December"); + } + + return QString::null; +} + +QString KLocale::country() const +{ + return QString::null; +} + +QString KLocale::dateFormat() const +{ + if ( QApplication::desktop()->width() < 480 ) { + if ( mIntDateFormat == 0 ) + return "%a %d %b %Y"; + else if ( mIntDateFormat == 1 ) + return "%a %b %d %Y"; + else if ( mIntDateFormat == 2 ) + return "%a %Y %b %d"; + } else { + + if ( mIntDateFormat == 0 ) + return "%A %d %B %Y"; + else if ( mIntDateFormat == 1 ) + return "%A %B %d %Y"; + else if ( mIntDateFormat == 2 ) + return "%A %Y %B %d"; + } + return mDateFormat ; +} + +QString KLocale::dateFormatShort() const +{ + + if ( mIntDateFormat == 0 ) + return "%d.%m.%Y"; + else if ( mIntDateFormat == 1 ) + return "%m.%d.%Y"; + else if ( mIntDateFormat == 2 ) + return "%Y-%m-%d"; + return mDateFormatShort ; + +} + + +QString KLocale::timeFormat() const +{ + if ( mHourF24Format) + return "%H:%M:%S"; + return "%I:%M:%S%p"; +} + +void KLocale::insertCatalogue ( const QString & ) +{ +} + +KCalendarSystem *KLocale::calendar() +{ + if ( !mCalendarSystem ) { + mCalendarSystem = new KCalendarSystemGregorian; + } + + return mCalendarSystem; +} + +int KLocale::timezoneOffset( QString timeZone ) +{ + int ret = 1001; + int index = mTimeZoneList.findIndex( timeZone ); + if ( index < 24 ) + ret = ( index-11 ) * 60 ; + return ret; +} + +QStringList KLocale::timeZoneList() const +{ + return mTimeZoneList; +} +void KLocale::setTimezone( const QString &timeZone ) +{ + mTimeZoneOffset = timezoneOffset( timeZone ); +} + +void KLocale::setDaylightSaving( bool b, int start , int end ) +{ + daylightEnabled = b; + daylightStart = start; + daylightEnd = end; + mSouthDaylight = (end < start); + // qDebug("klocale daylight %d %d %d ", b, start , end ); +} + +int KLocale::localTimeOffset( const QDateTime &dt ) +{ + bool addDaylight = false; + if ( daylightEnabled ) { + int d_end, d_start; + int dayofyear = dt.date().dayOfYear(); + int year = dt.date().year(); + int add = 0; + if ( QDate::leapYear(year) ) + add = 1; + QDate date ( year,1,1 ); + if ( daylightEnd > 59 ) + d_end = daylightEnd +add; + else + d_end = daylightEnd; + if ( daylightStart > 59 ) + d_start = daylightStart +add; + else + d_start = daylightStart; + QDate s_date = date.addDays( d_start -1 ); + QDate e_date = date.addDays( d_end -1 ); + int dof = s_date.dayOfWeek(); + if ( dof < 7 ) + s_date = s_date.addDays( -dof ); + dof = e_date.dayOfWeek(); + if ( dof < 7 ) + e_date = e_date.addDays( -dof ); + QTime startTime ( 3,0,0 ); + QDateTime startDt( s_date, startTime ); + QDateTime endDt( e_date, startTime ); + //qDebug("dayligt saving start %s end %s ",startDt.toString().latin1(),endDt.toString().latin1( )); + if ( mSouthDaylight ) { + if ( ! ( endDt < dt && dt < startDt) ) + addDaylight = true; + } else { + if ( startDt < dt && dt < endDt ) + addDaylight = true; + + + } + } + int addMin = 0; + if ( addDaylight ) + addMin = 60; + return mTimeZoneOffset + addMin; +} +// ****************************************************************** +// added LR +QString KLocale::formatNumber(double num, int precision) const +{ + bool neg = num < 0; + if (precision == -1) precision = 2; + QString res = QString::number(neg?-num:num, 'f', precision); + int pos = res.find('.'); + if (pos == -1) pos = res.length(); + else res.replace(pos, 1, decimalSymbol()); + + while (0 < (pos -= 3)) + res.insert(pos, thousandsSeparator()); // thousand sep + + // How can we know where we should put the sign? + res.prepend(neg?negativeSign():positiveSign()); + + return res; +} +QString KLocale::formatNumber(const QString &numStr) const +{ + return formatNumber(numStr.toDouble()); +} +double KLocale::readNumber(const QString &_str, bool * ok) const +{ + QString str = _str.stripWhiteSpace(); + bool neg = str.find(negativeSign()) == 0; + if (neg) + str.remove( 0, negativeSign().length() ); + + /* will hold the scientific notation portion of the number. + Example, with 2.34E+23, exponentialPart == "E+23" + */ + QString exponentialPart; + int EPos; + + EPos = str.find('E', 0, false); + + if (EPos != -1) + { + exponentialPart = str.mid(EPos); + str = str.left(EPos); + } + + int pos = str.find(decimalSymbol()); + QString major; + QString minor; + if ( pos == -1 ) + major = str; + else + { + major = str.left(pos); + minor = str.mid(pos + decimalSymbol().length()); + } + + // Remove thousand separators + int thlen = thousandsSeparator().length(); + int lastpos = 0; + while ( ( pos = major.find( thousandsSeparator() ) ) > 0 ) + { + // e.g. 12,,345,,678,,922 Acceptable positions (from the end) are 5, 10, 15... i.e. (3+thlen)*N + int fromEnd = major.length() - pos; + if ( fromEnd % (3+thlen) != 0 // Needs to be a multiple, otherwise it's an error + || pos - lastpos > 3 // More than 3 digits between two separators -> error + || pos == 0 // Can't start with a separator + || (lastpos>0 && pos-lastpos!=3)) // Must have exactly 3 digits between two separators + { + if (ok) *ok = false; + return 0.0; + } + + lastpos = pos; + major.remove( pos, thlen ); + } + if (lastpos>0 && major.length()-lastpos!=3) // Must have exactly 3 digits after the last separator + { + if (ok) *ok = false; + return 0.0; + } + + QString tot; + if (neg) tot = '-'; + + tot += major + '.' + minor + exponentialPart; + + return tot.toDouble(ok); +} +QString KLocale::decimalSymbol() const +{ + + return m_decimalSymbol; +} + +QString KLocale::thousandsSeparator() const +{ + + return m_thousandsSeparator; +} +QString KLocale::positiveSign() const +{ + return m_positiveSign; +} + +QString KLocale::negativeSign() const +{ + return m_negativeSign; +} diff --git a/microkde/kdecore/klocale.h b/microkde/kdecore/klocale.h new file mode 100644 index 0000000..7470cd2 --- a/dev/null +++ b/microkde/kdecore/klocale.h @@ -0,0 +1,110 @@ +#ifndef MINIKDE_KLOCALE_H +#define MINIKDE_KLOCALE_H + +#include +#include +#include +#include + +#ifndef I18N_NOOP +#define I18N_NOOP(x) (x) +#endif + +class KCalendarSystem; +void setLocaleDict( QDict * dict ); +QString i18n(const char *text); +QString i18n(const char *hint, const char *text); +QString i18n(const char *text1, const char *textn, int num); + +// Qt3's uic generates i18n( "msg", "comment" ) calls which conflict +// with our i18n method. we use uic -tr tr2i18n to redirect +// to the right i18n() function +inline QString tr2i18n(const char* message, const char* =0) { + return i18n( message); +} + +class KLocale +{ + public: + KLocale(); + + QString formatNumber(double num, int precision = -1) const; + QString formatNumber(const QString &numStr) const; + double readNumber(const QString &numStr, bool * ok = 0) const; + + QString decimalSymbol() const; + QString thousandsSeparator() const; + QString positiveSign() const; + QString negativeSign() const; + + + QString translate( const char *index ) const; + QString translate( const char *index, const char *fallback) const; + + QString formatDate(const QDate &pDate, bool shortFormat = false) const; + QString formatTime(const QTime &pTime, bool includeSecs = false) const; + QString formatDateTime(const QDateTime &pDateTime) const; + QString formatDateTime(const QDateTime &pDateTime, + bool shortFormat, + bool includeSecs = false) const; + + QDate readDate(const QString &str, bool* ok = 0) const; + QDate readDate( const QString &intstr, const QString &fmt, bool* ok = 0) const; + QTime readTime(const QString &str, bool* ok = 0) const; + + bool use12Clock() const; + bool weekStartsMonday() const; + int weekStartDay() const; + + QString weekDayName(int,bool=false) const; + QString monthName(int,bool=false) const; + + QString country() const; + + QString dateFormat() const; + QString dateFormatShort() const; + QString timeFormat() const; + + void insertCatalogue ( const QString & ); + + KCalendarSystem *calendar(); + void setHore24Format ( bool ); + void setWeekStartMonday( bool ); + void setIntDateFormat( int ); + int getIntDateFormat( ); + void setLanguage( int ); + void setDateFormat( QString ); + void setDateFormatShort( QString ); + + QString m_decimalSymbol; + QString m_thousandsSeparator; + QString m_currencySymbol; + QString m_monetaryDecimalSymbol; + QString m_monetaryThousandsSeparator; + QString m_positiveSign; + QString m_negativeSign; + + int timezoneOffset( QString ); + QStringList timeZoneList() const; + void setDaylightSaving( bool, int , int ); + int localTimeOffset(const QDateTime &); + void setTimezone( const QString &timeZone ); + private: + QTime readTime(const QString &str, bool seconds, bool *ok) const; + QDate readDate(const QString &str, bool shortFormat, bool *ok) const; + KCalendarSystem *mCalendarSystem; + bool mWeekStartsMonday; + bool mHourF24Format; + int mIntDateFormat; + int mLanguage; + QString mDateFormat; + QString mDateFormatShort; + QStringList mTimeZoneList; + bool daylightEnabled; + int mDaylightTZoffset; + int mNondaylightTZoffset; + bool mSouthDaylight; + int daylightStart, daylightEnd, mTimeZoneOffset; +}; + +#endif diff --git a/microkde/kdecore/klocale_new.cpp b/microkde/kdecore/klocale_new.cpp new file mode 100644 index 0000000..223b6c4 --- a/dev/null +++ b/microkde/kdecore/klocale_new.cpp @@ -0,0 +1,2441 @@ +// -*- c-basic-offset: 2 -*- +/* This file is part of the KDE libraries + Copyright (c) 1997,2001 Stephan Kulow + Copyright (c) 1999 Preston Brown + Copyright (c) 1999-2002 Hans Petter Bieker + Copyright (c) 2002 Lukas Tinkl + + 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. +*/ + +//US#include + +#include // getenv +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "kcatalogue.h" +#include "kglobal.h" +#include "kstandarddirs.h" +#include "ksimpleconfig.h" +//US #include "kinstance.h" +#include "kconfig.h" +#include "kconfigbase.h" +#include "kdebug.h" +#include "kcalendarsystem.h" + +//US we use no factory. Simply use the gregorian calendar +//US #include "kcalendarsystemfactory.h" +#include "kcalendarsystemgregorian.h" + +#include "klocale.h" + +static const char * const SYSTEM_MESSAGES = "kdelibs"; + +static const char *maincatalogue = 0; + +QDict *mLocaleDict = 0; + +void setLocaleDict( QDict * dict ) +{ + mLocaleDict = dict; + +} + +class KLocalePrivate +{ +public: + int weekStartDay; + int plural_form; + bool nounDeclension; + bool dateMonthNamePossessive; + QStringList languageList; + QValueList catalogues; + QString encoding; + QTextCodec * codecForEncoding; + KConfig * config; + bool formatInited; + int /*QPrinter::PageSize*/ pageSize; + KLocale::MeasureSystem measureSystem; + QStringList langTwoAlpha; + KConfig *languages; + + QString calendarType; + KCalendarSystem * calendar; + QString first_language; + bool utf8FileEncoding; +}; + +static KLocale *this_klocale = 0; + +KLocale::KLocale( const QString & catalogue, KConfig * config ) +{ + d = new KLocalePrivate; + d->config = config; + d->languages = 0; + d->calendar = 0; + + initCatalogue(catalogue); + initEncoding(0); + initFileNameEncoding(0); + + KConfig *cfg = d->config; + this_klocale = this; +//US if (!cfg) cfg = KGlobal::instance()->config(); + if (!cfg) cfg = KGlobal::config(); + this_klocale = 0; +//US Q_ASSERT( cfg ); + ASSERT( cfg ); + + if (m_language.isEmpty()) + initLanguage(cfg, config == 0); + + +/*US +//US mDateFormat = "%a %Y %b %d"; +//US mDateFormatShort = "%Y-%m-%d"; + mTimeZoneList << i18n ("-11:00 US/Samoa") + << i18n ("-10:00 US/Hawaii") + << i18n ("-09:00 US/Alaska") + << i18n ("-08:00 US/Pacific") + << i18n ("-07:00 US/Mountain") + << i18n ("-06:00 US/Central") + << i18n ("-05:00 US/Eastern") + << i18n ("-04:00 Brazil/West") + << i18n ("-03:00 Brazil/East") + << i18n ("-02:00 Brazil/DeNoronha") + << i18n ("-01:00 Atlantic/Azores") + << i18n (" 00:00 Europe/London(UTC)") + << i18n ("+01:00 Europe/Oslo(CET)") + << i18n ("+02:00 Europe/Helsinki") + << i18n ("+03:00 Europe/Moscow") + << i18n ("+04:00 Indian/Mauritius") + << i18n ("+05:00 Indian/Maldives") + << i18n ("+06:00 Indian/Chagos") + << i18n ("+07:00 Asia/Bangkok") + << i18n ("+08:00 Asia/Hongkong") + << i18n ("+09:00 Asia/Tokyo") + << i18n ("+10:00 Asia/Vladivostok") + << i18n ("+11:00 Asia/Magadan") + << i18n ("+12:00 Asia/Kamchatka") + // << i18n (" xx:xx User defined offset") + << i18n (" Local Time"); +*/ + mTimeZoneList << "-11:00 US/Samoa" + << "-10:00 US/Hawaii" + << "-09:00 US/Alaska" + << "-08:00 US/Pacific" + << "-07:00 US/Mountain" + << "-06:00 US/Central" + << "-05:00 US/Eastern" + << "-04:00 Brazil/West" + << "-03:00 Brazil/East" + << "-02:00 Brazil/DeNoronha" + << "-01:00 Atlantic/Azores" + << " 00:00 Europe/London(UTC)" + << "+01:00 Europe/Oslo(CET)" + << "+02:00 Europe/Helsinki" + << "+03:00 Europe/Moscow" + << "+04:00 Indian/Mauritius" + << "+05:00 Indian/Maldives" + << "+06:00 Indian/Chagos" + << "+07:00 Asia/Bangkok" + << "+08:00 Asia/Hongkong" + << "+09:00 Asia/Tokyo" + << "+10:00 Asia/Vladivostok" + << "+11:00 Asia/Magadan" + << "+12:00 Asia/Kamchatka" + // << " xx:xx User defined offset" + << " Local Time"; + + mSouthDaylight = false; + mTimeZoneOffset = 0; + daylightEnabled = false; + + mWeekStartsMonday = true; + mHourF24Format = true; + mIntDateFormat = 0; + mLanguage = 0; + +} + + +QString KLocale::_initLanguage(KConfigBase *config) +{ + if (this_klocale) + { + // ### HPB Why this cast?? + this_klocale->initLanguage((KConfig *) config, true); + return this_klocale->language(); + } + return QString::null; +} + +void KLocale::initCatalogue(const QString & catalogue) +{ + // Use the first non-null string. + QString mainCatalogue = catalogue; + if (maincatalogue) + mainCatalogue = QString::fromLatin1(maincatalogue); + + if (mainCatalogue.isEmpty()) { + kdDebug(173) << "KLocale instance created called without valid " + << "catalogue! Give an argument or call setMainCatalogue " + << "before init" << endl; + } + else + d->catalogues.append( KCatalogue(mainCatalogue ) ); + + // always include kdelibs.mo + d->catalogues.append( KCatalogue( SYSTEM_MESSAGES ) ); +} + +void KLocale::initLanguage(KConfig * config, bool useEnv) +{ + KConfigGroupSaver saver(config, "Locale"); + + m_country = config->readEntry( "Country" ); + if ( m_country.isEmpty() ) + m_country = defaultCountry(); + + // Reset the list and add the new languages + QStringList languageList; + if ( useEnv ) + languageList += QStringList::split + (':', QFile::decodeName( ::getenv("KDE_LANG") )); + +//US languageList += config->readListEntry("Language", ':'); + languageList += config->readListEntry("Language"); + + // same order as setlocale use + if ( useEnv ) + { + // HPB: Only run splitLocale on the environment variables.. + QStringList langs; + + langs << QFile::decodeName( ::getenv("LC_ALL") ); + langs << QFile::decodeName( ::getenv("LC_MESSAGES") ); + langs << QFile::decodeName( ::getenv("LANG") ); + langs << QFile::decodeName( ::getenv("LC_CTYPE") ); + + for ( QStringList::Iterator it = langs.begin(); + it != langs.end(); + ++it ) + { + QString ln, ct, chrset; + splitLocale(*it, ln, ct, chrset); + + if (!ct.isEmpty()) { + langs.insert(it, ln + '_' + ct); + if (!chrset.isEmpty()) + langs.insert(it, ln + '_' + ct + '.' + chrset); + } + + langs.insert(it, ln); + } + + languageList += langs; + } + + // now we have a language list -- let's use the first OK language + setLanguage( languageList ); +} + +void KLocale::doBindInit() +{ + return; // LR + for ( QValueList::Iterator it = d->catalogues.begin(); + it != d->catalogues.end(); + ++it ) + initCatalogue( *it ); + + if ( useDefaultLanguage() ) + d->plural_form = -1; + else + { + QString pf = translate_priv + ( I18N_NOOP("_: Dear translator, please do not translate this string " + "in any form, but pick the _right_ value out of " + "NoPlural/TwoForms/French... If not sure what to do mail " + "thd@kde.org and coolo@kde.org, they will tell you. " + "Better leave that out if unsure, the programs will " + "crash!!\nDefinition of PluralForm - to be set by the " + "translator of kdelibs.po"), 0); + if ( pf.isEmpty() ) { + kdWarning(173) << "found no definition of PluralForm for " << m_language << endl; + d->plural_form = -1; + } else if ( pf == "NoPlural" ) + d->plural_form = 0; + else if ( pf == "TwoForms" ) + d->plural_form = 1; + else if ( pf == "French" ) + d->plural_form = 2; + else if ( pf == "OneTwoRest" || pf == "Gaeilge" ) // Gaelige is the old name + d->plural_form = 3; + else if ( pf == "Russian" ) + d->plural_form = 4; + else if ( pf == "Polish" ) + d->plural_form = 5; + else if ( pf == "Slovenian" ) + d->plural_form = 6; + else if ( pf == "Lithuanian" ) + d->plural_form = 7; + else if ( pf == "Czech" ) + d->plural_form = 8; + else if ( pf == "Slovak" ) + d->plural_form = 9; + else if ( pf == "Maltese" ) + d->plural_form = 10; + else if ( pf == "Arabic" ) + d->plural_form = 11; + else if ( pf == "Balcan" ) + d->plural_form = 12; + else { + kdWarning(173) << "Definition of PluralForm is none of " + << "NoPlural/" + << "TwoForms/" + << "French/" + << "OneTwoRest/" + << "Russian/" + << "Polish/" + << "Slovenian/" + << "Lithuanian/" + << "Czech/" + << "Slovak/" + << "Arabic/" + << "Balcan/" + << "Maltese: " << pf << endl; + exit(1); + } + } + + d->formatInited = false; +} + +void KLocale::doFormatInit() const +{ + if ( d->formatInited ) return; + + KLocale * that = const_cast(this); + that->initFormat(); + + d->formatInited = true; +} + +void KLocale::initFormat() +{ + KConfig *config = d->config; +//US if (!config) config = KGlobal::instance()->config(); + if (!config) config = KGlobal::config(); + ASSERT( config ); + + kdDebug(173) << "KLocale::initFormat" << endl; + + // make sure the config files are read using the correct locale + // ### Why not add a KConfigBase::setLocale( const KLocale * )? + // ### Then we could remove this hack +//US +//US KLocale *lsave = KGlobal::_locale; +//US KGlobal::_locale = this; + KLocale *lsave = KGlobal::locale(); + KGlobal::setLocale(this); + + KConfigGroupSaver saver(config, "Locale"); + + + +//US in kabc/adress.cpp we have a similar setup. Check there in case of problems + KSimpleConfig entry(locateLocal("locale", + QString::fromLatin1("l10n/%1/entry.desktop") + .arg(m_country)) ); + + entry.setGroup("KCM Locale"); + + // Numeric +#define readConfigEntry(key, default, save) \ + save = entry.readEntry(key, QString::fromLatin1(default)); \ + save = config->readEntry(key, save); + +#define readConfigNumEntry(key, default, save, type) \ + save = (type)entry.readNumEntry(key, default); \ + save = (type)config->readNumEntry(key, save); + +#define readConfigBoolEntry(key, default, save) \ + save = entry.readBoolEntry(key, default); \ + save = config->readBoolEntry(key, save); + + readConfigEntry("DecimalSymbol", ".", m_decimalSymbol); + readConfigEntry("ThousandsSeparator", ",", m_thousandsSeparator); + m_thousandsSeparator.replace( QString::fromLatin1("$0"), QString::null ); + //kdDebug(173) << "m_thousandsSeparator=" << m_thousandsSeparator << endl; + + readConfigEntry("PositiveSign", "", m_positiveSign); + readConfigEntry("NegativeSign", "-", m_negativeSign); + + // Monetary + readConfigEntry("CurrencySymbol", "$", m_currencySymbol); + readConfigEntry("MonetaryDecimalSymbol", ".", m_monetaryDecimalSymbol); + readConfigEntry("MonetaryThousandsSeparator", ",", + m_monetaryThousandsSeparator); + m_monetaryThousandsSeparator.replace(QString::fromLatin1("$0"), QString::null); + + readConfigNumEntry("FracDigits", 2, m_fracDigits, int); + readConfigBoolEntry("PositivePrefixCurrencySymbol", true, + m_positivePrefixCurrencySymbol); + readConfigBoolEntry("NegativePrefixCurrencySymbol", true, + m_negativePrefixCurrencySymbol); + readConfigNumEntry("PositiveMonetarySignPosition", (int)BeforeQuantityMoney, + m_positiveMonetarySignPosition, SignPosition); + readConfigNumEntry("NegativeMonetarySignPosition", (int)ParensAround, + m_negativeMonetarySignPosition, SignPosition); + + //Grammatical + readConfigBoolEntry("NounDeclension", false, d->nounDeclension); + + // Date and time + readConfigEntry("TimeFormat", "%H:%M:%S", m_timeFormat); + readConfigEntry("DateFormat", "%A %d %B %Y", m_dateFormat); + readConfigEntry("DateFormatShort", "%Y-%m-%d", m_dateFormatShort); + readConfigBoolEntry("DateMonthNamePossessive", false, + d->dateMonthNamePossessive); + readConfigNumEntry("WeekStartDay", 1, d->weekStartDay, int); + + // other +//US readConfigNumEntry("PageSize", (int)QPrinter::A4, d->pageSize, int); + readConfigNumEntry("MeasureSystem", (int)Metric, d->measureSystem, + MeasureSystem); + readConfigEntry("CalendarSystem", "gregorian", d->calendarType); + delete d->calendar; + d->calendar = 0; // ### HPB Is this the correct place? + + // end of hack +//US KGlobal::_locale = lsave; + KGlobal::setLocale(lsave); +} + +bool KLocale::setCountry(const QString & country) +{ + // Check if the file exists too?? + if ( country.isEmpty() ) + return false; + + m_country = country; + + d->formatInited = false; + + return true; +} + +QString KLocale::catalogueFileName(const QString & language, + const KCatalogue & catalogue) +{ + QString path = QString::fromLatin1("%1/LC_MESSAGES/%2.mo") + .arg( language ) + .arg( catalogue.name() ); + + return locate( "locale", path ); +} + +bool KLocale::isLanguageInstalled(const QString & language) const +{ + // Do not allow empty languages + if ( language.isEmpty() ) return false; + + bool bRes = true; + if ( language != defaultLanguage() ) + for ( QValueList::ConstIterator it = d->catalogues.begin(); + it != d->catalogues.end() && bRes; + ++it ) + { + bRes = !catalogueFileName( language, *it ).isNull(); + if ( !bRes ) + kdDebug(173) << "message catalogue not found: " + << (*it).name() << endl; + } + + return bRes; +} + +bool KLocale::setLanguage(const QString & language) +{ + bool bRes = true; + + if (d->first_language.isNull() || language != d->first_language) + bRes = isLanguageInstalled( language ); + + if ( bRes ) + { + m_language = language; + + // remember our first time - it will be our true love + if (d->first_language.isNull()) + d->first_language = language; + + doBindInit(); + } + + return bRes; +} + +bool KLocale::setLanguage(const QStringList & languages) +{ + QStringList languageList(languages); + + // Remove duplicate entries in reverse so that we + // can keep user's language preference order intact. (DA) + for( QStringList::Iterator it = languageList.fromLast(); + it != languageList.begin(); + --it ) + if ( languageList.contains(*it) > 1 || (*it).isEmpty() ) + it = languageList.remove( it ); + + bool bRes = false; + for ( QStringList::ConstIterator it = languageList.begin(); + it != languageList.end(); + ++it ) + if ( bRes = setLanguage( *it ) ) + break; + + if ( !bRes ) + setLanguage(defaultLanguage()); + + d->languageList = languageList; + d->langTwoAlpha.clear(); // Flush cache + + return bRes; +} + +void KLocale::splitLocale(const QString & aStr, + QString & language, + QString & country, + QString & chrset) +{ + QString str = aStr; + + // just in case, there is another language appended + int f = str.find(':'); + if (f >= 0) + str.truncate(f); + + country = QString::null; + chrset = QString::null; + language = QString::null; + + f = str.find('.'); + if (f >= 0) + { + chrset = str.mid(f + 1); + str.truncate(f); + } + + f = str.find('_'); + if (f >= 0) + { + country = str.mid(f + 1); + str.truncate(f); + } + + language = str; +} + +QString KLocale::language() const +{ + return m_language; +} + +QString KLocale::country() const +{ + return m_country; +} + +QString KLocale::monthName(int i, bool shortName) const +{ + if ( shortName ) + switch ( i ) + { + case 1: return translate("January", "Jan"); + case 2: return translate("February", "Feb"); + case 3: return translate("March", "Mar"); + case 4: return translate("April", "Apr"); + case 5: return translate("May short", "May"); + case 6: return translate("June", "Jun"); + case 7: return translate("July", "Jul"); + case 8: return translate("August", "Aug"); + case 9: return translate("September", "Sep"); + case 10: return translate("October", "Oct"); + case 11: return translate("November", "Nov"); + case 12: return translate("December", "Dec"); + } + else + switch (i) + { + case 1: return translate("January"); + case 2: return translate("February"); + case 3: return translate("March"); + case 4: return translate("April"); + case 5: return translate("May long", "May"); + case 6: return translate("June"); + case 7: return translate("July"); + case 8: return translate("August"); + case 9: return translate("September"); + case 10: return translate("October"); + case 11: return translate("November"); + case 12: return translate("December"); + } + + return QString::null; +} + +QString KLocale::monthNamePossessive(int i, bool shortName) const +{ + if ( shortName ) + switch ( i ) + { + case 1: return translate("of January", "of Jan"); + case 2: return translate("of February", "of Feb"); + case 3: return translate("of March", "of Mar"); + case 4: return translate("of April", "of Apr"); + case 5: return translate("of May short", "of May"); + case 6: return translate("of June", "of Jun"); + case 7: return translate("of July", "of Jul"); + case 8: return translate("of August", "of Aug"); + case 9: return translate("of September", "of Sep"); + case 10: return translate("of October", "of Oct"); + case 11: return translate("of November", "of Nov"); + case 12: return translate("of December", "of Dec"); + } + else + switch (i) + { + case 1: return translate("of January"); + case 2: return translate("of February"); + case 3: return translate("of March"); + case 4: return translate("of April"); + case 5: return translate("of May long", "of May"); + case 6: return translate("of June"); + case 7: return translate("of July"); + case 8: return translate("of August"); + case 9: return translate("of September"); + case 10: return translate("of October"); + case 11: return translate("of November"); + case 12: return translate("of December"); + } + + return QString::null; +} + +QString KLocale::weekDayName (int i, bool shortName) const +{ + if ( shortName ) + switch ( i ) + { + case 1: return translate("Monday", "Mon"); + case 2: return translate("Tuesday", "Tue"); + case 3: return translate("Wednesday", "Wed"); + case 4: return translate("Thursday", "Thu"); + case 5: return translate("Friday", "Fri"); + case 6: return translate("Saturday", "Sat"); + case 7: return translate("Sunday", "Sun"); + } + else + switch ( i ) + { + case 1: return translate("Monday"); + case 2: return translate("Tuesday"); + case 3: return translate("Wednesday"); + case 4: return translate("Thursday"); + case 5: return translate("Friday"); + case 6: return translate("Saturday"); + case 7: return translate("Sunday"); + } + + return QString::null; +} + +void KLocale::insertCatalogue( const QString & catalogue ) +{ + KCatalogue cat( catalogue ); + + initCatalogue( cat ); + + d->catalogues.append( cat ); +} + +void KLocale::removeCatalogue(const QString &catalogue) +{ + for ( QValueList::Iterator it = d->catalogues.begin(); + it != d->catalogues.end(); ) + if ((*it).name() == catalogue) { + it = d->catalogues.remove(it); + return; + } else + ++it; +} + +void KLocale::setActiveCatalogue(const QString &catalogue) +{ + for ( QValueList::Iterator it = d->catalogues.begin(); + it != d->catalogues.end(); ++it) + if ((*it).name() == catalogue) { + KCatalogue save = *it; + d->catalogues.remove(it); + d->catalogues.prepend(save); + return; + } +} + +KLocale::~KLocale() +{ + delete d->languages; + delete d; +} + +QString KLocale::translate_priv(const char *msgid, + const char *fallback, + const char **translated) const +{ + if (!msgid || !msgid[0]) + { + kdWarning() << "KLocale: trying to look up \"\" in catalogue. " + << "Fix the program" << endl; + return QString::null; + } + + if ( useDefaultLanguage() ) + return QString::fromUtf8( fallback ); + + for ( QValueList::ConstIterator it = d->catalogues.begin(); + it != d->catalogues.end(); + ++it ) + { + // kdDebug(173) << "translate " << msgid << " " << (*it).name() << " " << (!KGlobal::activeInstance() ? QCString("no instance") : KGlobal::activeInstance()->instanceName()) << endl; + const char * text = (*it).translate( msgid ); + + if ( text ) + { + // we found it + if (translated) + *translated = text; + return QString::fromUtf8( text ); + } + } + + // Always use UTF-8 if the string was not found + return QString::fromUtf8( fallback ); +} + +QString KLocale::translate(const char* msgid) const +{ + return translate_priv(msgid, msgid); +} + +QString KLocale::translate( const char *index, const char *fallback) const +{ + if (!index || !index[0] || !fallback || !fallback[0]) + { + kdDebug(173) << "KLocale: trying to look up \"\" in catalogue. " + << "Fix the program" << endl; + return QString::null; + } + + if ( useDefaultLanguage() ) + return QString::fromUtf8( fallback ); + + char *newstring = new char[strlen(index) + strlen(fallback) + 5]; + sprintf(newstring, "_: %s\n%s", index, fallback); + // as copying QString is very fast, it looks slower as it is ;/ + QString r = translate_priv(newstring, fallback); + delete [] newstring; + + return r; +} + +static QString put_n_in(const QString &orig, unsigned long n) +{ + QString ret = orig; + int index = ret.find("%n"); + if (index == -1) + return ret; + ret.replace(index, 2, QString::number(n)); + return ret; +} + +#define EXPECT_LENGTH(x) \ + if (forms.count() != x) { \ + kdError() << "translation of \"" << singular << "\" doesn't contain " << x << " different plural forms as expected\n"; \ + return QString( "BROKEN TRANSLATION %1" ).arg( singular ); } + +QString KLocale::translate( const char *singular, const char *plural, + unsigned long n ) const +{ + if (!singular || !singular[0] || !plural || !plural[0]) + { + kdWarning() << "KLocale: trying to look up \"\" in catalogue. " + << "Fix the program" << endl; + return QString::null; + } + + char *newstring = new char[strlen(singular) + strlen(plural) + 6]; + sprintf(newstring, "_n: %s\n%s", singular, plural); + // as copying QString is very fast, it looks slower as it is ;/ + QString r = translate_priv(newstring, 0); + delete [] newstring; + + if ( r.isEmpty() || useDefaultLanguage() || d->plural_form == -1) { + if ( n == 1 ) { + return put_n_in( QString::fromUtf8( singular ), n ); + } else { + QString tmp = QString::fromUtf8( plural ); +#ifndef NDEBUG + if (tmp.find("%n") == -1) { + kdWarning() << "the message for i18n should contain a '%n'! " << plural << endl; + } +#endif + return put_n_in( tmp, n ); + } + } + + QStringList forms = QStringList::split( "\n", r, false ); + switch ( d->plural_form ) { + case 0: // NoPlural + EXPECT_LENGTH( 1 ); + return put_n_in( forms[0], n); + case 1: // TwoForms + EXPECT_LENGTH( 2 ); + if ( n == 1 ) + return put_n_in( forms[0], n); + else + return put_n_in( forms[1], n); + case 2: // French + EXPECT_LENGTH( 2 ); + if ( n == 1 || n == 0 ) + return put_n_in( forms[0], n); + else + return put_n_in( forms[1], n); + case 3: // Gaeilge + EXPECT_LENGTH( 3 ); + if ( n == 1 ) + return put_n_in( forms[0], n); + else if ( n == 2 ) + return put_n_in( forms[1], n); + else + return put_n_in( forms[2], n); + case 4: // Russian, corrected by mok + EXPECT_LENGTH( 3 ); + if ( n%10 == 1 && n%100 != 11) + return put_n_in( forms[0], n); // odin fail + else if (( n%10 >= 2 && n%10 <=4 ) && (n%100<10 || n%100>20)) + return put_n_in( forms[1], n); // dva faila + else + return put_n_in( forms[2], n); // desyat' failov + case 5: // Polish + EXPECT_LENGTH( 3 ); + if ( n == 1 ) + return put_n_in( forms[0], n); + else if ( n%10 >= 2 && n%10 <=4 && (n%100<10 || n%100>=20) ) + return put_n_in( forms[1], n); + else + return put_n_in( forms[2], n); + case 6: // Slovenian + EXPECT_LENGTH( 4 ); + if ( n%100 == 1 ) + return put_n_in( forms[1], n); // ena datoteka + else if ( n%100 == 2 ) + return put_n_in( forms[2], n); // dve datoteki + else if ( n%100 == 3 || n%100 == 4 ) + return put_n_in( forms[3], n); // tri datoteke + else + return put_n_in( forms[0], n); // sto datotek + case 7: // Lithuanian + EXPECT_LENGTH( 3 ); + if ( n%10 == 0 || (n%100>=11 && n%100<=19) ) + return put_n_in( forms[2], n); + else if ( n%10 == 1 ) + return put_n_in( forms[0], n); + else + return put_n_in( forms[1], n); + case 8: // Czech + EXPECT_LENGTH( 3 ); + if ( n%100 == 1 ) + return put_n_in( forms[0], n); + else if (( n%100 >= 2 ) && ( n%100 <= 4 )) + return put_n_in( forms[1], n); + else + return put_n_in( forms[2], n); + case 9: // Slovak + EXPECT_LENGTH( 3 ); + if ( n == 1 ) + return put_n_in( forms[0], n); + else if (( n >= 2 ) && ( n <= 4 )) + return put_n_in( forms[1], n); + else + return put_n_in( forms[2], n); + case 10: // Maltese + EXPECT_LENGTH( 4 ); + if ( n == 1 ) + return put_n_in( forms[0], n ); + else if ( ( n == 0 ) || ( n%100 > 0 && n%100 <= 10 ) ) + return put_n_in( forms[1], n ); + else if ( n%100 > 10 && n%100 < 20 ) + return put_n_in( forms[2], n ); + else + return put_n_in( forms[3], n ); + case 11: // Arabic + EXPECT_LENGTH( 4 ); + if (n == 1) + return put_n_in(forms[0], n); + else if (n == 2) + return put_n_in(forms[1], n); + else if ( n < 11) + return put_n_in(forms[2], n); + else + return put_n_in(forms[3], n); + case 12: // Balcan + EXPECT_LENGTH( 3 ); + if (n != 11 && n % 10 == 1) + return put_n_in(forms[0], n); + else if (n / 10 != 1 && n % 10 >= 2 && n % 10 <= 4) + return put_n_in(forms[1], n); + else + return put_n_in(forms[2], n); + } + kdError() << "The function should have been returned in another way\n"; + + return QString::null; +} + +QString KLocale::translateQt( const char *context, const char *source, + const char *message) const +{ + if (!source || !source[0]) { + kdWarning() << "KLocale: trying to look up \"\" in catalogue. " + << "Fix the program" << endl; + return QString::null; + } + + if ( useDefaultLanguage() ) { + return QString::null; + } + + char *newstring = 0; + const char *translation = 0; + QString r; + + if ( message && message[0]) { + char *newstring = new char[strlen(source) + strlen(message) + 5]; + sprintf(newstring, "_: %s\n%s", source, message); + const char *translation = 0; + // as copying QString is very fast, it looks slower as it is ;/ + r = translate_priv(newstring, source, &translation); + delete [] newstring; + if (translation) + return r; + } + + if ( context && context[0] && message && message[0]) { + newstring = new char[strlen(context) + strlen(message) + 5]; + sprintf(newstring, "_: %s\n%s", context, message); + // as copying QString is very fast, it looks slower as it is ;/ + r = translate_priv(newstring, source, &translation); + delete [] newstring; + if (translation) + return r; + } + + r = translate_priv(source, source, &translation); + if (translation) + return r; + return QString::null; +} + +bool KLocale::nounDeclension() const +{ + doFormatInit(); + return d->nounDeclension; +} + +bool KLocale::dateMonthNamePossessive() const +{ + doFormatInit(); + return d->dateMonthNamePossessive; +} + +int KLocale::weekStartDay() const +{ + doFormatInit(); + return d->weekStartDay; +} + +bool KLocale::weekStartsMonday() const //deprecated +{ + doFormatInit(); + return (d->weekStartDay==1); +} + +QString KLocale::decimalSymbol() const +{ + doFormatInit(); + return m_decimalSymbol; +} + +QString KLocale::thousandsSeparator() const +{ + doFormatInit(); + return m_thousandsSeparator; +} + +QString KLocale::currencySymbol() const +{ + doFormatInit(); + return m_currencySymbol; +} + +QString KLocale::monetaryDecimalSymbol() const +{ + doFormatInit(); + return m_monetaryDecimalSymbol; +} + +QString KLocale::monetaryThousandsSeparator() const +{ + doFormatInit(); + return m_monetaryThousandsSeparator; +} + +QString KLocale::positiveSign() const +{ + doFormatInit(); + return m_positiveSign; +} + +QString KLocale::negativeSign() const +{ + doFormatInit(); + return m_negativeSign; +} + +int KLocale::fracDigits() const +{ + doFormatInit(); + return m_fracDigits; +} + +bool KLocale::positivePrefixCurrencySymbol() const +{ + doFormatInit(); + return m_positivePrefixCurrencySymbol; +} + +bool KLocale::negativePrefixCurrencySymbol() const +{ + doFormatInit(); + return m_negativePrefixCurrencySymbol; +} + +KLocale::SignPosition KLocale::positiveMonetarySignPosition() const +{ + doFormatInit(); + return m_positiveMonetarySignPosition; +} + +KLocale::SignPosition KLocale::negativeMonetarySignPosition() const +{ + doFormatInit(); + return m_negativeMonetarySignPosition; +} + +static inline void put_it_in( QChar *buffer, uint& index, const QString &s ) +{ + for ( uint l = 0; l < s.length(); l++ ) + buffer[index++] = s.at( l ); +} + +static inline void put_it_in( QChar *buffer, uint& index, int number ) +{ + buffer[index++] = number / 10 + '0'; + buffer[index++] = number % 10 + '0'; +} + +QString KLocale::formatMoney(double num, + const QString & symbol, + int precision) const +{ + // some defaults + QString currency = symbol.isNull() + ? currencySymbol() + : symbol; + if (precision < 0) precision = fracDigits(); + + // the number itself + bool neg = num < 0; + QString res = QString::number(neg?-num:num, 'f', precision); + int pos = res.find('.'); + if (pos == -1) pos = res.length(); + else res.replace(pos, 1, monetaryDecimalSymbol()); + + while (0 < (pos -= 3)) + res.insert(pos, monetaryThousandsSeparator()); // thousend sep + + // set some variables we need later + int signpos = neg + ? negativeMonetarySignPosition() + : positiveMonetarySignPosition(); + QString sign = neg + ? negativeSign() + : positiveSign(); + + switch (signpos) + { + case ParensAround: + res.prepend('('); + res.append (')'); + break; + case BeforeQuantityMoney: + res.prepend(sign); + break; + case AfterQuantityMoney: + res.append(sign); + break; + case BeforeMoney: + currency.prepend(sign); + break; + case AfterMoney: + currency.append(sign); + break; + } + + if (neg?negativePrefixCurrencySymbol(): + positivePrefixCurrencySymbol()) + { + res.prepend(' '); + res.prepend(currency); + } else { + res.append (' '); + res.append (currency); + } + + return res; +} + +QString KLocale::formatMoney(const QString &numStr) const +{ + return formatMoney(numStr.toDouble()); +} + +QString KLocale::formatNumber(double num, int precision) const +{ + bool neg = num < 0; + if (precision == -1) precision = 2; + QString res = QString::number(neg?-num:num, 'f', precision); + int pos = res.find('.'); + if (pos == -1) pos = res.length(); + else res.replace(pos, 1, decimalSymbol()); + + while (0 < (pos -= 3)) + res.insert(pos, thousandsSeparator()); // thousand sep + + // How can we know where we should put the sign? + res.prepend(neg?negativeSign():positiveSign()); + + return res; +} + +QString KLocale::formatLong(long num) const +{ + return formatNumber((double)num, 0); +} + +QString KLocale::formatNumber(const QString &numStr) const +{ + return formatNumber(numStr.toDouble()); +} + +QString KLocale::formatDate(const QDate &pDate, bool shortFormat) const +{ + const QString rst = shortFormat?dateFormatShort():dateFormat(); + + // I'm rather safe than sorry + QChar *buffer = new QChar[rst.length() * 3 / 2 + 50]; + + unsigned int index = 0; + bool escape = false; + int number = 0; + + int year = calendar()->year(pDate); + int month = calendar()->month(pDate); + int day = calendar()->day(pDate); + + for ( uint format_index = 0; format_index < rst.length(); ++format_index ) + { + if ( !escape ) + { + if ( rst.at( format_index ).unicode() == '%' ) + escape = true; + else + buffer[index++] = rst.at( format_index ); + } + else + { + switch ( rst.at( format_index ).unicode() ) + { + case '%': + buffer[index++] = '%'; + break; + case 'Y': + put_it_in( buffer, index, year / 100 ); + case 'y': + put_it_in( buffer, index, year % 100 ); + break; + case 'n': + number = month; + case 'e': + // to share the code + if ( rst.at( format_index ).unicode() == 'e' ) + number = day; + if ( number / 10 ) + buffer[index++] = number / 10 + '0'; + buffer[index++] = number % 10 + '0'; + break; + case 'm': + put_it_in( buffer, index, month ); + break; + case 'b': + if (d->nounDeclension && d->dateMonthNamePossessive) +//US put_it_in( buffer, index, calendar()->monthNamePossessive(month, year, true) ); + put_it_in( buffer, index, calendar()->monthNamePossessive(month, true) ); + else +//US put_it_in( buffer, index, calendar()->monthName(month, year, true) ); + put_it_in( buffer, index, calendar()->monthName(month, true) ); + break; + case 'B': + if (d->nounDeclension && d->dateMonthNamePossessive) +//US put_it_in( buffer, index, calendar()->monthNamePossessive(month, year, false) ); + put_it_in( buffer, index, calendar()->monthNamePossessive(month, false) ); + else +//US put_it_in( buffer, index, calendar()->monthName(month, year, false) ); + put_it_in( buffer, index, calendar()->monthName(month, false) ); + break; + case 'd': + put_it_in( buffer, index, day ); + break; + case 'a': + put_it_in( buffer, index, calendar()->weekDayName(pDate, true) ); + break; + case 'A': + put_it_in( buffer, index, calendar()->weekDayName(pDate, false) ); + break; + default: + buffer[index++] = rst.at( format_index ); + break; + } + escape = false; + } + } + QString ret( buffer, index ); + delete [] buffer; + return ret; +} + +void KLocale::setMainCatalogue(const char *catalogue) +{ + maincatalogue = catalogue; +} + +double KLocale::readNumber(const QString &_str, bool * ok) const +{ + QString str = _str.stripWhiteSpace(); + bool neg = str.find(negativeSign()) == 0; + if (neg) + str.remove( 0, negativeSign().length() ); + + /* will hold the scientific notation portion of the number. + Example, with 2.34E+23, exponentialPart == "E+23" + */ + QString exponentialPart; + int EPos; + + EPos = str.find('E', 0, false); + + if (EPos != -1) + { + exponentialPart = str.mid(EPos); + str = str.left(EPos); + } + + int pos = str.find(decimalSymbol()); + QString major; + QString minor; + if ( pos == -1 ) + major = str; + else + { + major = str.left(pos); + minor = str.mid(pos + decimalSymbol().length()); + } + + // Remove thousand separators + int thlen = thousandsSeparator().length(); + int lastpos = 0; + while ( ( pos = major.find( thousandsSeparator() ) ) > 0 ) + { + // e.g. 12,,345,,678,,922 Acceptable positions (from the end) are 5, 10, 15... i.e. (3+thlen)*N + int fromEnd = major.length() - pos; + if ( fromEnd % (3+thlen) != 0 // Needs to be a multiple, otherwise it's an error + || pos - lastpos > 3 // More than 3 digits between two separators -> error + || pos == 0 // Can't start with a separator + || (lastpos>0 && pos-lastpos!=3)) // Must have exactly 3 digits between two separators + { + if (ok) *ok = false; + return 0.0; + } + + lastpos = pos; + major.remove( pos, thlen ); + } + if (lastpos>0 && major.length()-lastpos!=3) // Must have exactly 3 digits after the last separator + { + if (ok) *ok = false; + return 0.0; + } + + QString tot; + if (neg) tot = '-'; + + tot += major + '.' + minor + exponentialPart; + + return tot.toDouble(ok); +} + +double KLocale::readMoney(const QString &_str, bool * ok) const +{ + QString str = _str.stripWhiteSpace(); + bool neg = false; + bool currencyFound = false; + // First try removing currency symbol from either end + int pos = str.find(currencySymbol()); + if ( pos == 0 || pos == (int) str.length()-1 ) + { + str.remove(pos,currencySymbol().length()); + str = str.stripWhiteSpace(); + currencyFound = true; + } + if (str.isEmpty()) + { + if (ok) *ok = false; + return 0; + } + // Then try removing negative sign from either end + // (with a special case for parenthesis) + if (negativeMonetarySignPosition() == ParensAround) + { + if (str.at(0) == '(' && str.at(str.length()-1) == ')') + { + neg = true; + str.remove(str.length()-1,1); + str.remove(0,1); + } + } + else + { + int i1 = str.find(negativeSign()); + if ( i1 == 0 || i1 == (int) str.length()-1 ) + { + neg = true; + str.remove(i1,negativeSign().length()); + } + } + if (neg) str = str.stripWhiteSpace(); + + // Finally try again for the currency symbol, if we didn't find + // it already (because of the negative sign being in the way). + if ( !currencyFound ) + { + pos = str.find(currencySymbol()); + if ( pos == 0 || pos == (int) str.length()-1 ) + { + str.remove(pos,currencySymbol().length()); + str = str.stripWhiteSpace(); + } + } + + // And parse the rest as a number + pos = str.find(monetaryDecimalSymbol()); + QString major; + QString minior; + if (pos == -1) + major = str; + else + { + major = str.left(pos); + minior = str.mid(pos + monetaryDecimalSymbol().length()); + } + + // Remove thousand separators + int thlen = monetaryThousandsSeparator().length(); + int lastpos = 0; + while ( ( pos = major.find( monetaryThousandsSeparator() ) ) > 0 ) + { + // e.g. 12,,345,,678,,922 Acceptable positions (from the end) are 5, 10, 15... i.e. (3+thlen)*N + int fromEnd = major.length() - pos; + if ( fromEnd % (3+thlen) != 0 // Needs to be a multiple, otherwise it's an error + || pos - lastpos > 3 // More than 3 digits between two separators -> error + || pos == 0 // Can't start with a separator + || (lastpos>0 && pos-lastpos!=3)) // Must have exactly 3 digits between two separators + { + if (ok) *ok = false; + return 0.0; + } + lastpos = pos; + major.remove( pos, thlen ); + } + if (lastpos>0 && major.length()-lastpos!=3) // Must have exactly 3 digits after the last separator + { + if (ok) *ok = false; + return 0.0; + } + + QString tot; + if (neg) tot = '-'; + tot += major + '.' + minior; + return tot.toDouble(ok); +} + +/** + * helper function to read integers + * @param str + * @param pos the position to start at. It will be updated when we parse it. + * @return the integer read in the string, or -1 if no string + */ +static int readInt(const QString &str, uint &pos) +{ + if (!str.at(pos).isDigit()) return -1; + int result = 0; + for (; str.length() > pos && str.at(pos).isDigit(); pos++) + { + result *= 10; + result += str.at(pos).digitValue(); + } + + return result; +} + +QDate KLocale::readDate(const QString &intstr, bool* ok) const +{ + QDate date; + date = readDate(intstr, ShortFormat, ok); + if (date.isValid()) return date; + return readDate(intstr, NormalFormat, ok); +} + +QDate KLocale::readDate(const QString &intstr, ReadDateFlags flags, bool* ok) const +{ + QString fmt = ((flags & ShortFormat) ? dateFormatShort() : dateFormat()).simplifyWhiteSpace(); + return readDate( intstr, fmt, ok ); +} + +QDate KLocale::readDate(const QString &intstr, const QString &fmt, bool* ok) const +{ + //kdDebug() << "KLocale::readDate intstr=" << intstr << " fmt=" << fmt << endl; + QString str = intstr.simplifyWhiteSpace().lower(); + int day = -1, month = -1; + // allow the year to be omitted if not in the format + int year = calendar()->year(QDate::currentDate()); + uint strpos = 0; + uint fmtpos = 0; + + bool error = false; + + while (fmt.length() > fmtpos && str.length() > strpos && !error) + { + + QChar c = fmt.at(fmtpos++); + + if (c != '%') { + if (c.isSpace() && str.at(strpos).isSpace()) + strpos++; + else if (c != str.at(strpos++)) + error = true; + } + else + { + int j; + // remove space at the begining + if (str.length() > strpos && str.at(strpos).isSpace()) + strpos++; + + c = fmt.at(fmtpos++); + switch (c) + { + case 'a': + case 'A': + + error = true; + j = 1; + while (error && (j < 8)) { + QString s = weekDayName(j, c == 'a').lower(); + int len = s.length(); + if (str.mid(strpos, len) == s) + { + strpos += len; + error = false; + } + j++; + } + break; + case 'b': + case 'B': + + error = true; + if (d->nounDeclension && d->dateMonthNamePossessive) { + j = 1; + while (error && (j < 13)) { +//US QString s = calendar()->monthNamePossessive(j, year, c == 'b').lower(); + QString s = calendar()->monthNamePossessive(j, c == 'b').lower(); + int len = s.length(); + if (str.mid(strpos, len) == s) { + month = j; + strpos += len; + error = false; + } + j++; + } + } + j = 1; + while (error && (j < 13)) { +//US QString s = calendar()->monthName(j, year, c == 'b').lower(); + QString s = calendar()->monthName(j, c == 'b').lower(); + int len = s.length(); + if (str.mid(strpos, len) == s) { + month = j; + strpos += len; + error = false; + } + j++; + } + break; + case 'd': + case 'e': + day = readInt(str, strpos); + error = (day < 1 || day > 31); + break; + + case 'n': + case 'm': + month = readInt(str, strpos); + error = (month < 1 || month > 12); + break; + + case 'Y': + case 'y': + year = readInt(str, strpos); + error = (year < 0); + // Qt treats a year in the range 0-100 as 1900-1999. + // It is nicer for the user if we treat 0-68 as 2000-2068 + if (c == 'y' && year < 69) + // eg. gregorian += 2000 + year += (calendar()->year(QDate::currentDate()) / 100) * 100; + else if (c == 'y' && year < 100) + // eg. gregorian += 1900 + year += (calendar()->year(QDate::currentDate()) / 100) * 100 - 100; + break; + } + } + } + + /* for a match, we should reach the end of both strings, not just one of + them */ + if ( fmt.length() > fmtpos || str.length() > strpos ) + { + error = true; + } + + //kdDebug(173) << "KLocale::readDate day=" << day << " month=" << month << " year=" << year << endl; + if ( year != -1 && month != -1 && day != -1 && !error) + { + if (ok) *ok = true; + + QDate result; + calendar()->setYMD(result, year, month, day); + + return result; + } + else + { + if (ok) *ok = false; + return QDate(); // invalid date + } +} + +QTime KLocale::readTime(const QString &intstr, bool *ok) const +{ + QTime _time; + _time = readTime(intstr, WithSeconds, ok); + if (_time.isValid()) return _time; + return readTime(intstr, WithoutSeconds, ok); +} + +QTime KLocale::readTime(const QString &intstr, ReadTimeFlags flags, bool *ok) const +{ + QString str = intstr.simplifyWhiteSpace().lower(); + QString Format = timeFormat().simplifyWhiteSpace(); + if (flags & WithoutSeconds) + { +//US remove not available in my QT version +//US Format.remove(QRegExp(".%S")); + Format.replace(QRegExp(".%S"), ""); + } + + int hour = -1, minute = -1; + int second = ( (flags & WithoutSeconds) == 0 ) ? -1 : 0; // don't require seconds + bool g_12h = false; + bool pm = false; + uint strpos = 0; + uint Formatpos = 0; + + while (Format.length() > Formatpos || str.length() > strpos) + { + if ( !(Format.length() > Formatpos && str.length() > strpos) ) goto error; + + QChar c = Format.at(Formatpos++); + + if (c != '%') + { + if (c.isSpace()) + strpos++; + else if (c != str.at(strpos++)) + goto error; + continue; + } + + // remove space at the begining + if (str.length() > strpos && str.at(strpos).isSpace()) + strpos++; + + c = Format.at(Formatpos++); + switch (c) + { + case 'p': + { + QString s; + s = translate("pm").lower(); + int len = s.length(); + if (str.mid(strpos, len) == s) + { + pm = true; + strpos += len; + } + else + { + s = translate("am").lower(); + len = s.length(); + if (str.mid(strpos, len) == s) { + pm = false; + strpos += len; + } + else + goto error; + } + } + break; + + case 'k': + case 'H': + g_12h = false; + hour = readInt(str, strpos); + if (hour < 0 || hour > 23) + goto error; + + break; + + case 'l': + case 'I': + g_12h = true; + hour = readInt(str, strpos); + if (hour < 1 || hour > 12) + goto error; + + break; + + case 'M': + minute = readInt(str, strpos); + if (minute < 0 || minute > 59) + goto error; + + break; + + case 'S': + second = readInt(str, strpos); + if (second < 0 || second > 59) + goto error; + + break; + } + } + if (g_12h) { + hour %= 12; + if (pm) hour += 12; + } + + if (ok) *ok = true; + return QTime(hour, minute, second); + + error: + if (ok) *ok = false; + return QTime(-1, -1, -1); // return invalid date if it didn't work +} + +QString KLocale::formatTime(const QTime &pTime, bool includeSecs) const +{ + const QString rst = timeFormat(); + + // only "pm/am" here can grow, the rest shrinks, but + // I'm rather safe than sorry + QChar *buffer = new QChar[rst.length() * 3 / 2 + 30]; + + uint index = 0; + bool escape = false; + int number = 0; + + for ( uint format_index = 0; format_index < rst.length(); format_index++ ) + { + if ( !escape ) + { + if ( rst.at( format_index ).unicode() == '%' ) + escape = true; + else + buffer[index++] = rst.at( format_index ); + } + else + { + switch ( rst.at( format_index ).unicode() ) + { + case '%': + buffer[index++] = '%'; + break; + case 'H': + put_it_in( buffer, index, pTime.hour() ); + break; + case 'I': + put_it_in( buffer, index, ( pTime.hour() + 11) % 12 + 1 ); + break; + case 'M': + put_it_in( buffer, index, pTime.minute() ); + break; + case 'S': + if (includeSecs) + put_it_in( buffer, index, pTime.second() ); + else if ( index > 0 ) + { + // we remove the seperator sign before the seconds and + // assume that works everywhere + --index; + break; + } + break; + case 'k': + number = pTime.hour(); + case 'l': + // to share the code + if ( rst.at( format_index ).unicode() == 'l' ) + number = (pTime.hour() + 11) % 12 + 1; + if ( number / 10 ) + buffer[index++] = number / 10 + '0'; + buffer[index++] = number % 10 + '0'; + break; + case 'p': + { + QString s; + if ( pTime.hour() >= 12 ) + put_it_in( buffer, index, translate("pm") ); + else + put_it_in( buffer, index, translate("am") ); + break; + } + default: + buffer[index++] = rst.at( format_index ); + break; + } + escape = false; + } + } + QString ret( buffer, index ); + delete [] buffer; + return ret; +} + +bool KLocale::use12Clock() const +{ + if ((timeFormat().contains(QString::fromLatin1("%I")) > 0) || + (timeFormat().contains(QString::fromLatin1("%l")) > 0)) + return true; + else + return false; +} + +QString KLocale::languages() const +{ + return d->languageList.join( QString::fromLatin1(":") ); +} + +QStringList KLocale::languageList() const +{ + return d->languageList; +} + +QString KLocale::formatDateTime(const QDateTime &pDateTime, + bool shortFormat, + bool includeSeconds) const +{ + return translate("concatenation of dates and time", "%1 %2") + .arg( formatDate( pDateTime.date(), shortFormat ) ) + .arg( formatTime( pDateTime.time(), includeSeconds ) ); +} + +QString i18n(const char* text) +{ + /* + register KLocale *instance = KGlobal::locale(); + if (instance) + return instance->translate(text); + */ + return QString::fromUtf8(text); +} + +QString i18n(const char* index, const char *text) +{ + /* + register KLocale *instance = KGlobal::locale(); + if (instance) + return instance->translate(index, text); + */ + return QString::fromUtf8(text); +} + +QString i18n(const char* singular, const char* plural, unsigned long n) +{ + return (QString::fromUtf8(plural)); // hack! remove this line! + register KLocale *instance = KGlobal::locale(); + if (instance) + return instance->translate(singular, plural, n); + if (n == 1) + return put_n_in(QString::fromUtf8(singular), n); + else + return put_n_in(QString::fromUtf8(plural), n); +} + +void KLocale::initInstance() +{ + if (KGlobal::locale()) + return; + +/*US lets change the whole way how to create a KLocale + KInstance *app = KGlobal::instance(); + if (app) { + KGlobal::_locale = new KLocale(QString::fromLatin1(app->instanceName())); + + // only do this for the global instance + QTextCodec::setCodecForLocale(KGlobal::_locale->codecForEncoding()); + } + else + kdDebug(173) << "no app name available using KLocale - nothing to do\n"; +*/ +//US new implementation + QString appname = KGlobal::getAppName(); + if (appname) { + KLocale *l = new KLocale(appname); + KGlobal::setLocale(l); + + // only do this for the global instance +//US +//US QTextCodec::setCodecForLocale(KGlobal::locale())->codecForEncoding()); +//US qt_set_locale_codec( KGlobal::locale()->codecForEncoding() ); + qDebug("KLocale::initInstance we have to do here something !!!"); + } + else + kdDebug(173) << "no app name available using KLocale - nothing to do\n"; + +} + +QString KLocale::langLookup(const QString &fname, const char *rtype) +{ + QStringList search; + + // assemble the local search paths +//US we have only one resourcedir. So use it !! +/*US original + const QStringList localDoc = KGlobal::dirs()->resourceDirs(rtype); + // look up the different languages + for (int id=localDoc.count()-1; id >= 0; --id) + { + QStringList langs = KGlobal::locale()->languageList(); + langs.append( "en" ); + langs.remove( defaultLanguage() ); + QStringList::ConstIterator lang; + for (lang = langs.begin(); lang != langs.end(); ++lang) + search.append(QString("%1%2/%3").arg(localDoc[id]).arg(*lang).arg(fname)); + } +*/ +//US new code +//US What is here correct??? const QString localDoc = KGlobal::dirs()->findResourceDir(rtype); + const QString localDoc = rtype; + // look up the different languages + QStringList langs = KGlobal::locale()->languageList(); + langs.append( "en" ); + langs.remove( defaultLanguage() ); + QStringList::ConstIterator lang; + for (lang = langs.begin(); lang != langs.end(); ++lang) + search.append(QString("%1%2/%3").arg(localDoc).arg(*lang).arg(fname)); + + // try to locate the file + QStringList::Iterator it; + for (it = search.begin(); it != search.end(); ++it) + { + kdDebug(173) << "Looking for help in: " << *it << endl; + + QFileInfo info(*it); + if (info.exists() && info.isFile() && info.isReadable()) + return *it; + } + + return QString::null; +} + +bool KLocale::useDefaultLanguage() const +{ + return language() == defaultLanguage(); +} + +void KLocale::initEncoding(KConfig *) +{ + const int mibDefault = 4; // ISO 8859-1 + + // This all made more sense when we still had the EncodingEnum config key. + setEncoding( QTextCodec::codecForLocale()->mibEnum() ); + + if ( !d->codecForEncoding ) + { + kdWarning(173) << " Defaulting to ISO 8859-1 encoding." << endl; + setEncoding(mibDefault); + } + + ASSERT( d->codecForEncoding ); +} + +void KLocale::initFileNameEncoding(KConfig *) +{ + // If the following environment variable is set, assume all filenames + // are in UTF-8 regardless of the current C locale. + d->utf8FileEncoding = getenv("KDE_UTF8_FILENAMES") != 0; + if (d->utf8FileEncoding) + { + QFile::setEncodingFunction(KLocale::encodeFileNameUTF8); + QFile::setDecodingFunction(KLocale::decodeFileNameUTF8); + } + // Otherwise, stay with QFile's default filename encoding functions + // which, on Unix platforms, use the locale's codec. +} + +QCString KLocale::encodeFileNameUTF8( const QString & fileName ) +{ + return fileName.utf8(); +} + +QString KLocale::decodeFileNameUTF8( const QCString & localFileName ) +{ + return QString::fromUtf8(localFileName); +} + +void KLocale::initCatalogue( KCatalogue & catalogue ) +{ + catalogue.setFileName( catalogueFileName( language(), catalogue ) ); +} + +void KLocale::setDateFormat(const QString & format) +{ + doFormatInit(); + m_dateFormat = format.stripWhiteSpace(); +} + +void KLocale::setDateFormatShort(const QString & format) +{ + doFormatInit(); + m_dateFormatShort = format.stripWhiteSpace(); +} + +void KLocale::setDateMonthNamePossessive(bool possessive) +{ + doFormatInit(); + d->dateMonthNamePossessive = possessive; +} + +void KLocale::setTimeFormat(const QString & format) +{ + doFormatInit(); + m_timeFormat = format.stripWhiteSpace(); +} + +void KLocale::setWeekStartsMonday(bool start) //deprecated +{ + doFormatInit(); + if (start) + d->weekStartDay = 1; + else + d->weekStartDay = 7; +} + +void KLocale::setWeekStartDay(int day) +{ + doFormatInit(); + if (day>7 || day<1) + d->weekStartDay = 1; //Monday is default + else + d->weekStartDay = day; +} + +QString KLocale::dateFormat() const +{ + doFormatInit(); + return m_dateFormat; +} + +QString KLocale::dateFormatShort() const +{ + doFormatInit(); + return m_dateFormatShort; +} + +QString KLocale::timeFormat() const +{ + doFormatInit(); + return m_timeFormat; +} + +void KLocale::setDecimalSymbol(const QString & symbol) +{ + doFormatInit(); + m_decimalSymbol = symbol.stripWhiteSpace(); +} + +void KLocale::setThousandsSeparator(const QString & separator) +{ + doFormatInit(); + // allow spaces here + m_thousandsSeparator = separator; +} + +void KLocale::setPositiveSign(const QString & sign) +{ + doFormatInit(); + m_positiveSign = sign.stripWhiteSpace(); +} + +void KLocale::setNegativeSign(const QString & sign) +{ + doFormatInit(); + m_negativeSign = sign.stripWhiteSpace(); +} + +void KLocale::setPositiveMonetarySignPosition(SignPosition signpos) +{ + doFormatInit(); + m_positiveMonetarySignPosition = signpos; +} + +void KLocale::setNegativeMonetarySignPosition(SignPosition signpos) +{ + doFormatInit(); + m_negativeMonetarySignPosition = signpos; +} + +void KLocale::setPositivePrefixCurrencySymbol(bool prefix) +{ + doFormatInit(); + m_positivePrefixCurrencySymbol = prefix; +} + +void KLocale::setNegativePrefixCurrencySymbol(bool prefix) +{ + doFormatInit(); + m_negativePrefixCurrencySymbol = prefix; +} + +void KLocale::setFracDigits(int digits) +{ + doFormatInit(); + m_fracDigits = digits; +} + +void KLocale::setMonetaryThousandsSeparator(const QString & separator) +{ + doFormatInit(); + // allow spaces here + m_monetaryThousandsSeparator = separator; +} + +void KLocale::setMonetaryDecimalSymbol(const QString & symbol) +{ + doFormatInit(); + m_monetaryDecimalSymbol = symbol.stripWhiteSpace(); +} + +void KLocale::setCurrencySymbol(const QString & symbol) +{ + doFormatInit(); + m_currencySymbol = symbol.stripWhiteSpace(); +} + +int KLocale::pageSize() const +{ + doFormatInit(); + return d->pageSize; +} + +void KLocale::setPageSize(int pageSize) +{ + // #### check if it's in range?? + doFormatInit(); + d->pageSize = pageSize; +} + +KLocale::MeasureSystem KLocale::measureSystem() const +{ + doFormatInit(); + return d->measureSystem; +} + +void KLocale::setMeasureSystem(MeasureSystem value) +{ + doFormatInit(); + d->measureSystem = value; +} + +QString KLocale::defaultLanguage() +{ + return QString::fromLatin1("en_US"); +} + +QString KLocale::defaultCountry() +{ + return QString::fromLatin1("C"); +} + +const char * KLocale::encoding() const +{ + return codecForEncoding()->name(); +} + +int KLocale::encodingMib() const +{ + return codecForEncoding()->mibEnum(); +} + +int KLocale::fileEncodingMib() const +{ + if (d->utf8FileEncoding) + return 106; + return codecForEncoding()->mibEnum(); +} + +QTextCodec * KLocale::codecForEncoding() const +{ + return d->codecForEncoding; +} + +bool KLocale::setEncoding(int mibEnum) +{ + QTextCodec * codec = QTextCodec::codecForMib(mibEnum); + if (codec) + d->codecForEncoding = codec; + + return codec != 0; +} + +QStringList KLocale::languagesTwoAlpha() const +{ + if (d->langTwoAlpha.count()) + return d->langTwoAlpha; + + const QStringList &origList = languageList(); + + QStringList result; + +//US KConfig config(QString::fromLatin1("language.codes"), true, false); + KConfig config(locateLocal("config", QString::fromLatin1("language.codes"))); + config.setGroup("TwoLetterCodes"); + + for ( QStringList::ConstIterator it = origList.begin(); + it != origList.end(); + ++it ) + { + QString lang = *it; + QStringList langLst; + +/*US I changed the following code, because hasKey is not available. +!!! check if my version is correct + if (config.hasKey( lang )) + langLst = config.readListEntry( lang ); + else + { + int i = lang.find('_'); + if (i >= 0) + lang.truncate(i); + langLst << lang; + } +*/ + langLst = config.readListEntry( lang ); + if (langLst.isEmpty()) + { + int i = lang.find('_'); + if (i >= 0) + lang.truncate(i); + langLst << lang; + } + + + for ( QStringList::ConstIterator langIt = langLst.begin(); + langIt != langLst.end(); + ++langIt ) + { + if ( !(*langIt).isEmpty() && !result.contains( *langIt ) ) + result += *langIt; + } + } + d->langTwoAlpha = result; + return result; +} + +QStringList KLocale::allLanguagesTwoAlpha() const +{ + if (!d->languages) +//US d->languages = new KConfig("all_languages", true, false, "locale"); + d->languages = new KConfig(locateLocal( "locale", "all_languages")); + +//US return d->languages->groupList(); + qDebug("KLocale::allLanguagesTwoAlpha has to be fixed."); + return *(new QStringList()); + +} + +QString KLocale::twoAlphaToLanguageName(const QString &code) const +{ + if (!d->languages) +//US d->languages = new KConfig("all_languages", true, false, "locale"); + d->languages = new KConfig(locateLocal( "locale", "all_languages")); + + d->languages->setGroup(code.lower()); + return d->languages->readEntry("Name"); +} + +QStringList KLocale::allCountriesTwoAlpha() const +{ + QStringList countries; + + qDebug("KLocale::allCountriesTwoAlpha has to be fixed."); +//US QStringList paths = KGlobal::dirs()->findAllResources("locale", "l10n/*/entry.desktop"); + QStringList paths = KGlobal::dirs()->findAllResources("locale", "l10n/*/entry.desktop", true, true); + + for(QStringList::ConstIterator it = paths.begin(); + it != paths.end(); ++it) + { + QString code = (*it).mid((*it).length()-16, 2); + if (code != "/C") + countries.append(code); + } + return countries; +} + +QString KLocale::twoAlphaToCountryName(const QString &code) const +{ +//US KConfig cfg("l10n/"+code.lower()+"/entry.desktop", true, false, "locale"); + KConfig cfg(locateLocal("locale", "l10n/"+code.lower()+"/entry.desktop")); + cfg.setGroup("KCM Locale"); + return cfg.readEntry("Name"); +} + +void KLocale::setCalendar(const QString & calType) +{ + doFormatInit(); + + d->calendarType = calType; + + delete d->calendar; + d->calendar = 0; +} + +QString KLocale::calendarType() const +{ + doFormatInit(); + + return d->calendarType; +} + +const KCalendarSystem * KLocale::calendar() const +{ + doFormatInit(); + + // Check if it's the correct calendar?!? +//US we are always using the gregorian calendar +//US if ( !d->calendar ) +//US d->calendar = KCalendarSystemFactory::create( d->calendarType, this ); + if ( !d->calendar ) + d->calendar = new KCalendarSystemGregorian; + + return d->calendar; +} + +KLocale::KLocale(const KLocale & rhs) +{ + d = new KLocalePrivate; + + *this = rhs; +} + +KLocale & KLocale::operator=(const KLocale & rhs) +{ + // Numbers and money + m_decimalSymbol = rhs.m_decimalSymbol; + m_thousandsSeparator = rhs.m_thousandsSeparator; + m_currencySymbol = rhs.m_currencySymbol; + m_monetaryDecimalSymbol = rhs.m_monetaryDecimalSymbol; + m_monetaryThousandsSeparator = rhs.m_monetaryThousandsSeparator; + m_positiveSign = rhs.m_positiveSign; + m_negativeSign = rhs.m_negativeSign; + m_fracDigits = rhs.m_fracDigits; + m_positivePrefixCurrencySymbol = rhs.m_positivePrefixCurrencySymbol; + m_negativePrefixCurrencySymbol = rhs.m_negativePrefixCurrencySymbol; + m_positiveMonetarySignPosition = rhs.m_positiveMonetarySignPosition; + m_negativeMonetarySignPosition = rhs.m_negativeMonetarySignPosition; + + // Date and time + m_timeFormat = rhs.m_timeFormat; + m_dateFormat = rhs.m_dateFormat; + m_dateFormatShort = rhs.m_dateFormatShort; + + m_language = rhs.m_language; + m_country = rhs.m_country; + + // the assignment operator works here + *d = *rhs.d; + d->languages = 0; // Don't copy languages + d->calendar = 0; // Don't copy the calendar + + return *this; +} + +bool KLocale::setCharset(const QString & ) { return true; } +QString KLocale::charset() const { return QString::fromLatin1("UTF-8"); } + + +int KLocale::timezoneOffset( QString timeZone ) +{ + int ret = 1001; + int index = mTimeZoneList.findIndex( timeZone ); + if ( index < 24 ) + ret = ( index-11 ) * 60 ; + return ret; +} + +QStringList KLocale::timeZoneList() const +{ + return mTimeZoneList; +} +void KLocale::setTimezone( const QString &timeZone ) +{ + mTimeZoneOffset = timezoneOffset( timeZone ); +} + +void KLocale::setDaylightSaving( bool b, int start , int end ) +{ + daylightEnabled = b; + daylightStart = start; + daylightEnd = end; + mSouthDaylight = (end < start); + // qDebug("klocale daylight %d %d %d ", b, start , end ); +} + +int KLocale::localTimeOffset( const QDateTime &dt ) +{ + bool addDaylight = false; + if ( daylightEnabled ) { + int d_end, d_start; + int dayofyear = dt.date().dayOfYear(); + int year = dt.date().year(); + int add = 0; + if ( QDate::leapYear(year) ) + add = 1; + QDate date ( year,1,1 ); + if ( daylightEnd > 59 ) + d_end = daylightEnd +add; + else + d_end = daylightEnd; + if ( daylightStart > 59 ) + d_start = daylightStart +add; + else + d_start = daylightStart; + QDate s_date = date.addDays( d_start -1 ); + QDate e_date = date.addDays( d_end -1 ); + int dof = s_date.dayOfWeek(); + if ( dof < 7 ) + s_date = s_date.addDays( -dof ); + dof = e_date.dayOfWeek(); + if ( dof < 7 ) + e_date = e_date.addDays( -dof ); + QTime startTime ( 3,0,0 ); + QDateTime startDt( s_date, startTime ); + QDateTime endDt( e_date, startTime ); + //qDebug("dayligt saving start %s end %s ",startDt.toString().latin1(),endDt.toString().latin1( )); + if ( mSouthDaylight ) { + if ( ! ( endDt < dt && dt < startDt) ) + addDaylight = true; + } else { + if ( startDt < dt && dt < endDt ) + addDaylight = true; + + + } + } + int addMin = 0; + if ( addDaylight ) + addMin = 60; + return mTimeZoneOffset + addMin; +} + +void KLocale::setHore24Format ( bool b ) +{ + mHourF24Format = b; +} +void KLocale::setWeekStartMonday( bool b ) +{ + mWeekStartsMonday = b; +} +void KLocale::setIntDateFormat( int i ) +{ + mIntDateFormat = i; +} +void KLocale::setLanguage( int i ) +{ + mLanguage = i; +} + + + diff --git a/microkde/kdecore/klocale_new.h b/microkde/kdecore/klocale_new.h new file mode 100644 index 0000000..777c0bd --- a/dev/null +++ b/microkde/kdecore/klocale_new.h @@ -0,0 +1,1224 @@ +#ifndef MINIKDE_KLOCALE_H +#define MINIKDE_KLOCALE_H + +#include +#include +#include + +class QStringList; +class QTextCodec; +class QDate; +class QTime; +class QDateTime; + +class KGlobal; +class KConfig; +class KConfigBase; +class KLocalePrivate; +class KCatalogue; +class KCalendarSystem; + +#ifndef I18N_NOOP +#define I18N_NOOP(x) (x) +#endif + +void setLocaleDict( QDict * dict ); + +/** + * i18n is the function that does everything you need to translate + * a string. You just wrap around every user visible string a i18n + * call to get a QString with the string in the user's preferred + * language. + * + * The argument must be an UTF-8 encoded string (If you only use + * characters that are in US-ASCII, you're on the safe side. But + * for e.g. german umlauts or french accents should be recoded to + * UTF-8) + **/ +QString i18n(const char *text); + +/** + * If the string is too ambiguous to be translated well to a non-english + * language, use this form of i18n to separate lookup string and english + * text. + * @see translate + **/ +QString i18n(const char *index, const char *text); + +/** + * If you want to handle plural forms, use this form of i18n. + * The plural has to contain a %n where n fits into. + * @see translate + **/ +QString i18n(const char *singular, const char *plural, unsigned long n); + +/** + * Qt3's uic generates i18n( "msg", "comment" ) calls which conflict + * with our i18n method. We use uic -tr tr2i18n to redirect + * to the right i18n() function +**/ +inline QString tr2i18n(const char* message, const char* =0) { + return i18n(message); +} + +/** + * + * KLocale provides support for country specific stuff like + * the national language. + * + * KLocale supports translating, as well as specifying the format + * for numbers, currency, time, and date. + * + * @author Stephan Kulow , Preston Brown , + * Hans Petter Bieker , Lukas Tinkl + * @short class for supporting locale settings and national language + */ +class KLocale +{ + friend class KGlobal; // for initInstance() +public: + /** + * Constructs a KLocale with the given catalogue name. + * The constructor looks for an entry Locale/Language in the + * configuration file. + * If no config file is specified, it will also look for languages + * using the environment variables (KDE_LANG, LC_MESSAGES, LC_ALL, LANG), + * as well as the global configuration fie. If we were not able to use + * non of the specified languages, the default language (en_US) will be + * used. + * + * If you specify a configuration file, it has to be valid until + * the KLocale object is destroyed. + * + * @param catalogue The name of the main language file + * @param config The configuration file to use. + */ + KLocale( const QString& catalogue, KConfig *config = 0 ); + + /** + * Copy constructor. + */ + KLocale( const KLocale & rhs ); + + /** + * Assignment operator. + */ + KLocale& operator= ( const KLocale & rhs ); + + /** + * Destructor. + */ + ~KLocale(); + + /** + * Translates the string into the corresponding string in + * the national language, if available. If not, returns + * the string itself. + * There is a KDE wide message file that contains the most + * often used phrases, so we can avoid duplicating the + * translation of these phrases. If a phrase is not found + * in the catalogue given to the constructor, it will search + * in the system catalog. This makes it possible to override + * some phrases for your needs. + * + * The argument must be an UTF-8 encoded string (If you only use + * characters that are in US-ASCII you're on the safe side. But + * for e.g. german umlauts or french accents should be recoded to + * UTF-8) + * + * @param index The lookup text and default text, if not found. + */ + QString translate( const char *index ) const; + + /** + * Translates the string into the corresponding string in the + * national language, if available. + * + * The real contents of the string is in the argument fallback, + * but the meaning of it is coded into the argument index. + * In some cases you'll need this function, when english is + * too ambiguous to express it. + * + * Most of the times the translators will tell you if it can't + * be translated as it, but think of cases as "New", where the + * translations differs depending on what is New. + * Or simple cases as "Open", that can be used to express something + * is open or it can be used to express that you want something to + * open... There are tons of such examples. + * + * If translate("Open") is not enough to translate it well, use + * translate("To Open", "Open") or translate("Is Open", "Open"). + * The english user will see "Open" in both cases, but the translated + * version may vary. Of course you can also use i18n() + * + * @param index The lookup text + * @param fallback the default text, if not found + * @return translation + */ + QString translate( const char *index, const char *fallback) const; + + /** + * Used to get the correct, translated singular or plural of a + * word. + * @param singular the singular form of the word, for example "file". + * @param plural the plural form of the word. Must contain a "%n" that will + * be replaced by the number @n, for example "%n files" + * @param n the number + * @return the correct singular or plural for the selected language, + * depending on n + */ + QString translate( const char *singular, const char *plural, + unsigned long n) const; + + /** + * Changes the current encoding. + * + * @param mibEnum The mib of the preferred codec + * + * @return True on success. + */ + bool setEncoding(int mibEnum); + + /** + * Changes the current language. The current language will be left + * unchanged if failed. It will force a reload of the country specific + * configuration as well. + * + * @param language The language code. + * + * @return True on success. + */ + bool setLanguage(const QString & language); + + /** + * Changes the list of prefed languages for the locale. The first valid + * language in the list will be used, or the default (en_US) language + * will be used if non of the specified languages were available. + * + * @param languages The list of language codes. + * + * @return True if one of the specified languages were used. + */ + bool setLanguage(const QStringList & languages); + + /** + * Changes the current country. The current country will be left + * unchanged if failed. It will force a reload of the country specific + * configuration. + * + * @param country The ISO 3166 country code. + * + * @return True on success. + */ + bool setCountry(const QString & country); + + /** + * Various positions for where to place the positive or negative + * sign when they are related to a monetary value. + */ + enum SignPosition { ParensAround = 0, BeforeQuantityMoney = 1, + AfterQuantityMoney = 2, + BeforeMoney = 3, AfterMoney = 4 }; + + /** + * Returns what a decimal point should look like ("." or "," etc.) + * according to the current locale or user settings. + * + * @return The decimal symbol used by locale. + */ + QString decimalSymbol() const; + + /** + * Returns what the thousands separator should look + * like ("," or "." etc.) + * according to the current locale or user settings. + * + * @return The thousands separator used by locale. + */ + QString thousandsSeparator() const; + + /** + * Returns what the symbol denoting currency in the current locale + * as as defined by user settings should look like. + * + * @return The default currency symbol used by locale. + */ + QString currencySymbol() const; + + /** + * Returns what a decimal point should look like ("." or "," etc.) + * for monetary values, according to the current locale or user + * settings. + * + * @return The monetary decimal symbol used by locale. + */ + QString monetaryDecimalSymbol() const; + + /** + * Returns what a thousands separator for monetary values should + * look like ("," or " " etc.) according to the current locale or + * user settings. + * + * @return The monetary thousands separator used by locale. + */ + QString monetaryThousandsSeparator() const; + + /** + * Returns what a positive sign should look like ("+", " ", etc.) + * according to the current locale or user settings. + * + * @return The positive sign used by locale. + */ + QString positiveSign() const; + + /** + * Returns what a negative sign should look like ("-", etc.) + * according to the current locale or user settings. + * + * @return The negative sign used by locale. + */ + QString negativeSign() const; + + /** + * The number of fractional digits to include in numeric/monetary + * values (usually 2). + * + * @return Default number of fractional digits used by locale. + */ + int fracDigits() const; + + /** + * If and only if the currency symbol precedes a positive value, + * this will be true. + * + * @return Where to print the currency symbol for positive numbers. + */ + bool positivePrefixCurrencySymbol() const; + + /** + * If and only if the currency symbol precedes a negative value, + * this will be true. + * + * @return True if the currency symbol precedes negative numbers. + */ + bool negativePrefixCurrencySymbol() const; + + /** + * Returns the position of a positive sign in relation to a + * monetary value. + * + * @return Where/how to print the positive sign. + * @see SignPosition + */ + SignPosition positiveMonetarySignPosition() const; + + /** + * Denotes where to place a negative sign in relation to a + * monetary value. + * + * @return Where/how to print the negative sign. + * @see SignPosition + */ + SignPosition negativeMonetarySignPosition() const; + + /** + * Given a double, converts that to a numeric string containing + * the localized monetary equivalent. + * + * e.g. given 123456, return "$ 123,456.00". + * + * @param num The number we want to format + * @param currency The currency symbol you want. + * @param digits Number of fractional digits, or -1 for the default + * value + * + * @return The number of money as a localized string + * @see fracDigits() + */ + QString formatMoney(double num, + const QString & currency = QString::null, + int digits = -1) const; + + /** + * Given a double, converts that to a numeric string containing + * the localized numeric equivalent. + * + * e.g. given 123456.78F, return "123,456.78" (for some European country). + * If precision isn't specified, 2 is used. + * + * @param num The number to convert + * @param precision Number of fractional digits used. + * + * @return The number as a localized string + */ + QString formatNumber(double num, int precision = -1) const; + + /** + * Given an integer, converts that to a numeric string containing + * the localized numeric equivalent. + * + * e.g. given 123456L, return "123,456" (for some European country). + * + * @param num The number to convert + * + * @return The number as a localized string + * @since 3.2 + */ + QString formatLong(long num) const; + + /** + * Use this to determine whether nouns are declined in + * locale's language. This property should remain + * read-only (no setter function) + * + * @return If nouns are declined + * @since 3.1 + */ + bool nounDeclension() const; + + /** + * Returns a string formatted to the current locale's conventions + * regarding dates. + * + * @param pDate The date to be formated. + * @param shortFormat True for non text dates. + * + * @return The date as a string + */ + QString formatDate(const QDate &pDate, bool shortFormat = false) const; + + /** + * Use this to determine whether in dates a possessive form of month + * name is preferred ("of January" rather than "January") + * + * @return If possessive form should be used + * @since 3.1 + */ + bool dateMonthNamePossessive() const; + + /** + * Returns a string formatted to the current locale's conventions + * regarding times. + * + * @param pTime The time to be formated. + * @param includeSecs if true, seconds are included in the output, + * otherwise only hours and minutes are formatted. + * + * @return The time as a string + */ + QString formatTime(const QTime &pTime, bool includeSecs = false) const; + + /** + * Use this to determine if the user wants a 12 hour clock. + * + * @return If the user wants 12h clock + */ + bool use12Clock() const; + + /** + * @deprecated + * + * Please use the @ref weekStartDay method instead. + * + * Use this to determine if the user wants the week to start on Monday. + * + * @return true if the week starts on Monday + */ + bool weekStartsMonday() const; //### remove for KDE 4.0 + + /** + * Use this to determine which day is the first day of the week. + * + * @return an integer (Monday=1..Sunday=7) + * @since 3.1 + */ + int weekStartDay() const; + + /** + * @deprecated + * + * Returns a string containing the name of the month name used in the Gregorian calendar. + * + * @param i the month number of the year starting at 1/January. + * @param shortName we will return the short version of the string. + * + * @return The name of the month + */ + QString monthName(int i, bool shortName = false) const; + + /** + * @deprecated + * + * Returns a string containing the possessive form of the month name used in the Gregorian calendar. + * ("of January", "of February", etc.) + * It's needed in long format dates in some languages. + * + * @param i the month number of the year starting at 1/January. + * @param shortName we will return the short version of the string. + * + * @return The possessive form of the name of the month + * @since 3.1 + */ + QString monthNamePossessive(int i, bool shortName = false) const; + + /** + * @deprecated + * + * Returns a string containing the name of the week day used in the Gregorian calendar. + * + * @param i the day number of the week starting at 1/Monday. + * @param shortName we will return the short version of the string. + * + * @return The name of the day + */ + QString weekDayName(int i, bool shortName = false) const; + + /** + * Returns a pointer to the calendar system object. + * + * @return the current calendar system instance + * @since 3.2 + */ + const KCalendarSystem * calendar() const; + + /** + * Returns the name of the calendar system that is currently being + * used by the system. + * + * @return the name of the calendar system + * @since 3.2 + */ + QString calendarType() const; + + /** + * Changes the current calendar system to the calendar specified. + * Currently is "gregorian" and "hijri" supported. If the calendar + * system specified is not found, gregorian will be used. + * + * @param calendarType the name of the calendar type + * @since 3.2 + */ + void setCalendar(const QString & calendarType); + + /** + * Returns a string formated to the current locale's conventions + * regarding both date and time. + * + * @param pDateTime The date and time to be formated. + * @param shortFormat using the short date format. + * @param includeSecs using the short date format. + * + * @return The date and time as a string + */ + QString formatDateTime(const QDateTime &pDateTime, + bool shortFormat = true, + bool includeSecs = false) const; + + /** + * Converts a localized monetary string to a double. + * + * @param numStr the string we want to convert. + * @param ok the boolean that is set to false if it's not a number. + * If @p ok is 0, it will be ignored + * + * @return The string converted to a double + */ + double readMoney(const QString &numStr, bool * ok = 0) const; + + /** + * Converts a localized numeric string to a double. + * + * @param numStr the string we want to convert. + * @param ok the boolean that is set to false if it's not a number. + * If @p ok is 0, it will be ignored + * + * @return The string converted to a double + */ + double readNumber(const QString &numStr, bool * ok = 0) const; + + /** + * Converts a localized date string to a QDate. + * The bool pointed by ok will be invalid if the date entered was not valid. + * + * @param str the string we want to convert. + * @param ok the boolean that is set to false if it's not a valid date. + * If @p ok is 0, it will be ignored + * + * @return The string converted to a QDate + */ + QDate readDate(const QString &str, bool* ok = 0) const; + + /** + * Converts a localized date string to a QDate, using the specified format. + * You will usually not want to use this method. + */ + QDate readDate( const QString &intstr, const QString &fmt, bool* ok = 0) const; + + enum ReadDateFlags { + NormalFormat = 1, + ShortFormat = 2 + }; + + /** + * Converts a localized date string to a QDate. + * This method is stricter than readDate(str,&ok): it will either accept + * a date in full format or a date in short format, depending on @p flags. + * + * @param str the string we want to convert. + * @param flags whether the date string is to be in full format or in short format. + * @param ok the boolean that is set to false if it's not a valid date. + * If @p ok is 0, it will be ignored + * + * @return The string converted to a QDate + * @since 3.2 + */ + QDate readDate(const QString &str, ReadDateFlags flags, bool *ok = 0) const; + + /** + * Converts a localized time string to a QTime. + * This method will try to parse it with seconds, then without seconds. + * The bool pointed by ok will be false if the time entered was not valid. + * + * @param str the string we want to convert. + * @param ok the boolean that is set to false if it's not a valid time. + * If @p ok is 0, it will be ignored + * + * @return The string converted to a QTime + */ + QTime readTime(const QString &str, bool* ok = 0) const; + + enum ReadTimeFlags { + WithSeconds = 0, // default (no flag set) + WithoutSeconds = 1 + }; // (maybe use this enum as a bitfield, if adding independent features?) + /** + * Converts a localized time string to a QTime. + * This method is stricter than readTime(str,&ok): it will either accept + * a time with seconds or a time without seconds. + * Use this method when the format is known by the application. + * + * @param str the string we want to convert. + * @param flags whether the time string is expected to contain seconds or not. + * @param ok the boolean that is set to false if it's not a valid time. + * If @p ok is 0, it will be ignored + * + * @return The string converted to a QTime + * @since 3.2 + */ + QTime readTime(const QString &str, ReadTimeFlags flags, bool *ok = 0) const; + + /** + * Returns the language used by this object. The domain AND the + * library translation must be available in this language. + * @ref defaultLanguage() is returned by default, if no other available. + * + * @return The currently used language. + */ + QString language() const; + + /** + * Returns the country code of the country where the user lives. + * @ref defaultCountry() is returned by default, if no other available. + * + * @return The country code for the user. + */ + QString country() const; + + /** + * Returns the preferred languages as ISO 639-1 codes. This means + * that information about country is removed. If the internal language + * code might be represented by more than one 639-1 code, they will all be + * listed (but only once). + * + * If the selected languages are "nn, nb, pt_BR", you will get: + * "nn, no, nb, pt". + * + * @return List of language codes + * + * @see languageList + */ + QStringList languagesTwoAlpha() const; + + /** + * Returns the languages selected by user. The codes returned here is the + * internal language codes. + * + * @return List of language codes + * + * @see languagesTwoAlpha + */ + QStringList languageList() const; + + /** + * Returns the user's preferred encoding. + * + * @return The name of the preferred encoding + * + * @see codecForEncoding + * @see encodingMib + */ + const char * encoding() const; + + /** + * Returns the user's preferred encoding. + * + * @return The Mib of the preferred encoding + * + * @see encoding + * @see codecForEncoding + */ + int encodingMib() const; + /** + * Returns the user's preferred encoding. Should never be NULL. + * + * @return The codec for the preferred encoding + * + * @see encoding + * @see encodingMib + */ + QTextCodec * codecForEncoding() const; + + /** + * Returns the file encoding. + * + * @return The Mib of the file encoding + * + * @see QFile::encodeName + * @see QFile::decodeName + */ + int fileEncodingMib() const; + + /** + * Changes the current date format. + * + * The format of the date is a string which contains variables that will + * be replaced: + * @li %Y with the century (e.g. "19" for "1984") + * @li %y with the lower 2 digits of the year (e.g. "84" for "1984") + * @li %n with the month (January="1", December="12") + * @li %m with the month with two digits (January="01", December="12") + * @li %e with the day of the month (e.g. "1" on the first of march) + * @li %d with the day of the month with two digits(e.g. "01" on the first of march) + * @li %b with the short form of the month (e.g. "Jan" for January) + * @li %a with the short form of the weekday (e.g. "Wed" for Wednesday) + * @li %A with the long form of the weekday (e.g. "Wednesday" for Wednesday) + * Everything else in the format string will be taken as is. + * For example, March 20th 1989 with the format "%y:%m:%d" results + * in "89:03:20". + * + * @param format The new date format + */ + void setDateFormat(const QString & format); + /** + * Changes the current short date format. + * + * The format of the date is a string which contains variables that will + * be replaced: + * @li %Y with the century (e.g. "19" for "1984") + * @li %y with the lower 2 digits of the year (e.g. "84" for "1984") + * @li %n with the month (January="1", December="12") + * @li %m with the month with two digits (January="01", December="12") + * @li %e with the day of the month (e.g. "1" on the first of march) + * @li %d with the day of the month with two digits(e.g. "01" on the first of march) + * @li %b with the short form of the month (e.g. "Jan" for January) + * @li %a with the short form of the weekday (e.g. "Wed" for Wednesday) + * @li %A with the long form of the weekday (e.g. "Wednesday" for Wednesday) + * Everything else in the format string will be taken as is. + * For example, March 20th 1989 with the format "%y:%m:%d" results + * in "89:03:20". + * + * @param format The new short date format + */ + void setDateFormatShort(const QString & format); + /** + * Changes the form of month name used in dates. + * + * @param possessive True if possessive forms should be used + * @since 3.1 + */ + void setDateMonthNamePossessive(bool possessive); + /** + * Changes the current time format. + * + * The format of the time is string a which contains variables that will + * be replaced: + * @li %H with the hour in 24h format and 2 digits (e.g. 5pm is "17", 5am is "05") + * @li %k with the hour in 24h format and one digits (e.g. 5pm is "17", 5am is "5") + * @li %I with the hour in 12h format and 2 digits (e.g. 5pm is "05", 5am is "05") + * @li %l with the hour in 12h format and one digits (e.g. 5pm is "5", 5am is "5") + * @li %M with the minute with 2 digits (e.g. the minute of 07:02:09 is "02") + * @li %S with the seconds with 2 digits (e.g. the minute of 07:02:09 is "09") + * @li %p with pm or am (e.g. 17.00 is "pm", 05.00 is "am") + * Everything else in the format string will be taken as is. + * For example, 5.23pm with the format "%H:%M" results + * in "17:23". + * + * @param format The new time format + */ + void setTimeFormat(const QString & format); + + /** + * @deprecated + * + * Please use @ref setWeekStartDay instead. + * + * Changes how KLocale defines the first day in week. + * + * @param start True if Monday is the first day in the week + */ + void setWeekStartsMonday(bool start); //### remove for KDE 4.0 + + /** + * Changes how KLocale defines the first day in week. + * + * @param day first day of the week (Monday=1..Sunday=7) as integer + * @since 3.1 + */ + void setWeekStartDay(int day); + /** + * Returns the currently selected date format. + * + * @return Current date format. + * @see setDateFormat() + */ + QString dateFormat() const; + /** + * Returns the currently selected short date format. + * + * @return Current short date format. + * @see setDateFormatShort() + */ + QString dateFormatShort() const; + /** + * Returns the currently selected time format. + * + * @return Current time format. + * @see setTimeFormat() + */ + QString timeFormat() const; + + /** + * Changes the symbol used to identify the decimal pointer. + * + * @param symbol The new decimal symbol. + */ + void setDecimalSymbol(const QString & symbol); + /** + * Changes the separator used to group digits when formating numbers. + * + * @param separator The new thousands separator. + */ + void setThousandsSeparator(const QString & separator); + /** + * Changes the sign used to identify a positive number. Normally this is + * left blank. + * + * @param sign Sign used for positive numbers. + */ + void setPositiveSign(const QString & sign); + /** + * Changes the sign used to identify a negative number. + * + * @param sign Sign used for negative numbers. + */ + void setNegativeSign(const QString & sign); + /** + * Changes the sign position used for positive monetary values. + * + * @param signpos The new sign position + */ + void setPositiveMonetarySignPosition(SignPosition signpos); + /** + * Changes the sign position used for negative monetary values. + * + * @param signpos The new sign position + */ + void setNegativeMonetarySignPosition(SignPosition signpos); + /** + * Changes the position where the currency symbol should be printed for + * positive monetary values. + * + * @param prefix True if the currency symbol should be prefixed instead of + * postfixed + */ + void setPositivePrefixCurrencySymbol(bool prefix); + /** + * Changes the position where the currency symbol should be printed for + * negative monetary values. + * + * @param prefix True if the currency symbol should be prefixed instead of + * postfixed + */ + void setNegativePrefixCurrencySymbol(bool prefix); + /** + * Changes the number of digits used when formating numbers. + * + * @param digits The default number of digits to use. + */ + void setFracDigits(int digits); + /** + * Changes the separator used to group digits when formating monetary values. + * + * @param separator The new thousands separator. + */ + void setMonetaryThousandsSeparator(const QString & separator); + /** + * Changes the symbol used to identify the decimal pointer for monetary + * values. + * + * @param symbol The new decimal symbol. + */ + void setMonetaryDecimalSymbol(const QString & symbol); + /** + * Changes the current currency symbol. + * + * @param symbol The new currency symbol + */ + void setCurrencySymbol(const QString & symbol); + + /** + * Returns the preferred page size for printing. + * + * @return The preferred page size, cast it to QPrinter::PageSize + */ + int pageSize() const; + + /** + * Changes the preferred page size when printing. + * + * @param paperFormat the new preferred page size in the format QPrinter::PageSize + */ + void setPageSize(int paperFormat); + + /** + * The Metric system will give you information in mm, while the + * Imperial system will give you information in inches. + */ + enum MeasureSystem { Metric, Imperial }; + + /** + * Returns which measuring system we use. + * + * @return The preferred measuring system + */ + MeasureSystem measureSystem() const; + + /** + * Changes the preferred measuring system. + * + * @return value The preferred measuring system + */ + void setMeasureSystem(MeasureSystem value); + + /** + * Adds another catalogue to search for translation lookup. + * This function is useful for extern libraries and/or code, + * that provides its own messages. + * + * If the catalogue does not exist for the chosen language, + * it will be ignored and en_US will be used. + * + * @param catalogue The catalogue to add. + */ + void insertCatalogue(const QString& catalogue); + + /** + * Removes a catalog for translation lookup. + * @param catalogue The catalogue to remove. + * @see insertCatalogue() + */ + void removeCatalogue(const QString &catalogue); + + /** + * Sets the active catalog for translation lookup. + * @param catalogue The catalogue to activate. + */ + void setActiveCatalogue(const QString &catalogue); + + /** + * Translates a message as a QTranslator is supposed to. + * The parameters are similar to i18n(), but the result + * value has other semantics (it can be QString::null) + * @since 3.1 + **/ + QString translateQt(const char *context, + const char *sourceText, + const char *message) const; + + /** + * Returns list of all known ISO 639-1 codes. + * @return a list of all language codes + * @since 3.1 + */ + QStringList allLanguagesTwoAlpha() const; + + /** + * Convert a ISO 639-1 code to a human readable form. + * @param code the language ISO 639-1 code + * @return the human readable form + * @since 3.1 + */ + QString twoAlphaToLanguageName(const QString &code) const; + + /** + * Returns list of all known country codes. + * @return a list of all country codes + * @since 3.1 + */ + QStringList allCountriesTwoAlpha() const; + + /** + * Convert a country code to a human readable form. + * @param code the country code + * @return the human readable form of the country name + * @since 3.1 + */ + QString twoAlphaToCountryName(const QString &code) const; + + + + int timezoneOffset( QString ); + QStringList timeZoneList() const; + void setDaylightSaving( bool, int , int ); + int localTimeOffset(const QDateTime &); + void setTimezone( const QString &timeZone ); + + void setHore24Format ( bool ); + void setWeekStartMonday( bool ); + void setIntDateFormat( int ); + void setLanguage( int ); + + + + /** + * Returns the parts of the parameter str understood as language setting + * the format is language_COUNTRY.charset + * + * @param str The string to split. + * @param language This will be set to the language part of the string. + * @param country This will be set to the country part of the string. + * @param charset This will be set to the charset part of the string. + */ + static void splitLocale(const QString & str, + QString & language, + QString & country, + QString & charset); + + /** + * Use this to as main catalogue for *all* KLocales, if not the appname + * will be used. This function is best to be the very first instruction + * in your program's main function as it only has an effect before the + * first KLocale object is created (and this is in common KDE applications + * quite early). + * + * @param catalogue Catalogue to override all other main catalogues. + */ + static void setMainCatalogue(const char *catalogue); + + /** + * Finds localized resource in resourceDir( rtype ) + \ + fname. + * + * @param fname relative path to find + * @param rtype resource type to use + */ + static QString langLookup(const QString &fname, const char *rtype = "html"); + + /** + * Returns the name of the internal language. + * + * @return Name of the default language + */ + static QString defaultLanguage(); + + /** + * Returns the name of the default country. + * + * @return Name of the default country + */ + static QString defaultCountry(); + + + /** + * @internal Called from KConfigBackend to initialize language. + */ + static QString _initLanguage(KConfigBase *config); + +#ifdef KDE_NO_COMPAT +private: +#endif + /** + * @deprecated + * use formatMoney(double) + */ + QString formatMoney(const QString &numStr) const; + + /** + * @deprecated + * use formatNumber(double) + */ + QString formatNumber(const QString &numStr) const; + + /** + * @deprecated + * Use languageList() + * + * @return String containing language codes separated by colons + */ + QString languages() const; + + /** + * @deprecated + * @return True + */ + bool setCharset(const QString & charset); + + /** + * @deprecated + * @see encoding + */ + QString charset() const; + +protected: + /** + * @internal Creates a KLocale object for KGlobal and inits the locale + * pointer. + */ + static void initInstance(); + +private: + /** + * @internal Inits the localization part of the instance with the config + * object. + * + * @param config The configuration object used for init. + */ + void initFormat(KConfig *config); + + /** + * @internal Inits the language part of the instance with the given config + * object. It should be valid and contain the global entries. + * + * @param config The configuration object used for init + * @param useEnv True if we should use environment variables + */ + void initLanguage(KConfig * config, bool useEnv); + + /** + * @internal Figures out which encoding the user prefers. + * + * @param config The configuration object used for init + */ + void initEncoding(KConfig * config); + + /** + * @internal Figures out which catalogues to use. + * + * @param catalogue The name of the main catalogue + */ + void initCatalogue(const QString & catalogue); + + /** + * @internal Figures out which encoding the user prefers for filenames + * and sets up the appropriate QFile encoding and decoding functions. + */ + void initFileNameEncoding(KConfig *config); + + /** + * @internal A QFile filename encoding function (QFile::encodeFn). + */ + static QCString encodeFileNameUTF8( const QString & fileName ); + + /** + * @internal QFile filename decoding function (QFile::decodeFn). + */ + static QString decodeFileNameUTF8( const QCString & localFileName ); + + /** + * @internal Changes the file name of the catalogue to the correct + * one. + */ + void initCatalogue( KCatalogue & catalogue ); + + /** + * @internal Reads the language and format configuration form disk. + */ + void doBindInit(); + + /** + * @internal Ensures that the format configuration is read. + */ + void doFormatInit() const; + + /** + * @internal Reads the format configuration from disk. + */ + void initFormat(); + + /** + * @internal function used by the two translate versions + */ + QString translate_priv(const char *index, + const char *text, + const char ** original = 0) const; + + /** + * @internal function used to determine if we are using the en_US translation + */ + bool useDefaultLanguage() const; + + /** + * @internal Checks if the specified language is installed + */ + bool isLanguageInstalled(const QString & language) const; + + /** + * @internal Retrieves the file name of the catalogue, or QString::null + * if not found. + */ + static QString catalogueFileName(const QString & language, + const KCatalogue & catalogue); + + +private: + // Numbers and money + QString m_decimalSymbol; + QString m_thousandsSeparator; + QString m_currencySymbol; + QString m_monetaryDecimalSymbol; + QString m_monetaryThousandsSeparator; + QString m_positiveSign; + QString m_negativeSign; + int m_fracDigits; + SignPosition m_positiveMonetarySignPosition; + SignPosition m_negativeMonetarySignPosition; + + // Date and time + QString m_timeFormat; + QString m_dateFormat; + QString m_dateFormatShort; + + QString m_language; + QString m_country; + + QStringList mTimeZoneList; + bool daylightEnabled; + int mDaylightTZoffset; + int mNondaylightTZoffset; + bool mSouthDaylight; + int daylightStart, daylightEnd, mTimeZoneOffset; + bool mWeekStartsMonday; + bool mHourF24Format; + int mIntDateFormat; + int mLanguage; + + + + + bool m_weekStartsMonday; //### remove for KDE 4.0 + bool m_positivePrefixCurrencySymbol; + bool m_negativePrefixCurrencySymbol; + + KLocalePrivate *d; +}; + +#endif diff --git a/microkde/kdecore/kmdcodec.cpp b/microkde/kdecore/kmdcodec.cpp new file mode 100644 index 0000000..bc03569 --- a/dev/null +++ b/microkde/kdecore/kmdcodec.cpp @@ -0,0 +1,1127 @@ +/* + Copyright (C) 2000-2001 Dawit Alemayehu + Copyright (C) 2001 Rik Hemsley (rikkus) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License (LGPL) + version 2 as published by the Free Software Foundation. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + RFC 1321 "MD5 Message-Digest Algorithm" Copyright (C) 1991-1992. + RSA Data Security, Inc. Created 1991. All rights reserved. + + The KMD5 class is based on a C++ implementation of + "RSA Data Security, Inc. MD5 Message-Digest Algorithm" by + Mordechai T. Abzug, Copyright (c) 1995. This implementation + passes the test-suite as defined in RFC 1321. + + The encoding and decoding utilities in KCodecs with the exception of + quoted-printable are based on the java implementation in HTTPClient + package by Ronald Tschal� Copyright (C) 1996-1999. + + The quoted-printable codec as described in RFC 2045, section 6.7. is by + Rik Hemsley (C) 2001. +*/ + +//US #include + +#include +#include +#include + +#include +#include "kmdcodec.h" + +#define KMD5_S11 7 +#define KMD5_S12 12 +#define KMD5_S13 17 +#define KMD5_S14 22 +#define KMD5_S21 5 +#define KMD5_S22 9 +#define KMD5_S23 14 +#define KMD5_S24 20 +#define KMD5_S31 4 +#define KMD5_S32 11 +#define KMD5_S33 16 +#define KMD5_S34 23 +#define KMD5_S41 6 +#define KMD5_S42 10 +#define KMD5_S43 15 +#define KMD5_S44 21 + +const char KCodecs::Base64EncMap[64] = +{ + 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, + 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, + 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, + 0x59, 0x5A, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, + 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, + 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, + 0x77, 0x78, 0x79, 0x7A, 0x30, 0x31, 0x32, 0x33, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2B, 0x2F +}; + +const char KCodecs::Base64DecMap[128] = +{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x3F, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, + 0x3C, 0x3D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, + 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, + 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, + 0x17, 0x18, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, + 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, + 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, + 0x31, 0x32, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +const char KCodecs::UUEncMap[64] = +{ + 0x60, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, + 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F +}; + +const char KCodecs::UUDecMap[128] = +{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +const char KCodecs::hexChars[16] = +{ + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' +}; + +const unsigned int KCodecs::maxQPLineLength = 70; + + +/******************************** KCodecs ********************************/ +// strchr(3) for broken systems. +static int rikFindChar(register const char * _s, const char c) +{ + register const char * s = _s; + + while (true) + { + if ((0 == *s) || (c == *s)) break; ++s; + if ((0 == *s) || (c == *s)) break; ++s; + if ((0 == *s) || (c == *s)) break; ++s; + if ((0 == *s) || (c == *s)) break; ++s; + } + + return s - _s; +} + +QCString KCodecs::quotedPrintableEncode(const QByteArray& in, bool useCRLF) +{ + QByteArray out; + quotedPrintableEncode (in, out, useCRLF); + return QCString (out.data(), out.size()+1); +} + +QCString KCodecs::quotedPrintableEncode(const QCString& str, bool useCRLF) +{ + if (str.isEmpty()) + return ""; + + QByteArray in (str.length()); + memcpy (in.data(), str.data(), str.length()); + return quotedPrintableEncode(in, useCRLF); +} + +void KCodecs::quotedPrintableEncode(const QByteArray& in, QByteArray& out, bool useCRLF) +{ + out.resize (0); + if (in.isEmpty()) + return; + + char *cursor; + const char *data; + unsigned int lineLength; + unsigned int pos; + + const unsigned int length = in.size(); + const unsigned int end = length - 1; + + + // Reasonable guess for output size when we're encoding + // mostly-ASCII data. It doesn't really matter, because + // the underlying allocation routines are quite efficient, + // but it's nice to have 0 allocations in many cases. + out.resize ((length*12)/10); + cursor = out.data(); + data = in.data(); + lineLength = 0; + pos = 0; + + for (unsigned int i = 0; i < length; i++) + { + unsigned char c (data[i]); + + // check if we have to enlarge the output buffer, use + // a safety margin of 16 byte + pos = cursor-out.data(); + if (out.size()-pos < 16) { + out.resize(out.size()+4096); + cursor = out.data()+pos; + } + + // Plain ASCII chars just go straight out. + + if ((c >= 33) && (c <= 126) && ('=' != c)) + { + *cursor++ = c; + ++lineLength; + } + + // Spaces need some thought. We have to encode them at eol (or eof). + + else if (' ' == c) + { + if + ( + (i >= length) + || + ((i < end) && ((useCRLF && ('\r' == data[i + 1]) && ('\n' == data[i + 2])) + || + (!useCRLF && ('\n' == data[i + 1])))) + ) + { + *cursor++ = '='; + *cursor++ = '2'; + *cursor++ = '0'; + + lineLength += 3; + } + else + { + *cursor++ = ' '; + ++lineLength; + } + } + // If we find a line break, just let it through. + else if ((useCRLF && ('\r' == c) && (i < end) && ('\n' == data[i + 1])) || + (!useCRLF && ('\n' == c))) + { + lineLength = 0; + + if (useCRLF) { + *cursor++ = '\r'; + *cursor++ = '\n'; + ++i; + } else { + *cursor++ = '\n'; + } + } + + // Anything else is converted to =XX. + + else + { + *cursor++ = '='; + *cursor++ = hexChars[c / 16]; + *cursor++ = hexChars[c % 16]; + + lineLength += 3; + } + + // If we're approaching the maximum line length, do a soft line break. + + if ((lineLength > maxQPLineLength) && (i < end)) + { + if (useCRLF) { + *cursor++ = '='; + *cursor++ = '\r'; + *cursor++ = '\n'; + } else { + *cursor++ = '='; + *cursor++ = '\n'; + } + + lineLength = 0; + } + } + + out.truncate(cursor - out.data()); +} + +QCString KCodecs::quotedPrintableDecode(const QByteArray & in) +{ + QByteArray out; + quotedPrintableDecode (in, out); + return QCString (out.data(), out.size()+1); +} + +QCString KCodecs::quotedPrintableDecode(const QCString & str) +{ + if (str.isEmpty()) + return ""; + + QByteArray in (str.length()); + memcpy (in.data(), str.data(), str.length()); + return quotedPrintableDecode (in); +} + +void KCodecs::quotedPrintableDecode(const QByteArray& in, QByteArray& out) +{ + // clear out the output buffer + out.resize (0); + if (in.isEmpty()) + return; + + char *cursor; + const char *data; + const unsigned int length = in.size(); + + data = in.data(); + out.resize (length); + cursor = out.data(); + + for (unsigned int i = 0; i < length; i++) + { + char c(in.at(i)); + + if ('=' == c) + { + if (i < length - 2) + { + char c1 = in.at(i + 1); + char c2 = in.at(i + 2); + + if (('\n' == c1) || ('\r' == c1 && '\n' == c2)) + { + // Soft line break. No output. + if ('\r' == c1) + i += 2; // CRLF line breaks + else + i += 1; + } + else + { + // =XX encoded byte. + + int hexChar0 = rikFindChar(hexChars, c1); + int hexChar1 = rikFindChar(hexChars, c2); + + if (hexChar0 < 16 && hexChar1 < 16) + { + *cursor++ = char((hexChar0 * 16) | hexChar1); + i += 2; + } + } + } + } + else + { + *cursor++ = c; + } + } + + out.truncate(cursor - out.data()); +} + +QCString KCodecs::base64Encode( const QCString& str, bool insertLFs ) +{ + if ( str.isEmpty() ) + return ""; + + QByteArray in (str.length()); + memcpy( in.data(), str.data(), str.length() ); + return base64Encode( in, insertLFs ); +} + +QCString KCodecs::base64Encode( const QByteArray& in, bool insertLFs ) +{ + QByteArray out; + base64Encode( in, out, insertLFs ); + return QCString( out.data(), out.size()+1 ); +} + +void KCodecs::base64Encode( const QByteArray& in, QByteArray& out, + bool insertLFs ) +{ + // clear out the output buffer + out.resize (0); + if ( in.isEmpty() ) + return; + + unsigned int sidx = 0; + unsigned int didx = 0; + const char* data = in.data(); + const unsigned int len = in.size(); + + unsigned int out_len = ((len+2)/3)*4; + + // Deal with the 76 characters or less per + // line limit specified in RFC 2045 on a + // pre request basis. + insertLFs = (insertLFs && out_len > 76); + if ( insertLFs ) + out_len += ((out_len-1)/76); + + int count = 0; + out.resize( out_len ); + + // 3-byte to 4-byte conversion + 0-63 to ascii printable conversion + if ( len > 1 ) + { + while (sidx < len-2) + { + if ( insertLFs ) + { + if ( count && (count%76) == 0 ) + out.at(didx++) = '\n'; + count += 4; + } + out.at(didx++) = Base64EncMap[(data[sidx] >> 2) & 077]; + out.at(didx++) = Base64EncMap[(data[sidx+1] >> 4) & 017 | + (data[sidx] << 4) & 077]; + out.at(didx++) = Base64EncMap[(data[sidx+2] >> 6) & 003 | + (data[sidx+1] << 2) & 077]; + out.at(didx++) = Base64EncMap[data[sidx+2] & 077]; + sidx += 3; + } + } + + if (sidx < len) + { + if ( insertLFs && (count > 0) && (count%76) == 0 ) + out.at(didx++) = '\n'; + + out.at(didx++) = Base64EncMap[(data[sidx] >> 2) & 077]; + if (sidx < len-1) + { + out.at(didx++) = Base64EncMap[(data[sidx+1] >> 4) & 017 | + (data[sidx] << 4) & 077]; + out.at(didx++) = Base64EncMap[(data[sidx+1] << 2) & 077]; + } + else + { + out.at(didx++) = Base64EncMap[(data[sidx] << 4) & 077]; + } + } + + // Add padding + while (didx < out.size()) + { + out.at(didx) = '='; + didx++; + } +} + +QCString KCodecs::base64Decode( const QCString& str ) +{ + if ( str.isEmpty() ) + return ""; + + QByteArray in( str.length() ); + memcpy( in.data(), str.data(), str.length() ); + return base64Decode( in ); +} + +QCString KCodecs::base64Decode( const QByteArray& in ) +{ + QByteArray out; + base64Decode( in, out ); + return QCString( out.data(), out.size()+1 ); +} + +void KCodecs::base64Decode( const QByteArray& in, QByteArray& out ) +{ + out.resize(0); + if ( in.isEmpty() ) + return; + + unsigned int count = 0; + unsigned int len = in.size(), tail = len; + const char* data = in.data(); + + // Deal with possible *nix "BEGIN" marker!! + while ( count < len && (data[count] == '\n' || data[count] == '\r' || + data[count] == '\t' || data[count] == ' ') ) + count++; + + if ( QString(data+count).left(5).lower() == "begin" ) + { + count += 5; + while ( count < len && data[count] != '\n' && data[count] != '\r' ) + count++; + + while ( count < len && (data[count] == '\n' || data[count] == '\r') ) + count ++; + + data += count; + tail = (len -= count); + } + + // Find the tail end of the actual encoded data even if + // there is/are trailing CR and/or LF. + while ( data[tail-1] == '=' || data[tail-1] == '\n' || + data[tail-1] == '\r' ) + if ( data[--tail] != '=' ) len = tail; + + unsigned int outIdx = 0; + out.resize( (count=len) ); + for (unsigned int idx = 0; idx < count; idx++) + { + // Adhere to RFC 2045 and ignore characters + // that are not part of the encoding table. + unsigned char ch = data[idx]; + if ((ch > 47 && ch < 58) || (ch > 64 && ch < 91) || + (ch > 96 && ch < 123) || ch == '+' || ch == '/' || ch == '=') + { + out.at(outIdx++) = Base64DecMap[ch]; + } + else + { + len--; + tail--; + } + } + + // kdDebug() << "Tail size = " << tail << ", Length size = " << len << endl; + + // 4-byte to 3-byte conversion + len = (tail>(len/4)) ? tail-(len/4) : 0; + unsigned int sidx = 0, didx = 0; + if ( len > 1 ) + { + while (didx < len-2) + { + out.at(didx) = (((out.at(sidx) << 2) & 255) | ((out.at(sidx+1) >> 4) & 003)); + out.at(didx+1) = (((out.at(sidx+1) << 4) & 255) | ((out.at(sidx+2) >> 2) & 017)); + out.at(didx+2) = (((out.at(sidx+2) << 6) & 255) | (out.at(sidx+3) & 077)); + sidx += 4; + didx += 3; + } + } + + if (didx < len) + out.at(didx) = (((out.at(sidx) << 2) & 255) | ((out.at(sidx+1) >> 4) & 003)); + + if (++didx < len ) + out.at(didx) = (((out.at(sidx+1) << 4) & 255) | ((out.at(sidx+2) >> 2) & 017)); + + // Resize the output buffer + if ( len == 0 || len < out.size() ) + out.resize(len); +} + +QCString KCodecs::uuencode( const QCString& str ) +{ + if ( str.isEmpty() ) + return ""; + + QByteArray in; + in.resize( str.length() ); + memcpy( in.data(), str.data(), str.length() ); + return uuencode( in ); +} + +QCString KCodecs::uuencode( const QByteArray& in ) +{ + QByteArray out; + uuencode( in, out ); + return QCString( out.data(), out.size()+1 ); +} + +void KCodecs::uuencode( const QByteArray& in, QByteArray& out ) +{ + out.resize( 0 ); + if( in.isEmpty() ) + return; + + unsigned int sidx = 0; + unsigned int didx = 0; + unsigned int line_len = 45; + + const char nl[] = "\n"; + const char* data = in.data(); + const unsigned int nl_len = strlen(nl); + const unsigned int len = in.size(); + + out.resize( (len+2)/3*4 + ((len+line_len-1)/line_len)*(nl_len+1) ); + // split into lines, adding line-length and line terminator + while (sidx+line_len < len) + { + // line length + out.at(didx++) = UUEncMap[line_len]; + + // 3-byte to 4-byte conversion + 0-63 to ascii printable conversion + for (unsigned int end = sidx+line_len; sidx < end; sidx += 3) + { + out.at(didx++) = UUEncMap[(data[sidx] >> 2) & 077]; + out.at(didx++) = UUEncMap[(data[sidx+1] >> 4) & 017 | + (data[sidx] << 4) & 077]; + out.at(didx++) = UUEncMap[(data[sidx+2] >> 6) & 003 | + (data[sidx+1] << 2) & 077]; + out.at(didx++) = UUEncMap[data[sidx+2] & 077]; + } + + // line terminator + //for (unsigned int idx=0; idx < nl_len; idx++) + //out.at(didx++) = nl[idx]; + memcpy(out.data()+didx, nl, nl_len); + didx += nl_len; + } + + // line length + out.at(didx++) = UUEncMap[len-sidx]; + // 3-byte to 4-byte conversion + 0-63 to ascii printable conversion + while (sidx+2 < len) + { + out.at(didx++) = UUEncMap[(data[sidx] >> 2) & 077]; + out.at(didx++) = UUEncMap[(data[sidx+1] >> 4) & 017 | + (data[sidx] << 4) & 077]; + out.at(didx++) = UUEncMap[(data[sidx+2] >> 6) & 003 | + (data[sidx+1] << 2) & 077]; + out.at(didx++) = UUEncMap[data[sidx+2] & 077]; + sidx += 3; + } + + if (sidx < len-1) + { + out.at(didx++) = UUEncMap[(data[sidx] >> 2) & 077]; + out.at(didx++) = UUEncMap[(data[sidx+1] >> 4) & 017 | + (data[sidx] << 4) & 077]; + out.at(didx++) = UUEncMap[(data[sidx+1] << 2) & 077]; + out.at(didx++) = UUEncMap[0]; + } + else if (sidx < len) + { + out.at(didx++) = UUEncMap[(data[sidx] >> 2) & 077]; + out.at(didx++) = UUEncMap[(data[sidx] << 4) & 077]; + out.at(didx++) = UUEncMap[0]; + out.at(didx++) = UUEncMap[0]; + } + + // line terminator + memcpy(out.data()+didx, nl, nl_len); + didx += nl_len; + + // sanity check + if ( didx != out.size() ) + out.resize( 0 ); +} + +QCString KCodecs::uudecode( const QCString& str ) +{ + if ( str.isEmpty() ) + return ""; + + QByteArray in; + in.resize( str.length() ); + memcpy( in.data(), str.data(), str.length() ); + return uudecode( in ); +} + +QCString KCodecs::uudecode( const QByteArray& in ) +{ + QByteArray out; + uudecode( in, out ); + return QCString( out.data(), out.size()+1 ); +} + +void KCodecs::uudecode( const QByteArray& in, QByteArray& out ) +{ + out.resize( 0 ); + if( in.isEmpty() ) + return; + + unsigned int sidx = 0; + unsigned int didx = 0; + unsigned int len = in.size(); + unsigned int line_len, end; + const char* data = in.data(); + + // Deal with *nix "BEGIN"/"END" separators!! + unsigned int count = 0; + while ( count < len && (data[count] == '\n' || data[count] == '\r' || + data[count] == '\t' || data[count] == ' ') ) + count ++; + + bool hasLF = false; + if ( QString( data+count).left(5).lower() == "begin" ) + { + count += 5; + while ( count < len && data[count] != '\n' && data[count] != '\r' ) + count ++; + + while ( count < len && (data[count] == '\n' || data[count] == '\r') ) + count ++; + + data += count; + len -= count; + hasLF = true; + } + + out.resize( len/4*3 ); + while ( sidx < len ) + { + // get line length (in number of encoded octets) + line_len = UUDecMap[ (unsigned char) data[sidx++]]; + // ascii printable to 0-63 and 4-byte to 3-byte conversion + end = didx+line_len; + char A, B, C, D; + if (end > 2) { + while (didx < end-2) + { + A = UUDecMap[(unsigned char) data[sidx]]; + B = UUDecMap[(unsigned char) data[sidx+1]]; + C = UUDecMap[(unsigned char) data[sidx+2]]; + D = UUDecMap[(unsigned char) data[sidx+3]]; + out.at(didx++) = ( ((A << 2) & 255) | ((B >> 4) & 003) ); + out.at(didx++) = ( ((B << 4) & 255) | ((C >> 2) & 017) ); + out.at(didx++) = ( ((C << 6) & 255) | (D & 077) ); + sidx += 4; + } + } + + if (didx < end) + { + A = UUDecMap[(unsigned char) data[sidx]]; + B = UUDecMap[(unsigned char) data[sidx+1]]; + out.at(didx++) = ( ((A << 2) & 255) | ((B >> 4) & 003) ); + } + + if (didx < end) + { + B = UUDecMap[(unsigned char) data[sidx+1]]; + C = UUDecMap[(unsigned char) data[sidx+2]]; + out.at(didx++) = ( ((B << 4) & 255) | ((C >> 2) & 017) ); + } + + // skip padding + while (sidx < len && data[sidx] != '\n' && data[sidx] != '\r') + sidx++; + + // skip end of line + while (sidx < len && (data[sidx] == '\n' || data[sidx] == '\r')) + sidx++; + + // skip the "END" separator when present. + if ( hasLF && QString( data+sidx).left(3).lower() == "end" ) + break; + } + + if ( didx < out.size() ) + out.resize( didx ); +} + +/******************************** KMD5 ********************************/ +KMD5::KMD5() +{ + init(); +} + +KMD5::KMD5(const char *in, int len) +{ + init(); + update(in, len); +} + +KMD5::KMD5(const QByteArray& in) +{ + init(); + update( in ); +} + +KMD5::KMD5(const QCString& in) +{ + init(); + update( in ); +} + +void KMD5::update(const QByteArray& in) +{ + update(in.data(), int(in.size())); +} + +void KMD5::update(const QCString& in) +{ + update(in.data(), int(in.length())); +} + +void KMD5::update(const unsigned char* in, int len) +{ + if (len < 0) + len = qstrlen(reinterpret_cast(in)); + + if (!len) + return; + + if (m_finalized) { + kdWarning() << "KMD5::update called after state was finalized!" << endl; + return; + } + + Q_UINT32 in_index; + Q_UINT32 buffer_index; + Q_UINT32 buffer_space; + Q_UINT32 in_length = static_cast( len ); + + buffer_index = static_cast((m_count[0] >> 3) & 0x3F); + + if ( (m_count[0] += (in_length << 3))<(in_length << 3) ) + m_count[1]++; + + m_count[1] += (in_length >> 29); + buffer_space = 64 - buffer_index; + + if (in_length >= buffer_space) + { + memcpy (m_buffer + buffer_index, in, buffer_space); + transform (m_buffer); + + for (in_index = buffer_space; in_index + 63 < in_length; + in_index += 64) + transform (reinterpret_cast(in+in_index)); + + buffer_index = 0; + } + else + in_index=0; + + memcpy(m_buffer+buffer_index, in+in_index, in_length-in_index); +} + +bool KMD5::update(QIODevice& file) +{ + char buffer[1024]; + int len; + + while ((len=file.readBlock(reinterpret_cast(buffer), sizeof(buffer))) > 0) + update(buffer, len); + + return file.atEnd(); +} + +void KMD5::finalize () +{ + if (m_finalized) return; + + Q_UINT8 bits[8]; + Q_UINT32 index, padLen; + static unsigned char PADDING[64]= + { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + + encode (bits, m_count, 8); + //memcpy( bits, m_count, 8 ); + + // Pad out to 56 mod 64. + index = static_cast((m_count[0] >> 3) & 0x3f); + padLen = (index < 56) ? (56 - index) : (120 - index); + update (reinterpret_cast(PADDING), padLen); + + // Append length (before padding) + update (reinterpret_cast(bits), 8); + + // Store state in digest + encode (m_digest, m_state, 16); + //memcpy( m_digest, m_state, 16 ); + + // Fill sensitive information with zero's + memset ( (void *)m_buffer, 0, sizeof(*m_buffer)); + + m_finalized = true; +} + + +bool KMD5::verify( const KMD5::Digest& digest) +{ + finalize(); + return (0 == memcmp(rawDigest(), digest, sizeof(KMD5::Digest))); +} + +bool KMD5::verify( const QCString& hexdigest) +{ + finalize(); + return (0 == strcmp(hexDigest().data(), hexdigest)); +} + +const KMD5::Digest& KMD5::rawDigest() +{ + finalize(); + return m_digest; +} + +void KMD5::rawDigest( KMD5::Digest& bin ) +{ + finalize(); + memcpy( bin, m_digest, 16 ); +} + + +QCString KMD5::hexDigest() +{ + QCString s(33); + + finalize(); + sprintf(s.data(), "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + m_digest[0], m_digest[1], m_digest[2], m_digest[3], m_digest[4], m_digest[5], + m_digest[6], m_digest[7], m_digest[8], m_digest[9], m_digest[10], m_digest[11], + m_digest[12], m_digest[13], m_digest[14], m_digest[15]); + + return s; +} + +void KMD5::hexDigest(QCString& s) +{ + finalize(); + s.resize(33); + sprintf(s.data(), "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + m_digest[0], m_digest[1], m_digest[2], m_digest[3], m_digest[4], m_digest[5], + m_digest[6], m_digest[7], m_digest[8], m_digest[9], m_digest[10], m_digest[11], + m_digest[12], m_digest[13], m_digest[14], m_digest[15]); +} + +QCString KMD5::base64Digest() +{ + QByteArray ba(16); + + finalize(); + memcpy(ba.data(), m_digest, 16); + return KCodecs::base64Encode(ba); +} + + +void KMD5::init() +{ + d = 0; + reset(); +} + +void KMD5::reset() +{ + m_finalized = false; + + m_count[0] = 0; + m_count[1] = 0; + + m_state[0] = 0x67452301; + m_state[1] = 0xefcdab89; + m_state[2] = 0x98badcfe; + m_state[3] = 0x10325476; + + memset ( m_buffer, 0, sizeof(*m_buffer)); + memset ( m_digest, 0, sizeof(*m_digest)); +} + +void KMD5::transform( const unsigned char block[64] ) +{ + + Q_UINT32 a = m_state[0], b = m_state[1], c = m_state[2], d = m_state[3], x[16]; + + decode (x, block, 64); + //memcpy( x, block, 64 ); + +//US Q_ASSERT(!m_finalized); // not just a user error, since the method is private + ASSERT(!m_finalized); // not just a user error, since the method is private + + /* Round 1 */ + FF (a, b, c, d, x[ 0], KMD5_S11, 0xd76aa478); /* 1 */ + FF (d, a, b, c, x[ 1], KMD5_S12, 0xe8c7b756); /* 2 */ + FF (c, d, a, b, x[ 2], KMD5_S13, 0x242070db); /* 3 */ + FF (b, c, d, a, x[ 3], KMD5_S14, 0xc1bdceee); /* 4 */ + FF (a, b, c, d, x[ 4], KMD5_S11, 0xf57c0faf); /* 5 */ + FF (d, a, b, c, x[ 5], KMD5_S12, 0x4787c62a); /* 6 */ + FF (c, d, a, b, x[ 6], KMD5_S13, 0xa8304613); /* 7 */ + FF (b, c, d, a, x[ 7], KMD5_S14, 0xfd469501); /* 8 */ + FF (a, b, c, d, x[ 8], KMD5_S11, 0x698098d8); /* 9 */ + FF (d, a, b, c, x[ 9], KMD5_S12, 0x8b44f7af); /* 10 */ + FF (c, d, a, b, x[10], KMD5_S13, 0xffff5bb1); /* 11 */ + FF (b, c, d, a, x[11], KMD5_S14, 0x895cd7be); /* 12 */ + FF (a, b, c, d, x[12], KMD5_S11, 0x6b901122); /* 13 */ + FF (d, a, b, c, x[13], KMD5_S12, 0xfd987193); /* 14 */ + FF (c, d, a, b, x[14], KMD5_S13, 0xa679438e); /* 15 */ + FF (b, c, d, a, x[15], KMD5_S14, 0x49b40821); /* 16 */ + + /* Round 2 */ + GG (a, b, c, d, x[ 1], KMD5_S21, 0xf61e2562); /* 17 */ + GG (d, a, b, c, x[ 6], KMD5_S22, 0xc040b340); /* 18 */ + GG (c, d, a, b, x[11], KMD5_S23, 0x265e5a51); /* 19 */ + GG (b, c, d, a, x[ 0], KMD5_S24, 0xe9b6c7aa); /* 20 */ + GG (a, b, c, d, x[ 5], KMD5_S21, 0xd62f105d); /* 21 */ + GG (d, a, b, c, x[10], KMD5_S22, 0x2441453); /* 22 */ + GG (c, d, a, b, x[15], KMD5_S23, 0xd8a1e681); /* 23 */ + GG (b, c, d, a, x[ 4], KMD5_S24, 0xe7d3fbc8); /* 24 */ + GG (a, b, c, d, x[ 9], KMD5_S21, 0x21e1cde6); /* 25 */ + GG (d, a, b, c, x[14], KMD5_S22, 0xc33707d6); /* 26 */ + GG (c, d, a, b, x[ 3], KMD5_S23, 0xf4d50d87); /* 27 */ + GG (b, c, d, a, x[ 8], KMD5_S24, 0x455a14ed); /* 28 */ + GG (a, b, c, d, x[13], KMD5_S21, 0xa9e3e905); /* 29 */ + GG (d, a, b, c, x[ 2], KMD5_S22, 0xfcefa3f8); /* 30 */ + GG (c, d, a, b, x[ 7], KMD5_S23, 0x676f02d9); /* 31 */ + GG (b, c, d, a, x[12], KMD5_S24, 0x8d2a4c8a); /* 32 */ + + /* Round 3 */ + HH (a, b, c, d, x[ 5], KMD5_S31, 0xfffa3942); /* 33 */ + HH (d, a, b, c, x[ 8], KMD5_S32, 0x8771f681); /* 34 */ + HH (c, d, a, b, x[11], KMD5_S33, 0x6d9d6122); /* 35 */ + HH (b, c, d, a, x[14], KMD5_S34, 0xfde5380c); /* 36 */ + HH (a, b, c, d, x[ 1], KMD5_S31, 0xa4beea44); /* 37 */ + HH (d, a, b, c, x[ 4], KMD5_S32, 0x4bdecfa9); /* 38 */ + HH (c, d, a, b, x[ 7], KMD5_S33, 0xf6bb4b60); /* 39 */ + HH (b, c, d, a, x[10], KMD5_S34, 0xbebfbc70); /* 40 */ + HH (a, b, c, d, x[13], KMD5_S31, 0x289b7ec6); /* 41 */ + HH (d, a, b, c, x[ 0], KMD5_S32, 0xeaa127fa); /* 42 */ + HH (c, d, a, b, x[ 3], KMD5_S33, 0xd4ef3085); /* 43 */ + HH (b, c, d, a, x[ 6], KMD5_S34, 0x4881d05); /* 44 */ + HH (a, b, c, d, x[ 9], KMD5_S31, 0xd9d4d039); /* 45 */ + HH (d, a, b, c, x[12], KMD5_S32, 0xe6db99e5); /* 46 */ + HH (c, d, a, b, x[15], KMD5_S33, 0x1fa27cf8); /* 47 */ + HH (b, c, d, a, x[ 2], KMD5_S34, 0xc4ac5665); /* 48 */ + + /* Round 4 */ + II (a, b, c, d, x[ 0], KMD5_S41, 0xf4292244); /* 49 */ + II (d, a, b, c, x[ 7], KMD5_S42, 0x432aff97); /* 50 */ + II (c, d, a, b, x[14], KMD5_S43, 0xab9423a7); /* 51 */ + II (b, c, d, a, x[ 5], KMD5_S44, 0xfc93a039); /* 52 */ + II (a, b, c, d, x[12], KMD5_S41, 0x655b59c3); /* 53 */ + II (d, a, b, c, x[ 3], KMD5_S42, 0x8f0ccc92); /* 54 */ + II (c, d, a, b, x[10], KMD5_S43, 0xffeff47d); /* 55 */ + II (b, c, d, a, x[ 1], KMD5_S44, 0x85845dd1); /* 56 */ + II (a, b, c, d, x[ 8], KMD5_S41, 0x6fa87e4f); /* 57 */ + II (d, a, b, c, x[15], KMD5_S42, 0xfe2ce6e0); /* 58 */ + II (c, d, a, b, x[ 6], KMD5_S43, 0xa3014314); /* 59 */ + II (b, c, d, a, x[13], KMD5_S44, 0x4e0811a1); /* 60 */ + II (a, b, c, d, x[ 4], KMD5_S41, 0xf7537e82); /* 61 */ + II (d, a, b, c, x[11], KMD5_S42, 0xbd3af235); /* 62 */ + II (c, d, a, b, x[ 2], KMD5_S43, 0x2ad7d2bb); /* 63 */ + II (b, c, d, a, x[ 9], KMD5_S44, 0xeb86d391); /* 64 */ + + m_state[0] += a; + m_state[1] += b; + m_state[2] += c; + m_state[3] += d; + + memset ( static_cast(x), 0, sizeof(x) ); +} + +inline Q_UINT32 KMD5::rotate_left (Q_UINT32 x, Q_UINT32 n) +{ + return (x << n) | (x >> (32-n)) ; +} + +inline Q_UINT32 KMD5::F (Q_UINT32 x, Q_UINT32 y, Q_UINT32 z) +{ + return (x & y) | (~x & z); +} + +inline Q_UINT32 KMD5::G (Q_UINT32 x, Q_UINT32 y, Q_UINT32 z) +{ + return (x & z) | (y & ~z); +} + +inline Q_UINT32 KMD5::H (Q_UINT32 x, Q_UINT32 y, Q_UINT32 z) +{ + return x ^ y ^ z; +} + +inline Q_UINT32 KMD5::I (Q_UINT32 x, Q_UINT32 y, Q_UINT32 z) +{ + return y ^ (x | ~z); +} + +void KMD5::FF ( Q_UINT32& a, Q_UINT32 b, Q_UINT32 c, Q_UINT32 d, + Q_UINT32 x, Q_UINT32 s, Q_UINT32 ac ) +{ + a += F(b, c, d) + x + ac; + a = rotate_left (a, s) +b; +} + +void KMD5::GG ( Q_UINT32& a, Q_UINT32 b, Q_UINT32 c, Q_UINT32 d, + Q_UINT32 x, Q_UINT32 s, Q_UINT32 ac) +{ + a += G(b, c, d) + x + ac; + a = rotate_left (a, s) +b; +} + +void KMD5::HH ( Q_UINT32& a, Q_UINT32 b, Q_UINT32 c, Q_UINT32 d, + Q_UINT32 x, Q_UINT32 s, Q_UINT32 ac ) +{ + a += H(b, c, d) + x + ac; + a = rotate_left (a, s) +b; +} + +void KMD5::II ( Q_UINT32& a, Q_UINT32 b, Q_UINT32 c, Q_UINT32 d, + Q_UINT32 x, Q_UINT32 s, Q_UINT32 ac ) +{ + a += I(b, c, d) + x + ac; + a = rotate_left (a, s) +b; +} + + +void KMD5::encode ( unsigned char* output, Q_UINT32 *in, Q_UINT32 len ) +{ +#if !defined(WORDS_BIGENDIAN) + memcpy(output, in, len); + +#else + Q_UINT32 i, j; + for (i = 0, j = 0; j < len; i++, j += 4) + { + output[j] = static_cast((in[i] & 0xff)); + output[j+1] = static_cast(((in[i] >> 8) & 0xff)); + output[j+2] = static_cast(((in[i] >> 16) & 0xff)); + output[j+3] = static_cast(((in[i] >> 24) & 0xff)); + } +#endif +} + +// Decodes in (Q_UINT8) into output (Q_UINT32). Assumes len is a +// multiple of 4. +void KMD5::decode (Q_UINT32 *output, const unsigned char* in, Q_UINT32 len) +{ +#if !defined(WORDS_BIGENDIAN) + memcpy(output, in, len); + +#else + Q_UINT32 i, j; + for (i = 0, j = 0; j < len; i++, j += 4) + output[i] = static_cast(in[j]) | + (static_cast(in[j+1]) << 8) | + (static_cast(in[j+2]) << 16) | + (static_cast(in[j+3]) << 24); +#endif +} diff --git a/microkde/kdecore/kmdcodec.h b/microkde/kdecore/kmdcodec.h new file mode 100644 index 0000000..2c4d611 --- a/dev/null +++ b/microkde/kdecore/kmdcodec.h @@ -0,0 +1,572 @@ +/* + Copyright (C) 2000-2001 Dawit Alemayehu + Copyright (C) 2001 Rik Hemsley (rikkus) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License (LGPL) + version 2 as published by the Free Software Foundation. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + RFC 1321 "MD5 Message-Digest Algorithm" Copyright (C) 1991-1992. + RSA Data Security, Inc. Created 1991. All rights reserved. + + The KMD5 class is based on a C++ implementation of + "RSA Data Security, Inc. MD5 Message-Digest Algorithm" by + Mordechai T. Abzug, Copyright (c) 1995. This implementation + passes the test-suite as defined in RFC 1321. + + The encoding and decoding utilities in KCodecs with the exception of + quoted-printable are based on the java implementation in HTTPClient + package by Ronald Tschalär Copyright (C) 1996-1999. + + The quoted-printable codec as described in RFC 2045, section 6.7. is by + Rik Hemsley (C) 2001. +*/ + +#ifndef _KMDBASE_H +#define _KMDBASE_H + +#define KBase64 KCodecs + +#include +#include +#include + +/** + * A wrapper class for the most commonly used encoding and + * decoding algorithms. Currently there is support for encoding + * and decoding input using base64, uu and the quoted-printable + * specifications. + * + * @sect Usage: + * + *
+ * QCString input = "Aladdin:open sesame";
+ * QCString result = KCodecs::base64Encode(input);
+ * cout << "Result: " << result.data() << endl;
+ *
+ * Output should be
+ * Result: QWxhZGRpbjpvcGVuIHNlc2FtZQ==
+ * 
+ * + * The above example makes use of the convenience functions + * (ones that accept/return null-terminated strings) to encode/decode + * a string. If what you need is to encode or decode binary data, then + * it is highly recommended that you use the functions that take an input + * and output QByteArray as arguments. These functions are specifically + * tailored for encoding and decoding binary data. + * + * @short A collection of commonly used encoding and decoding algorithms. + * @author Dawit Alemayehu + * @author Rik Hemsley + */ +class KCodecs +{ +public: + + /** + * Encodes the given data using the quoted-printable algorithm. + * + * @param in data to be encoded. + * @param useCRLF if true the input data is expected to have + * CRLF line breaks and the output will have CRLF line + * breaks, too. + * @return quoted-printable encoded data. + */ + static QCString quotedPrintableEncode(const QByteArray & in, + bool useCRLF = true); + + /** + * @overload + * + * Same as above except it accepts a null terminated + * string instead an array. + * + * @param str data to be encoded. + * @param useCRLF if true the input data is expected to have + * CRLF line breaks and the output will have CRLF line + * breaks, too. + * @return quoted-printable encoded data. + */ + static QCString quotedPrintableEncode(const QCString & str, + bool useCRLF = true); + + /** + * Encodes the given data using the quoted-printable algorithm. + * + * Use this function if you want the result of the encoding + * to be placed in another array which cuts down the number + * of copy operation that have to be performed in the process. + * This is also the preferred method for encoding binary data. + * + * NOTE: the output array is first reset and then resized + * appropriately before use, hence, all data stored in the + * output array will be lost. + * + * @param in data to be encoded. + * @param out decoded data. + * @param useCRLF if true the input data is expected to have + * CRLF line breaks and the output will have CRLF line + * breaks, too. + * @return quoted-printable encoded data. + */ + static void quotedPrintableEncode(const QByteArray & in, QByteArray& out, + bool useCRLF); + + /** + * Decodes a quoted-printable encoded string. + * + * Accepts data with CRLF or standard unix line breaks. + * + * @param in the data to be decoded. + * @return decoded data. + */ + static QCString quotedPrintableDecode(const QByteArray & in); + + /** + * @overload + * + * Same as above except it accepts a null terminated + * string instead an array. + * + * @param str the data to be decoded. + * @return decoded data. + */ + static QCString quotedPrintableDecode(const QCString & str); + + /** + * Decodes a quoted-printable encoded data. + * + * Accepts data with CRLF or standard unix line breaks. + * Use this function if you want the result of the decoding + * to be placed in another array which cuts down the number + * of copy operation that have to be performed in the process. + * This is also the preferred method for decoding an encoded + * binary data. + * + * NOTE: the output array is first reset and then resized + * appropriately before use, hence, all data stored in the + * output array will be lost. + * + * @param in data to be encoded. + * @param out decoded data. + * + * @return quoted-printable encoded data. + */ + static void quotedPrintableDecode(const QByteArray & in, QByteArray& out); + + + /** + * Encodes the given data using the uuencode algorithm. + * + * The output is split into lines starting with the number of + * encoded octets in the line and ending with a newline. No + * line is longer than 45 octets (60 characters), excluding the + * line terminator. + * + * @param in the data to be uuencoded + * @return a uuencoded data. + */ + static QCString uuencode( const QByteArray& in ); + + /** + * @overload + * + * Same as the above functions except it accepts + * a null terminated string instead an array. + * + * @param str the string to be uuencoded. + * @return the encoded string. + */ + static QCString uuencode( const QCString& str ); + + /** + * Encodes the given data using the uuencode algorithm. + * + * Use this function if you want the result of the encoding + * to be placed in another array and cut down the number of + * copy operation that have to be performed in the process. + * This is the preffered method for encoding binary data. + * + * NOTE: the output array is first reset and then resized + * appropriately before use, hence, all data stored in the + * output array will be lost. + * + * @param in the data to be uuencoded. + * @param out the container for the uudecoded data. + */ + static void uuencode( const QByteArray& in, QByteArray& out ); + + /** + * Decodes the given data using the uuencode algorithm. + * + * Any 'begin' and 'end' lines like those generated by + * the utilities in unix and unix-like OS will be + * automatically ignored. + * + * @param in the data uuencoded data to be decoded. + * @return a decoded string. + */ + static QCString uudecode( const QByteArray& in ); + + /** + * @overload + * + * Same as the above functions except it accepts + * a null terminated string instead an array. + * + * @param str the string to be decoded. + * @return a uudecoded string. + */ + static QCString uudecode( const QCString& str ); + + /** + * Decodes the given data using the uudecode algorithm. + * + * Use this function if you want the result of the decoding + * to be placed in another array which cuts down the number + * of copy operation that have to be performed in the process. + * This is the preferred method for decoding binary data. + * + * Any 'begin' and 'end' lines like those generated by + * the utilities in unix and unix-like OS will be + * automatically ignored. + * + * NOTE: the output array is first reset and then resized + * appropriately before use, hence, all data stored in the + * output array will be lost. + * + * @param in the uuencoded-data to be decoded. + * @param out the container for the uudecoded data. + */ + static void uudecode( const QByteArray& in, QByteArray& out ); + + + /** + * Encodes the given data using the base64 algorithm. + * + * The boolean argument determines if the encoded data is + * going to be restricted to 76 characters or less per line + * as specified by RFC 2045. If @p insertLFs is true, then + * there will be 76 characters or less per line. + * + * @param in the data to be encoded. + * @param insertLFs limit the number of characters per line. + * + * @return a base64 encoded string. + */ + static QCString base64Encode( const QByteArray& in, bool insertLFs = false); + + /** + * @overload + * + * Same as the above functions except it accepts + * a null terminated string instead an array. + * + * @param str the string to be encoded. + * @param insertLFs limit the number of characters per line. + * @return the decoded string. + */ + static QCString base64Encode( const QCString& str, bool insertLFs = false ); + + /** + * Encodes the given data using the base64 algorithm. + * + * Use this function if you want the result of the encoding + * to be placed in another array which cuts down the number + * of copy operation that have to be performed in the process. + * This is also the preferred method for encoding binary data. + * + * The boolean argument determines if the encoded data is going + * to be restricted to 76 characters or less per line as specified + * by RFC 2045. If @p insertLFs is true, then there will be 76 + * characters or less per line. + * + * NOTE: the output array is first reset and then resized + * appropriately before use, hence, all data stored in the + * output array will be lost. + * + * @param in the data to be encoded using base64. + * @param out the container for the encoded data. + * @param insertLFs limit the number of characters per line. + */ + static void base64Encode( const QByteArray& in, QByteArray& out, + bool insertLFs = false ); + + /** + * Decodes the given data that was encoded using the + * base64 algorithm. + * + * @param in the base64-encoded data to be decoded. + * @return the decoded data. + */ + static QCString base64Decode( const QByteArray& in ); + + /** + * @overload + * + * Same as the above functions except it accepts + * a null terminated string instead an array. + * + * @param str the base64-encoded string. + * @return the decoded string. + */ + static QCString base64Decode( const QCString& str ); + + /** + * Decodes the given data that was encoded with the base64 + * algorithm. + * + * Use this function if you want the result of the decoding + * to be placed in another array which cuts down the number + * of copy operation that have to be performed in the process. + * This is also the preferred method for decoding an encoded + * binary data. + * + * NOTE: the output array is first reset and then resized + * appropriately before use, hence, all data stored in the + * output array will be lost. + * + * @param in the encoded data to be decoded. + * @param out the container for the decoded data. + */ + static void base64Decode( const QByteArray& in, QByteArray& out ); + + +private: + KCodecs(); + +private: + static const char UUEncMap[64]; + static const char UUDecMap[128]; + static const char Base64EncMap[64]; + static const char Base64DecMap[128]; + static const char hexChars[16]; + static const unsigned int maxQPLineLength; +}; + +class KMD5Private; +/** + * Provides an easy to use C++ implementation of RSA's + * MD5 algorithm. + * + * The default constructor is designed to provide much the same + * functionality as the most commonly used C-implementation, while + * the other three constructors are meant to further simplify the + * process of obtaining a digest by calculating the result in a + * single step. + * + * KMD5 is state-based, that means you can add new contents with + * update() as long as you didn't request the digest value yet. + * After the digest value was requested, the object is "finalized" + * and you have to call reset() to be able to do another calculation + * with it. The reason for this behaviour is that upon requesting + * the message digest KMD5 has to pad the received contents up to a + * 64 byte boundary to calculate its value. After this operation it + * is not possible to resume consuming data. + * + * @sect Usage: + * + * A common usage of this class: + * + *
+ *  const char* test1;
+ *  KMD5::Digest rawResult;
+ *
+ *  test1 = "This is a simple test.";
+ *  KMD5 context (test1);
+ *  cout << "Hex Digest output: " << context.hexDigest().data() << endl;
+ * 
+ * + * To cut down on the unnecessary overhead of creating multiple KMD5 + * objects, you can simply invoke @ref reset() to reuse the same object + * in making another calculation: + * + *
+ *  context.reset ();
+ *  context.update ("TWO");
+ *  context.update ("THREE");
+ *  cout << "Hex Digest output: " << context.hexDigest().data() << endl;
+ * 
+ * + * @short An adapted C++ implementation of RSA Data Securities MD5 algorithm. + * @author Dirk Mueller , Dawit Alemayehu + */ + +class KMD5 +{ +public: + + typedef unsigned char Digest[16]; + + KMD5(); + + /** + * Constructor that updates the digest for the given string. + * + * @param in C string or binary data + * @param len if negative, calculates the length by using + * strlen on the first parameter, otherwise + * it trusts the given length (does not stop on NUL byte). + */ + KMD5(const char* in, int len = -1); + + /** + * @overload + * + * Same as above except it accepts a QByteArray as its argument. + */ + KMD5(const QByteArray& a ); + + /** + * @overload + * + * Same as above except it accepts a QByteArray as its argument. + */ + KMD5(const QCString& a ); + + /** + * Updates the message to be digested. Be sure to add all data + * before you read the digest. After reading the digest, you + * can not add more data! + * + * @param in message to be added to digest + * @param len the length of the given message. + */ + void update(const char* in, int len = -1) { update(reinterpret_cast(in), len); } + + /** + * @overload + */ + void update(const unsigned char* in, int len = -1); + + /** + * @overload + * + * @param in message to be added to the digest (QByteArray). + */ + void update(const QByteArray& in ); + + /** + * @overload + * + * @param in message to be added to the digest (QByteArray). + */ + void update(const QCString& in ); + + /** + * @overload + * + * reads the data from an I/O device, i.e. from a file (QFile). + * + * NOTE that the file must be open for reading. + * + * @param file a pointer to FILE as returned by calls like f{d,re}open + * + * @returns false if an error occured during reading. + */ + bool update(QIODevice& file); + + /** + * Calling this function will reset the calculated message digest. + * Use this method to perform another message digest calculation + * without recreating the KMD5 object. + */ + void reset(); + + /** + * @return the raw representation of the digest + */ + const Digest& rawDigest (); + + /** + * Fills the given array with the binary representation of the + * message digest. + * + * Use this method if you do not want to worry about making + * copy of the digest once you obtain it. + * + * @param bin an array of 16 characters ( char[16] ) + */ + void rawDigest( KMD5::Digest& bin ); + + /** + * Returns the value of the calculated message digest in + * a hexadecimal representation. + */ + QCString hexDigest (); + + /** + * @overload + */ + void hexDigest(QCString&); + + /** + * Returns the value of the calculated message digest in + * a base64-encoded representation. + */ + QCString base64Digest (); + + /** + * returns true if the calculated digest for the given + * message matches the given one. + */ + bool verify( const KMD5::Digest& digest); + + /** + * @overload + */ + bool verify(const QCString&); + +protected: + /** + * Performs the real update work. Note + * that length is implied to be 64. + */ + void transform( const unsigned char buffer[64] ); + + /** + * finalizes the digest + */ + void finalize(); + +private: + KMD5(const KMD5& u); + KMD5& operator=(const KMD5& md); + + void init(); + void encode( unsigned char* output, Q_UINT32 *in, Q_UINT32 len ); + void decode( Q_UINT32 *output, const unsigned char* in, Q_UINT32 len ); + + Q_UINT32 rotate_left( Q_UINT32 x, Q_UINT32 n ); + Q_UINT32 F( Q_UINT32 x, Q_UINT32 y, Q_UINT32 z ); + Q_UINT32 G( Q_UINT32 x, Q_UINT32 y, Q_UINT32 z ); + Q_UINT32 H( Q_UINT32 x, Q_UINT32 y, Q_UINT32 z ); + Q_UINT32 I( Q_UINT32 x, Q_UINT32 y, Q_UINT32 z ); + void FF( Q_UINT32& a, Q_UINT32 b, Q_UINT32 c, Q_UINT32 d, Q_UINT32 x, + Q_UINT32 s, Q_UINT32 ac ); + void GG( Q_UINT32& a, Q_UINT32 b, Q_UINT32 c, Q_UINT32 d, Q_UINT32 x, + Q_UINT32 s, Q_UINT32 ac ); + void HH( Q_UINT32& a, Q_UINT32 b, Q_UINT32 c, Q_UINT32 d, Q_UINT32 x, + Q_UINT32 s, Q_UINT32 ac ); + void II( Q_UINT32& a, Q_UINT32 b, Q_UINT32 c, Q_UINT32 d, Q_UINT32 x, + Q_UINT32 s, Q_UINT32 ac ); + +private: + Q_UINT32 m_state[4]; + Q_UINT32 m_count[2]; + Q_UINT8 m_buffer[64]; + Digest m_digest; + bool m_finalized; + + KMD5Private* d; +}; +#endif diff --git a/microkde/kdecore/ksharedptr.h b/microkde/kdecore/ksharedptr.h new file mode 100644 index 0000000..545058a --- a/dev/null +++ b/microkde/kdecore/ksharedptr.h @@ -0,0 +1,171 @@ +/* This file is part of the KDE libraries + Copyright (c) 1999 Waldo Bastian + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + 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. +*/ +#ifndef KSharedPTR_H +#define KSharedPTR_H + +/** + * Reference counting for shared objects. If you derive your object + * from this class, then you may use it in conjunction with + * @ref KSharedPtr to control the lifetime of your object. + * + * Specifically, all classes that derive from KShared have an internal + * counter keeping track of how many other objects have a reference to + * their object. If used with @ref KSharedPtr, then your object will + * not be deleted until all references to the object have been + * released. + * + * You should probably not ever use any of the methods in this class + * directly -- let the @ref KSharedPtr take care of that. Just derive + * your class from KShared and forget about it. + * + * @author Waldo Bastian + * @version $Id$ + */ +class KShared { +public: + /** + * Standard constructor. This will initialize the reference count + * on this object to 0. + */ + KShared() : count(0) { } + + /** + * Copy constructor. This will @em not actually copy the objects + * but it will initialize the reference count on this object to 0. + */ + KShared( const KShared & ) : count(0) { } + + /** + * Overloaded assignment operator. + */ + KShared &operator=(const KShared & ) { return *this; } + + /** + * Increases the reference count by one. + */ + void _KShared_ref() const { count++; } + + /** + * Releases a reference (decreases the reference count by one). If + * the count goes to 0, this object will delete itself. + */ + void _KShared_unref() const { if (!--count) delete this; } + + /** + * Return the current number of references held. + * + * @return Number of references + */ + int _KShared_count() const { return count; } + +protected: + virtual ~KShared() { } +private: + mutable int count; +}; + +/** + * Can be used to control the lifetime of an object that has derived + * @ref KShared. As long a someone holds a KSharedPtr on some @ref KShared + * object it won't become deleted but is deleted once its reference + * count is 0. This struct emulates C++ pointers perfectly. So just + * use it like a simple C++ pointer. + * + * KShared and KSharedPtr are preferred over QShared / QSharedPtr + * since they are more safe. + * + * @author Waldo Bastian + * @version $Id$ + */ +template< class T > +struct KSharedPtr +{ +public: +/** + * Creates a null pointer. + */ + KSharedPtr() + : ptr(0) { } + /** + * Creates a new pointer. + * @param the pointer + */ + KSharedPtr( T* t ) + : ptr(t) { if ( ptr ) ptr->_KShared_ref(); } + + /** + * Copies a pointer. + * @param the pointer to copy + */ + KSharedPtr( const KSharedPtr& p ) + : ptr(p.ptr) { if ( ptr ) ptr->_KShared_ref(); } + + /** + * Unreferences the object that this pointer points to. If it was + * the last reference, the object will be deleted. + */ + ~KSharedPtr() { if ( ptr ) ptr->_KShared_unref(); } + + KSharedPtr& operator= ( const KSharedPtr& p ) { + if ( ptr == p.ptr ) return *this; + if ( ptr ) ptr->_KShared_unref(); + ptr = p.ptr; + if ( ptr ) ptr->_KShared_ref(); + return *this; + } + KSharedPtr& operator= ( T* p ) { + if ( ptr == p ) return *this; + if ( ptr ) ptr->_KShared_unref(); + ptr = p; + if ( ptr ) ptr->_KShared_ref(); + return *this; + } + bool operator== ( const KSharedPtr& p ) const { return ( ptr == p.ptr ); } + bool operator!= ( const KSharedPtr& p ) const { return ( ptr != p.ptr ); } + bool operator== ( const T* p ) const { return ( ptr == p ); } + bool operator!= ( const T* p ) const { return ( ptr != p ); } + bool operator!() const { return ( ptr == 0 ); } + operator T*() const { return ptr; } + + /** + * Returns the pointer. + * @return the pointer + */ + T* data() { return ptr; } + + /** + * Returns the pointer. + * @return the pointer + */ + const T* data() const { return ptr; } + + const T& operator*() const { return *ptr; } + T& operator*() { return *ptr; } + const T* operator->() const { return ptr; } + T* operator->() { return ptr; } + + /** + * Returns the number of references. + * @return the number of references + */ + int count() const { return ptr->_KShared_count(); } // for debugging purposes +private: + T* ptr; +}; + +#endif diff --git a/microkde/kdecore/kshell.cpp b/microkde/kdecore/kshell.cpp new file mode 100644 index 0000000..efc007a --- a/dev/null +++ b/microkde/kdecore/kshell.cpp @@ -0,0 +1,386 @@ +/* + This file is part of the KDE libraries + + Copyright (c) 2003 Oswald Buddenhagen + + 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 + +#include +#include + +#include +#ifndef _WIN32_ +#include +#endif +//US #include + +/*US +static int fromHex( QChar c ) +{ + if (c >= '0' && c <= '9') + return c - '0'; + else if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + else if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + return -1; +} + +inline static bool isQuoteMeta( uint c ) +{ +#if 0 // it's not worth it, especially after seeing gcc's asm output ... + static const uchar iqm[] = { + 0x00, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00 + }; // \'"$ + + return (c < sizeof(iqm) * 8) && (iqm[c / 8] & (1 << (c & 7))); +#else + return c == '\\' || c == '\'' || c == '"' || c == '$'; +#endif +} + +inline static bool isMeta( uint c ) +{ + static const uchar iqm[] = { + 0x00, 0x00, 0x00, 0x00, 0xdc, 0x07, 0x00, 0xd8, + 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x38 + }; // \'"$`<>|;&(){}*?# + + return (c < sizeof(iqm) * 8) && (iqm[c / 8] & (1 << (c & 7))); +} + +QStringList KShell::splitArgs( const QString &args, int flags, int *err ) +{ + QStringList ret; + bool firstword = flags & AbortOnMeta; + + for (uint pos = 0; ; ) { + QChar c; + do { + if (pos >= args.length()) + goto okret; + c = args.unicode()[pos++]; + } while (c.isSpace()); + QString cret; + if ((flags & TildeExpand) && c == '~') { + uint opos = pos; + for (; ; pos++) { + if (pos >= args.length()) + break; + c = args.unicode()[pos]; + if (c == '/' || c.isSpace()) + break; + if (isQuoteMeta( c )) { + pos = opos; + c = '~'; + goto notilde; + } + if ((flags & AbortOnMeta) && isMeta( c )) + goto metaerr; + } + QString ccret = homeDir( QConstString( args.unicode() + opos, pos - opos ).string() ); + if (ccret.isEmpty()) { + pos = opos; + c = '~'; + goto notilde; + } + if (pos >= args.length()) { + ret += ccret; + goto okret; + } + pos++; + if (c.isSpace()) { + ret += ccret; + firstword = false; + continue; + } + cret = ccret; + } + // before the notilde label, as a tilde does not match anyway + if (firstword) { + if (c == '_' || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) { + uint pos2 = pos; + QChar cc; + do + cc = args[pos2++]; + while (cc == '_' || (cc >= 'A' && cc <= 'Z') || + (cc >= 'a' && cc <= 'z') || (cc >= '0' && cc <= '9')); + if (cc == '=') + goto metaerr; + } + } + notilde: + do { + if (c == '\'') { + uint spos = pos; + do { + if (pos >= args.length()) + goto quoteerr; + c = args.unicode()[pos++]; + } while (c != '\''); + cret += QConstString( args.unicode() + spos, pos - spos - 1 ).string(); + } else if (c == '"') { + for (;;) { + if (pos >= args.length()) + goto quoteerr; + c = args.unicode()[pos++]; + if (c == '"') + break; + if (c == '\\') { + if (pos >= args.length()) + goto quoteerr; + c = args.unicode()[pos++]; + if (c != '"' && c != '\\' && + !((flags & AbortOnMeta) && (c == '$' || c == '`'))) + cret += '\\'; + } else if ((flags & AbortOnMeta) && (c == '$' || c == '`')) + goto metaerr; + cret += c; + } + } else if (c == '$' && args[pos] == '\'') { + pos++; + for (;;) { + if (pos >= args.length()) + goto quoteerr; + c = args.unicode()[pos++]; + if (c == '\'') + break; + if (c == '\\') { + if (pos >= args.length()) + goto quoteerr; + c = args.unicode()[pos++]; + switch (c) { + case 'a': cret += '\a'; break; + case 'b': cret += '\b'; break; + case 'e': cret += '\033'; break; + case 'f': cret += '\f'; break; + case 'n': cret += '\n'; break; + case 'r': cret += '\r'; break; + case 't': cret += '\t'; break; + case '\\': cret += '\\'; break; + case '\'': cret += '\''; break; + case 'c': cret += args[pos++] & 31; break; + case 'x': + { + int hv = fromHex( args[pos] ); + if (hv < 0) { + cret += "\\x"; + } else { + int hhv = fromHex( args[++pos] ); + if (hhv > 0) { + hv = hv * 16 + hhv; + pos++; + } + cret += QChar( hv ); + } + break; + } + default: + if (c >= '0' && c <= '7') { + int hv = c - '0'; + for (int i = 0; i < 2; i++) { + c = args[pos]; + if (c < '0' || c > '7') + break; + hv = hv * 8 + (c - '0'); + pos++; + } + cret += QChar( hv ); + } else { + cret += '\\'; + cret += c; + } + break; + } + } else + cret += c; + } + } else { + if (c == '\\') { + if (pos >= args.length()) + goto quoteerr; + c = args.unicode()[pos++]; + if (!c.isSpace() && + !((flags & AbortOnMeta) ? isMeta( c ) : isQuoteMeta( c ))) + cret += '\\'; + } else if ((flags & AbortOnMeta) && isMeta( c )) + goto metaerr; + cret += c; + } + if (pos >= args.length()) + break; + c = args.unicode()[pos++]; + } while (!c.isSpace()); + ret += cret; + firstword = false; + } + + okret: + if (err) + *err = NoError; + return ret; + + quoteerr: + if (err) + *err = BadQuoting; + return QStringList(); + + metaerr: + if (err) + *err = FoundMeta; + return QStringList(); +} + +inline static bool isSpecial( uint c ) +{ + static const uchar iqm[] = { + 0xff, 0xff, 0xff, 0xff, 0xdd, 0x07, 0x00, 0xd8, + 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x38 + }; // 0-32 \'"$`<>|;&(){}*?# + + return (c < sizeof(iqm) * 8) && (iqm[c / 8] & (1 << (c & 7))); +} + +QString KShell::joinArgs( const QStringList &args ) +{ + QChar q( '\'' ); + QString ret; + for (QStringList::ConstIterator it = args.begin(); it != args.end(); ++it) { + if (!ret.isEmpty()) + ret += ' '; + if (!(*it).length()) + ret.append( q ).append( q ); + else { + for (uint i = 0; i < (*it).length(); i++) + if (isSpecial((*it).unicode()[i])) { + QString tmp(*it); + tmp.replace( q, "'\\''" ); + ret += q; + tmp += q; + ret += tmp; + goto ex; + } + ret += *it; + ex: ; + } + } + return ret; +} + +QString KShell::joinArgs( const char * const *args, int nargs ) +{ + if (!args) + return QString::null; // well, QString::empty, in fact. qt sucks ;) + QChar q( '\'' ); + QString ret; + for (const char * const *argp = args; nargs && *argp; argp++, nargs--) { + if (!ret.isEmpty()) + ret += ' '; + if (!**argp) + ret.append( q ).append( q ); + else { + QString tmp( QFile::decodeName( *argp ) ); + for (uint i = 0; i < tmp.length(); i++) + if (isSpecial(tmp.unicode()[i])) { + tmp.replace( q, "'\\''" ); + ret += q; + tmp += q; + ret += tmp; + goto ex; + } + ret += tmp; + ex: ; + } + } + return ret; +} + +QString KShell::joinArgsDQ( const QStringList &args ) +{ + QChar q( '\'' ), sp( ' ' ), bs( '\\' ); + QString ret; + for (QStringList::ConstIterator it = args.begin(); it != args.end(); ++it) { + if (!ret.isEmpty()) + ret += sp; + if (!(*it).length()) + ret.append( q ).append( q ); + else { + for (uint i = 0; i < (*it).length(); i++) + if (isSpecial((*it).unicode()[i])) { + ret.append( '$' ).append( q ); + for (uint pos = 0; pos < (*it).length(); pos++) { + int c = (*it).unicode()[pos]; + if (c < 32) { + ret += bs; + switch (c) { + case '\a': ret += 'a'; break; + case '\b': ret += 'b'; break; + case '\033': ret += 'e'; break; + case '\f': ret += 'f'; break; + case '\n': ret += 'n'; break; + case '\r': ret += 'r'; break; + case '\t': ret += 't'; break; + case '\034': ret += 'c'; ret += '|'; break; + default: ret += 'c'; ret += c + '@'; break; + } + } else { + if (c == '\'' || c == '\\') + ret += bs; + ret += c; + } + } + ret.append( q ); + goto ex; + } + ret += *it; + ex: ; + } + } + return ret; +} +*/ + +QString KShell::tildeExpand( const QString &fname ) +{ + if (fname[0] == '~') { + int pos = fname.find( '/' ); + if (pos < 0) + return homeDir( QConstString( (QChar*)(fname.unicode() + 1), fname.length() - 1 ).string() ); + QString ret = homeDir( QConstString( (QChar*)(fname.unicode() + 1), pos - 1 ).string() ); + if (!ret.isNull()) + ret += QConstString( (QChar*)(fname.unicode() + pos), fname.length() - pos ).string(); + return ret; + } + return fname; +} + +QString KShell::homeDir( const QString &user ) +{ +#ifdef _WIN32_ + return QDir::homeDirPath(); +#else + if (user.isEmpty()) + return QFile::decodeName( getenv( "HOME" ) ); + struct passwd *pw = getpwnam( QFile::encodeName( user ).data() ); + if (!pw) + return QString::null; + return QFile::decodeName( pw->pw_dir ); +#endif +} diff --git a/microkde/kdecore/kshell.h b/microkde/kdecore/kshell.h new file mode 100644 index 0000000..35d8217 --- a/dev/null +++ b/microkde/kdecore/kshell.h @@ -0,0 +1,143 @@ +/* + This file is part of the KDE libraries + + Copyright (c) 2003 Oswald Buddenhagen + + 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. +*/ +#ifndef _KSHELL_H +#define _KSHELL_H + +#include +#include + +/** + * Provides some basic POSIX shell and bash functionality. + * @see KStringHandler + */ +namespace KShell { + + /** + * Flags for @ref splitArgs(). + */ + enum Options { + NoOptions = 0, + + /** + * Perform tilde expansion. + */ + TildeExpand = 1, + + /** + * Bail out if a non-quoting and not quoted shell meta character is encoutered. + * Meta characters are the command separators @p semicolon and @p ampersand, + * the redirection symbols @p less-than, @p greater-than and the @p pipe @p symbol, + * the grouping symbols opening and closing @p parens and @p braces, the command + * substitution symbol @p backquote, the generic substitution symbol @p dollar + * (if not followed by an apostrophe), the wildcards @p asterisk and + * @p question @p mark, and the comment symbol @p hash @p mark. Additionally, + * a variable assignment in the first word is recognized. + */ + AbortOnMeta = 2 + }; + + /** + * Status codes from @ref splitArgs() + */ + enum Errors { + /** + * Success. + */ + NoError = 0, + + /** + * Indicates a parsing error, like an unterminated quoted string. + */ + BadQuoting, + + /** + * The AbortOnMeta flag was set and a shell meta character + * was encoutered. + */ + FoundMeta + }; + + /** + * Splits @p cmd according to POSIX shell word splitting and quoting rules. + * Can optionally perform tilde expansion and/or abort if it finds shell + * meta characters it cannot process. + * + * @param cmd the command to split + * @param flags operation flags, see @ref Options + * @param err if not NULL, a status code will be stored at the pointer + * target, see @ref Errors + * @return a list of unquoted words or an empty list if an error occured + */ + QStringList splitArgs( const QString &cmd, int flags = 0, int *err = 0 ); + + /** + * Quotes and joins @p args together according to POSIX shell rules. + * + * @param args a list of strings to quote and join + * @return a command suitable for shell execution + */ + QString joinArgs( const QStringList &args ); + + /** + * Same as above, but $'' is used instead of '' for the quoting. + * The output is suitable for @ref splitArgs(), bash, zsh and possibly + * other bourne-compatible shells, but not for plain sh. The advantage + * is, that control characters (ASCII less than 32) are escaped into + * human-readable strings. + * + * @param args a list of strings to quote and join + * @return a command suitable for shell execution + */ + QString joinArgsDQ( const QStringList &args ); + + /** + * Quotes and joins @p argv together according to POSIX shell rules. + * + * @param argv an array of c strings to quote and join. + * The strings are expected to be in local-8-bit encoding. + * @param argc maximal number of strings in @p argv. if not supplied, + * @p argv must be null-terminated. + * @return a command suitable for shell execution + */ + QString joinArgs( const char * const *argv, int argc = -1 ); + + /** + * Performs tilde expansion on @p path. Interprets "~/path" and + * "~user/path". + * + * @param path the path to tilde-expand + * @return the expanded path + */ + QString tildeExpand( const QString &path ); + + /** + * Obtain a @p user's home directory. + * + * @param user The name of the user whose home dir should be obtained. + * An empty string denotes the current user. + * @return The user's home directory. + */ + QString homeDir( const QString &user ); + +} + + +#endif /* _KSHELL_H */ diff --git a/microkde/kdecore/kshortcut.h b/microkde/kdecore/kshortcut.h new file mode 100644 index 0000000..4813734 --- a/dev/null +++ b/microkde/kdecore/kshortcut.h @@ -0,0 +1,846 @@ +/* This file is part of the KDE libraries + Copyright (C) 2001,2002 Ellis Whitehead + + 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. +*/ + +#ifndef __KSHORTCUT_H +#define __KSHORTCUT_H +/*US +#include +#include + +class QKeyEvent; +class KKeyNative; +*/ +/** +* A KKey object represents a single key with possible modifiers +* (Shift, Ctrl, Alt, Win). It can represent both keys which are +* understood by Qt as well as those which are additionally supported +* by the underlying system (e.g. X11). +* @see KKeyNative +* @see KKeySequence +* @see KShortcut +*/ +/*US +class KKey +{ + public: +*/ + /** + * The number of flags. + * @see ModFlag + */ +/*US + enum { MOD_FLAG_COUNT = 4 }; + enum { QtWIN = (Qt::ALT << 1) }; +*/ + /** + * Flags to represent the modifiers. You can combine modifiers + * by ORing them. + */ +/*US + enum ModFlag { + SHIFT = 0x01, + CTRL = 0x02, + ALT = 0x04, + WIN = 0x08 + }; +*/ + /** + * Creates a new null KKey. + * @see clear() + * @see isNull() + * @see null() + */ +//US KKey(); + + /** + * Creates a new key for the given Qt key code. + * @param keyQt the qt keycode + * @see Qt::Key + */ +//US KKey( int keyQt ); + + /** + * Creates a new key from the first key code of the given key sequence. + * @param keySeq the key sequence that contains the key + */ +//US KKey( const QKeySequence& keySeq ); + + /** + * Extracts the key from the given key event. + * @param keyEvent the key event to get the key from + */ +//US KKey( const QKeyEvent* keyEvent ); + + /** + * Copy constructor. + */ +//US KKey( const KKey& key ); + + /** + * Creates a new key from the given description. The form of the description + * is "[modifier+[modifier+]]+key", for example "e", "CTRL+q" or + * "CTRL+ALT+DEL". Allowed modifiers are "SHIFT", "CTRL", "ALT", "WIN" and + * "META". "WIN" and "META" are equivalent. Modifiers are not case-sensitive. + * @param key the description of the key + * @see KKeyServer::Sym::init() + */ +//US KKey( const QString& key ); + /** + * @internal + */ +//US KKey( uint key, uint mod ); +//US ~KKey(); + + // Initialization methods + /** + * Clears the key. The key is null after calling this function. + * @see isNull() + */ +//US void clear(); + + /** + * Initializes the key with the given Qt key code. + * @param keyQt the qt keycode + * @return true if successful, false otherwise + * @see Qt::Key + */ +//US bool init( int keyQt ); + + /** + * Initializes the key with the first key code of the given key sequence. + * @param keySeq the key sequence that contains the key + * @return true if successful, false otherwise + */ +//US bool init( const QKeySequence& keySeq ); + + /** + * Initializes the key by extracting the code from the given key event. + * @param keyEvent the key event to get the key from + * @return true if successful, false otherwise + */ +//US bool init( const QKeyEvent* keyEvent ); + + /** + * Copies the given key. + * @param key the key to copy + * @return true if successful, false otherwise + */ +//US bool init( const KKey& key ); + + /** + * Initializes the key with the given description. The form of the description + * is "[modifier+[modifier+]]+key", for example "e", "CTRL+q" or + * "CTRL+ALT+DEL". Allowed modifiers are "SHIFT", "CTRL", "ALT", "WIN" and + * "META". "WIN" and "META" are equivalent. Modifiers are not case-sensitive. + * @param key the description of the key + * @return true if successful, false otherwise + * @see KKeyServer::Sym::init() + */ +//US bool init( const QString& ); + + /** + * @internal + */ +//US bool init( uint key, uint mod ); + + /** + * Copies the key. + */ +//US KKey& operator =( const KKey& key ) +//US { init( key ); return *this; } + + // Query methods. + /** + * Returns true if the key is null (after @ref clear() or empty + * constructor). + * @return true if the key is null + * @see clear() + * @see null() + */ +//US bool isNull() const; + + /** + * @internal + */ +//US bool isValidQt() const; + + /** + * @internal + */ +//US bool isValidNative() const; + + /** + * @internal + */ +//US uint sym() const; + /** + * @internal + */ +//US uint modFlags() const; + + // Comparison Methods + /** + * Compares this key with the given KKey object. Returns a negative + * number if the given KKey is larger, 0 if they are equal and + * a positive number this KKey is larger. The returned value + * is the difference between the symbol or, if the symbols + * are equal, the difference between the encoded modifiers. + * @param key the key to compare with this key + * @return a negative number if the given KKey is larger, 0 if + * they are equal and a positive number this KKey is larger + */ +//US int compare( const KKey& key ) const; + + /** + * Compares the symbol and modifiers of both keys. + * @see compare() + */ +//US bool operator == ( const KKey& key ) const +//US { return compare( key ) == 0; } + /** + * Compares the symbol and modifiers of both keys. + * @see compare() + */ +//US bool operator != ( const KKey& key ) const +//US { return compare( key ) != 0; } + /** + * Compares the symbol and modifiers of both keys. + * @see compare() + */ +//US bool operator < ( const KKey& key ) const +//US { return compare( key ) < 0; } + + // Conversion methods. + /** + * Returns the qt key code. + * @return the qt key code or 0 if there is no key set. + * @see Qt::Key + */ +//US int keyCodeQt() const; + + /** + * Returns a human-readable representation of the key in the form + * "modifier+key". + * @return the string representation of the key + */ +//US QString toString() const; + + /** + * @internal + */ +//US QString toStringInternal() const; + + // Operation methods + /** + * @internal + */ +//US void simplify(); + + /** + * Returns a null key. + * @return the null key + * @see isNull() + * @see clear() + */ +//US static KKey& null(); + + /** + * Returns a user-readable representation of the given modifiers. + * @param f the modifiers to convert + * @return the string representation of the modifiers + */ +//US static QString modFlagLabel( ModFlag f ); + +//US private: + /* + * Under X11, m_key will hold an X11 key symbol. + * For Qt/Embedded, it will hold the Qt key code. + */ + /** + * Returns the native key symbol value key. Under X11, this is the X + * keycode. Under Qt/Embedded, this is the Qt keycode. + * @see /usr/include/X11/keysymdef.h + * @see qnamespace.h + */ +//US uint m_sym; + /** + * m_mod holds the + */ +//US uint m_mod; + +//US private: +//US friend class KKeyNative; +//US}; + +/** +* A KKeySequence object holds a sequence of up to 4 keys. +* Ex: Ctrl+X,I +* @see KKey +* @see KShortcut +*/ + +//USclass KKeySequence +//US{ +//US public: + /// Defines the maximum length of the key sequence +//US enum { MAX_KEYS = 4 }; + + /** + * Create a new null key sequence. + * @see isNull() + * @see null() + * @see clear() + */ +//US KKeySequence(); + + /** + * Copies the given qt key sequence. + * @param keySeq the qt key sequence to copy + */ +//US KKeySequence( const QKeySequence& keySeq ); + + /** + * Create a new key sequence that only contains the given key. + * @param key the key to add + */ +//US KKeySequence( const KKey& key ); + + /** + * Create a new key sequence that only contains the given key. + * @param key the key to add + */ +//US KKeySequence( const KKeyNative& key ); + + /** + * Copies the given key sequence. + * @param keySeq the key sequence to copy + */ +//US KKeySequence( const KKeySequence& keySeq ); + + /** + * Creates a new key sequence that contains the given key sequence. + * The description consists of comma-separated keys as + * required by @ref KKey::KKey(const QString&). + * @param keySeq the description of the key + * @see KKeyServer::Sym::init() + * @see KKey::KKey(const QString&) + */ +//US KKeySequence( const QString& keySeq ); + +//US ~KKeySequence(); + + /** + * Clears the key sequence. The key sequence is null after calling this + * function. + * @see isNull() + */ +//US void clear(); + + /** + * Copies the given qt key sequence over this key sequence. + * @param keySeq the qt key sequence to copy + * @return true if successful, false otherwise + */ +//US bool init( const QKeySequence& keySeq ); + + /** + * Initializes the key sequence to only contain the given key. + * @param key the key to set + * @return true if successful, false otherwise + */ +//US bool init( const KKey& key ); + + /** + * Initializes the key sequence to only contain the given key. + * @param key the key to set + * @return true if successful, false otherwise + */ +//US bool init( const KKeyNative& key ); + + /** + * Copies the given key sequence over this key sequence. + * @param keySeq the key sequence to copy + * @return true if successful, false otherwise + */ +//US bool init( const KKeySequence& keySeq ); + + /** + * Initializes this key sequence to contain the given key sequence. + * The description consists of comma-separated keys as + * required by @ref KKey::KKey(const QString&). + * @param key the description of the key + * @return true if successful, false otherwise + * @see KKeyServer::Sym::init() + * @see KKey::KKey(const QString&) + */ +//US bool init( const QString& key ); + + /** + * Copy the given key sequence into this sequence. + */ +//US KKeySequence& operator =( const KKeySequence& seq ) +//US { init( seq ); return *this; } + + /** + * Returns the number of key strokes of this sequence. + * @return the number of key strokes + * @see MAX_KEYS + */ +//US uint count() const; + + /** + * Return the @p i'th key of this sequence, or a null key if there + * are less then i keys. + * @param i the key to retrieve + * @return the @p i'th key, or @ref KKey::null() if there are less + * than i keys + * @see MAX_KEYS + */ +//US const KKey& key( uint i ) const; + + /** + * @internal + */ +//US bool isTriggerOnRelease() const; + + /** + * Sets the @p i'th key of the sequence. You can not introduce gaps + * in a sequence, so you must use an @p i <= @ref count(). Also note that + * the maximum length of a key sequence is @ref MAX_KEYS. + * @param i the position of the new key (<= @ref count(), <= @ref MAX_KEYS) + * @param key the key to set + * @return true if successful, false otherwise + */ +//US bool setKey( uint i, const KKey& key ); + + /** + * @internal + */ +//US void setTriggerOnRelease( bool ); + + /** + * Returns true if the key sequence is null (after @ref clear() or empty + * constructor). + * @return true if the key sequence is null + * @see clear() + * @see null() + */ +//US bool isNull() const; + + /** + * Returns true if this key sequence begins with the given sequence. + * @param keySeq the key sequence to search + * @return true if this key sequence begins with the given sequence + */ +//US bool startsWith( const KKeySequence& keySeq ) const; + + /** + * Compares this object with the given key sequence. Returns a negative + * number if the given KKeySequence is larger, 0 if they are equal and + * a positive number this KKeySequence is larger. Key sequences are + * compared by comparing the individual keys, starting from the beginning + * until an unequal key has been found. If a sequence contains more + * keys, it is considered larger. + * @param keySeq the key sequence to compare to + * @return a negative number if the given KKeySequence is larger, 0 if + * they are equal and a positive number this KKeySequence is larger + * @see KKey::sequence + */ +//US int compare( const KKeySequence& keySeq ) const; + + /** + * Compares the keys of both sequences. + * @see compare() + */ +//US bool operator == ( const KKeySequence& seq ) const +//US { return compare( seq ) == 0; } + + /** + * Compares the keys of both sequences. + * @see compare() + */ +//US bool operator != ( const KKeySequence& seq ) const +//US { return compare( seq ) != 0; } + + /** + * Compares the keys of both sequences. + * @see compare() + */ +//US bool operator < ( const KKeySequence& seq ) const +//US { return compare( seq ) < 0; } + // TODO: consider adding Qt::SequenceMatch matches(...) methods for QKeySequence equivalence + + /** + * Converts this key sequence to a QKeySequence. + * @return the QKeySequence + */ +//US QKeySequence qt() const; + + /** + * Returns the qt key code of the first key. + * @return the qt key code of the first key + * @see Qt::Key + * @see KKey::keyCodeQt() + */ +//US int keyCodeQt() const; + + /** + * Returns the key sequence as a number of key presses as + * returned by @ref KKey::toString(), seperated by commas. + * @return the string represenation of this key sequence + * @see KKey::toString() + */ +//US QString toString() const; + + /** + * @internal + */ +//US QString toStringInternal() const; + + /** + * Returns a null key sequence. + * @return the null key sequence + * @see isNull() + * @see clear() + */ +//US static KKeySequence& null(); + +//US protected: +//US uchar m_nKeys; +//US uchar m_bTriggerOnRelease; + // BCI: m_rgvar should be renamed to m_rgkey for KDE 4.0 +//US KKey m_rgvar[MAX_KEYS]; + +//US private: +//US class KKeySequencePrivate* d; +//US friend class KKeyNative; +//US}; + +/** +* The KShortcut class is used to represent a keyboard shortcut to an action. +* A shortcut is normally a single key with modifiers, such as Ctrl+V. +* A KShortcut object may also contain an alternate key which will also +* activate the action it's associated to, as long as no other actions have +* defined that key as their primary key. Ex: Ctrl+V;Shift+Insert. +*/ + +class KShortcut +{ + public: + /** + * The maximum number of key sequences that can be contained in + * a KShortcut. + */ + enum { MAX_SEQUENCES = 2 }; + + /** + * Creates a new null shortcut. + * @see null() + * @see isNull() + * @see clear() + */ + KShortcut() {} + + /** + * Creates a new shortcut with the given Qt key code + * as the only key sequence. + * @param keyQt the qt keycode + * @see Qt::Key + */ + KShortcut( int keyQt ) {} + + /** + * Creates a new shortcut that contains only the given qt key + * sequence. + * @param keySeq the qt key sequence to add + */ +//US KShortcut( const QKeySequence& keySeq ) {} + + /** + * Creates a new shortcut that contains only the given key + * in its only sequence. + * @param key the key to add + */ +//US KShortcut( const KKey& key ); + + /** + * Creates a new shortcut that contains only the given key + * sequence. + * @param keySeq the key sequence to add + */ +//US KShortcut( const KKeySequence& keySeq ); + + /** + * Copies the given shortcut. + * @param shortcut the shortcut to add + */ +//US KShortcut( const KShortcut& shortcut ); + + /** + * Creates a new key sequence that contains the given key sequence. + * The description consists of semicolon-separated keys as + * used in @ref KKeySequence::KKeySequence(const QString&). + * @param shortcut the description of the key + * @see KKeySequence::KKeySequence(const QString&) + */ + KShortcut( const char* shortcut ) {} + + /** + * Creates a new key sequence that contains the given key sequence. + * The description consists of semicolon-separated keys as + * used in @ref KKeySequence::KKeySequence(const QString&). + * @param shortcut the description of the key + * @see KKeySequence::KKeySequence(const QString&) + */ + KShortcut( const QString& shortcut ) {} + ~KShortcut() {} + + /** + * Clears the shortcut. The shortcut is null after calling this + * function. + * @see isNull() + */ +//US void clear(); + + /** + * Initializes the shortcut with the given Qt key code + * as the only key sequence. + * @param keyQt the qt keycode + * @see Qt::Key + */ +//US bool init( int keyQt ); + + /** + * Initializes the shortcut with the given qt key sequence. + * @param keySeq the qt key sequence to add + */ +//US bool init( const QKeySequence& keySeq ); + + /** + * Initializes the shortcut with the given key as its only sequence. + * @param key the key to add + */ +//US bool init( const KKey& key ); + + /** + * Initializes the shortcut with the given qt key sequence. + * @param keySeq the qt key sequence to add + */ +//US bool init( const KKeySequence& keySeq ); + + /** + * Copies the given shortcut. + * @param shortcut the shortcut to add + */ +//US bool init( const KShortcut& shortcut ); + + /** + * Initializes the key sequence with the given key sequence. + * The description consists of semicolon-separated keys as + * used in @ref KKeySequence::KKeySequence(const QString&). + * @param shortcut the description of the key + * @see KKeySequence::KKeySequence(const QString&) + */ +//US bool init( const QString& shortcut ); + + /** + * Copies the given shortcut over this shortcut. + */ +//US KShortcut& operator =( const KShortcut& cut ) +//US { init( cut ); return *this; } + + /** + * Returns the number of sequences that are in this + * shortcut. + * @return the number of sequences + * @ref MAX_SEQUENCES + */ +//US uint count() const; + + /** + * Returns the @p i'th key sequence of this shortcut. + * @param i the number of the key sequence to retrieve + * @return the @p i'th sequence or @ref KKeySequence::null() if + * there are less than @p i key sequences + * @ref MAX_SEQUENCES + */ +//US const KKeySequence& seq( uint i ) const; + + /** + * Returns the key code of the first key sequence, or + * null if there is no first key sequence. + * @return the key code of the first sequence's first key + * @see Qt::Key + * @see KKeySequence::keyCodeQt() + */ +//US int keyCodeQt() const; + + /** + * Returns true if the shortcut is null (after @ref clear() or empty + * constructor). + * @return true if the shortcut is null + * @see clear() + * @see null() + */ + bool isNull() const { return true; } + + /** + * Compares this object with the given shortcut. Returns a negative + * number if the given shortcut is larger, 0 if they are equal and + * a positive number this shortcut is larger. Shortcuts are + * compared by comparing the individual key sequences, starting from the + * beginning until an unequal key sequences has been found. If a shortcut + * contains more key sequences, it is considered larger. + * @param shortcut the shortcut to compare to + * @return a negative number if the given KShortcut is larger, 0 if + * they are equal and a positive number this KShortcut is larger + * @see KKey::compare() + * @see KKeyShortcut::compare() + */ +//US int compare( const KShortcut& shortcut ) const; + + /** + * Compares the sequences of both shortcuts. + * @see compare() + */ +//US bool operator == ( const KShortcut& cut ) const +//US { return compare( cut ) == 0; } + + /** + * Compares the sequences of both shortcuts. + * @see compare() + */ +//US bool operator != ( const KShortcut& cut ) const +//US { return compare( cut ) != 0; } + + /** + * Compares the sequences of both shortcuts. + * @see compare() + */ +//US bool operator < ( const KShortcut& cut ) const +//US { return compare( cut ) < 0; } + + /** + * Checks whether this shortcut contains a sequence that starts + * with the given key. + * @param key the key to check + * @return true if a key sequence starts with the key + */ +//US bool contains( const KKey& key ) const; + + /** + * Checks whether this shortcut contains a sequence that starts + * with the given key. + * @param key the key to check + * @return true if a key sequence starts with the key + */ +//US bool contains( const KKeyNative& key ) const; + + /** + * Checks whether this shortcut contains the given sequence. + * @param keySeq the key sequence to check + * @return true if the shortcut has the given key sequence + */ +//US bool contains( const KKeySequence& keySeq ) const; + + /** + * Sets the @p i'th key sequence of the shortcut. You can not introduce + * gaps in the list of sequences, so you must use an @i <= @ref count(). + * Also note that the maximum number of key sequences is @ref MAX_SEQUENCES. + * @param i the position of the new key sequence(<= @ref count(), + * <= @ref MAX_SEQUENCES) + * @param keySeq the key sequence to set + * @return true if successful, false otherwise + */ +//US bool setSeq( uint i, const KKeySequence& keySeq ); + + /** + * Appends the given key sequence. + * @param keySeq the key sequence to add + * @return true if successful, false otherwise + * @see setSeq() + * @see MAX_SEQUENCES + */ +//US bool append( const KKeySequence& keySeq ); + + /** + * Appends the given key + * @param spec the key to add + * @return true if successful, false otherwise + * @see setSeq() + * @see MAX_SEQUENCES + * @since 3.2 + */ +//US bool append( const KKey& spec ); + + /** + * Appends the sequences from the given shortcut. + * @param cut the shortcut to append + * @return true if successful, false otherwise + * @see MAX_SEQUENCES + * @since 3.2 + */ +//US bool append( const KShortcut& cut ); + + /** + * Converts this shortcut to a key sequence. The first key sequence + * will be taken. + */ +//US operator QKeySequence () const; + + /** + * Returns a description of the shortcut as semicolon-separated + * ket sequences, as returned by @ref KKeySequence::toString(). + * @return the string represenation of this shortcut + * @see KKey::toString() + * @see KKeySequence::toString() + */ +//US QString toString() const; + + /** + * @internal + */ + QString toStringInternal( const KShortcut* pcutDefault = 0 ) const + { + return "EMPTY IMPL."; + } + + /** + * Returns a null shortcut. + * @return the null shortcut + * @see isNull() + * @see clear() + */ +//US static KShortcut& null(); + +//US protected: +//US uint m_nSeqs; +//US KKeySequence m_rgseq[MAX_SEQUENCES]; + +//US private: +//US class KShortcutPrivate* d; +//US friend class KKeyNative; + +//US#ifndef KDE_NO_COMPAT +//US public: +//US operator int () const { return keyCodeQt(); } +//US#endif +}; + +#endif // __KSHORTCUT_H diff --git a/microkde/kdecore/kstandarddirs.cpp b/microkde/kdecore/kstandarddirs.cpp new file mode 100644 index 0000000..5abe05c --- a/dev/null +++ b/microkde/kdecore/kstandarddirs.cpp @@ -0,0 +1,1620 @@ +/* This file is part of the KDE libraries + Copyright (C) 1999 Sirtaj Singh Kang + Copyright (C) 1999 Stephan Kulow + Copyright (C) 1999 Waldo Bastian + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + 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. +*/ + +/* + * Author: Stephan Kulow and Sirtaj Singh Kang + * Version: $Id$ + * Generated: Thu Mar 5 16:05:28 EST 1998 + */ + +//US #include "config.h" + +#include +#include +//US#include +//US #ifdef HAVE_SYS_STAT_H +//US #include +//US #endif +//US#include +//US#include +//US#include + +#include +#include +#include +#include +#include +#include +#include + +#include "kstandarddirs.h" +#include "kconfig.h" +#include "kdebug.h" +//US #include "kinstance.h" +#include "kshell.h" +//US#include +//US#include + +//US +QString KStandardDirs::mAppDir = QString::null; + + +template class QDict; + +#if 0 +#include +void ddd( QString op ) +{ + static QTextEdit * dot = 0; + if ( ! dot ) + dot = new QTextEdit(); + + dot->show(); + + dot->append( op ); + +} +#endif +class KStandardDirs::KStandardDirsPrivate +{ +public: + KStandardDirsPrivate() + : restrictionsActive(false), + dataRestrictionActive(false) + { } + + bool restrictionsActive; + bool dataRestrictionActive; + QAsciiDict restrictions; + QStringList xdgdata_prefixes; + QStringList xdgconf_prefixes; +}; + +static const char* const types[] = {"html", "icon", "apps", "sound", + "data", "locale", "services", "mime", + "servicetypes", "config", "exe", + "wallpaper", "lib", "pixmap", "templates", + "module", "qtplugins", + "xdgdata-apps", "xdgdata-dirs", "xdgconf-menu", 0 }; + +static int tokenize( QStringList& token, const QString& str, + const QString& delim ); + +KStandardDirs::KStandardDirs( ) : addedCustoms(false) +{ + d = new KStandardDirsPrivate; + dircache.setAutoDelete(true); + relatives.setAutoDelete(true); + absolutes.setAutoDelete(true); + savelocations.setAutoDelete(true); + addKDEDefaults(); +} + +KStandardDirs::~KStandardDirs() +{ + delete d; +} + +bool KStandardDirs::isRestrictedResource(const char *type, const QString& relPath) const +{ + if (!d || !d->restrictionsActive) + return false; + + if (d->restrictions[type]) + return true; + + if (strcmp(type, "data")==0) + { + applyDataRestrictions(relPath); + if (d->dataRestrictionActive) + { + d->dataRestrictionActive = false; + return true; + } + } + return false; +} + +void KStandardDirs::applyDataRestrictions(const QString &relPath) const +{ + QString key; + int i = relPath.find('/'); + if (i != -1) + key = "data_"+relPath.left(i); + else + key = "data_"+relPath; + + if (d && d->restrictions[key.latin1()]) + d->dataRestrictionActive = true; +} + + +QStringList KStandardDirs::allTypes() const +{ + QStringList list; + for (int i = 0; types[i] != 0; ++i) + list.append(QString::fromLatin1(types[i])); + return list; +} + +void KStandardDirs::addPrefix( const QString& _dir ) +{ + if (_dir.isNull()) + return; + + QString dir = _dir; + if (dir.at(dir.length() - 1) != '/') + dir += '/'; + + if (!prefixes.contains(dir)) { + prefixes.append(dir); + dircache.clear(); + } +} + +void KStandardDirs::addXdgConfigPrefix( const QString& _dir ) +{ + if (_dir.isNull()) + return; + + QString dir = _dir; + if (dir.at(dir.length() - 1) != '/') + dir += '/'; + + if (!d->xdgconf_prefixes.contains(dir)) { + d->xdgconf_prefixes.append(dir); + dircache.clear(); + } +} + +void KStandardDirs::addXdgDataPrefix( const QString& _dir ) +{ + if (_dir.isNull()) + return; + + QString dir = _dir; + if (dir.at(dir.length() - 1) != '/') + dir += '/'; + + if (!d->xdgdata_prefixes.contains(dir)) { + d->xdgdata_prefixes.append(dir); + dircache.clear(); + } +} + + +QString KStandardDirs::kfsstnd_prefixes() +{ + return prefixes.join(":"); +} + +bool KStandardDirs::addResourceType( const char *type, + const QString& relativename ) +{ + if (relativename.isNull()) + return false; + + QStringList *rels = relatives.find(type); + if (!rels) { + rels = new QStringList(); + relatives.insert(type, rels); + } + QString copy = relativename; + if (copy.at(copy.length() - 1) != '/') + copy += '/'; + if (!rels->contains(copy)) { + rels->prepend(copy); + dircache.remove(type); // clean the cache + return true; + } + return false; +} + +bool KStandardDirs::addResourceDir( const char *type, + const QString& absdir) +{ + QStringList *paths = absolutes.find(type); + if (!paths) { + paths = new QStringList(); + absolutes.insert(type, paths); + } + QString copy = absdir; + if (copy.at(copy.length() - 1) != '/') + copy += '/'; + + if (!paths->contains(copy)) { + paths->append(copy); + dircache.remove(type); // clean the cache + return true; + } + return false; +} + +QString KStandardDirs::findResource( const char *type, + const QString& filename ) const +{ + if (filename.at(0) == '/') + return filename; // absolute dirs are absolute dirs, right? :-/ + +#if 0 +kdDebug() << "Find resource: " << type << endl; +for (QStringList::ConstIterator pit = prefixes.begin(); + pit != prefixes.end(); + pit++) +{ + kdDebug() << "Prefix: " << *pit << endl; +} +#endif + + QString dir = findResourceDir(type, filename); + if (dir.isNull()) + return dir; + else return dir + filename; +} +/*US +static Q_UINT32 updateHash(const QString &file, Q_UINT32 hash) +{ + QCString cFile = QFile::encodeName(file); +//US struct stat buff; +//US if ((access(cFile, R_OK) == 0) && +//US (stat( cFile, &buff ) == 0) && +//US (S_ISREG( buff.st_mode ))) + QFileInfo pathfnInfo(cFile); + if (( pathfnInfo.isReadable() == true ) && + ( pathfnInfo.isFile()) ) + { +//US hash = hash + (Q_UINT32) buff.st_ctime; + hash = hash + (Q_UINT32) pathfnInfo.lastModified(); + } + return hash; +} +*/ +/*US +Q_UINT32 KStandardDirs::calcResourceHash( const char *type, + const QString& filename, bool deep) const +{ + Q_UINT32 hash = 0; + + if (filename.at(0) == '/') + { + // absolute dirs are absolute dirs, right? :-/ + return updateHash(filename, hash); + } + if (d && d->restrictionsActive && (strcmp(type, "data")==0)) + applyDataRestrictions(filename); + QStringList candidates = resourceDirs(type); + QString fullPath; + + for (QStringList::ConstIterator it = candidates.begin(); + it != candidates.end(); it++) + { + hash = updateHash(*it + filename, hash); + if (!deep && hash) + return hash; + } + return hash; +} +*/ + +QStringList KStandardDirs::findDirs( const char *type, + const QString& reldir ) const +{ + QStringList list; + + checkConfig(); + + if (d && d->restrictionsActive && (strcmp(type, "data")==0)) + applyDataRestrictions(reldir); + QStringList candidates = resourceDirs(type); + QDir testdir; + + for (QStringList::ConstIterator it = candidates.begin(); + it != candidates.end(); it++) { + testdir.setPath(*it + reldir); + if (testdir.exists()) + list.append(testdir.absPath() + '/'); + } + + return list; +} + +QString KStandardDirs::findResourceDir( const char *type, + const QString& filename) const +{ +#ifndef NDEBUG + if (filename.isEmpty()) { + kdWarning() << "filename for type " << type << " in KStandardDirs::findResourceDir is not supposed to be empty!!" << endl; + return QString::null; + } +#endif + + if (d && d->restrictionsActive && (strcmp(type, "data")==0)) + applyDataRestrictions(filename); + QStringList candidates = resourceDirs(type); + QString fullPath; + + for (QStringList::ConstIterator it = candidates.begin(); + it != candidates.end(); it++) + if (exists(*it + filename)) + return *it; + +#ifndef NDEBUG + if(false && type != "locale") + kdDebug() << "KStdDirs::findResDir(): can't find \"" << filename << "\" in type \"" << type << "\"." << endl; +#endif + + return QString::null; +} + +bool KStandardDirs::exists(const QString &fullPath) +{ +//US struct stat buff; + QFileInfo fullPathInfo(QFile::encodeName(fullPath)); + +//US if (access(QFile::encodeName(fullPath), R_OK) == 0 && fullPathInfo.isReadable()) + if (fullPathInfo.isReadable()) + { + if (fullPath.at(fullPath.length() - 1) != '/') { +//US if (S_ISREG( buff.st_mode )) + if (fullPathInfo.isFile()) + return true; + } + else { +//US if (S_ISDIR( buff.st_mode )) + if (fullPathInfo.isDir()) + return true; + } + } + return false; +} + +static void lookupDirectory(const QString& path, const QString &relPart, + const QRegExp ®exp, + QStringList& list, + QStringList& relList, + bool recursive, bool uniq) +{ + QString pattern = regexp.pattern(); + if (recursive || pattern.contains('?') || pattern.contains('*')) + { + // We look for a set of files. +//US DIR *dp = opendir( QFile::encodeName(path)); + QDir dp(QFile::encodeName(path)); + if (!dp.exists()) + return; + static int iii = 0; + ++iii; + if ( iii == 5 ) + abort(); + assert(path.at(path.length() - 1) == '/'); + +//US struct dirent *ep; +//US struct stat buff; + + QString _dot("."); + QString _dotdot(".."); + +//US while( ( ep = readdir( dp ) ) != 0L ) + QStringList direntries = dp.entryList(); + QStringList::Iterator it = direntries.begin(); + + while ( it != list.end() ) // for each file... + { + +//US QString fn( QFile::decodeName(ep->d_name)); + QString fn = (*it); // dp.entryList already decodes + it++; + if ( fn.isNull() ) + break; + + if (fn == _dot || fn == _dotdot || fn.at(fn.length() - 1).latin1() == '~' ) + continue; + +/*US + if (!recursive && !regexp.exactMatch(fn)) + continue; // No match +*/ +//US this should do the same: + int pos = regexp.match(fn); + if (!recursive && !pos == 0) + continue; // No match + + QString pathfn = path + fn; +/*US + if ( stat( QFile::encodeName(pathfn), &buff ) != 0 ) { + kdDebug() << "Error stat'ing " << pathfn << " : " << perror << endl; + continue; // Couldn't stat (e.g. no read permissions) + } + + if ( recursive ) + { + if ( S_ISDIR( buff.st_mode )) { + lookupDirectory(pathfn + '/', relPart + fn + '/', regexp, list, relList, recursive, uniq); + } +*/ +//US replacement: + QFileInfo pathfnInfo(QFile::encodeName(pathfn)); + if ( pathfnInfo.isReadable() == false ) + { +//US kdDebug() << "Error stat'ing " << pathfn << " : " << perror << endl; + continue; // Couldn't stat (e.g. no read permissions) + } + + if ( recursive ) + { + if ( pathfnInfo.isDir()) { + lookupDirectory(pathfn + '/', relPart + fn + '/', regexp, list, relList, recursive, uniq); + } + + +/*US + if (!regexp.exactMatch(fn)) + continue; // No match +*/ +//US this should do the same: + pos = regexp.match(fn); + if (!pos == 0) + continue; // No match + } + +//US if ( S_ISREG( buff.st_mode)) + if ( pathfnInfo.isFile()) + { + if (!uniq || !relList.contains(relPart + fn)) + { + list.append( pathfn ); + relList.append( relPart + fn ); + } + } + } +//US closedir( dp ); + } + else + { + // We look for a single file. + QString fn = pattern; + QString pathfn = path + fn; +//US struct stat buff; + QFileInfo pathfnInfo(QFile::encodeName(pathfn)); + + +//US if ( stat( QFile::encodeName(pathfn), &buff ) != 0 ) + if ( pathfnInfo.isReadable() == false ) + return; // File not found + +//US if ( S_ISREG( buff.st_mode)) + if ( pathfnInfo.isFile()) + { + if (!uniq || !relList.contains(relPart + fn)) + { + list.append( pathfn ); + relList.append( relPart + fn ); + } + } + } +} + +static void lookupPrefix(const QString& prefix, const QString& relpath, + const QString& relPart, + const QRegExp ®exp, + QStringList& list, + QStringList& relList, + bool recursive, bool uniq) +{ + if (relpath.isNull()) { + lookupDirectory(prefix, relPart, regexp, list, + relList, recursive, uniq); + return; + } + QString path; + QString rest; + + if (relpath.length()) + { + int slash = relpath.find('/'); + if (slash < 0) + rest = relpath.left(relpath.length() - 1); + else { + path = relpath.left(slash); + rest = relpath.mid(slash + 1); + } + } + assert(prefix.at(prefix.length() - 1) == '/'); + +//US struct stat buff; + + if (path.contains('*') || path.contains('?')) { + QRegExp pathExp(path, true, true); +//US DIR *dp = opendir( QFile::encodeName(prefix) ); + QDir dp(QFile::encodeName(prefix)); + +//US if (!dp) + if (!dp.exists()) + { + return; + } + +//US struct dirent *ep; + + QString _dot("."); + QString _dotdot(".."); + +//US while( ( ep = readdir( dp ) ) != 0L ) + QStringList direntries = dp.entryList(); + QStringList::Iterator it = direntries.begin(); + + while ( it != list.end() ) // for each file... + { +//US QString fn( QFile::decodeName(ep->d_name)); + QString fn = (*it); // dp.entryList() already encodes the strings + it++; + + if (fn == _dot || fn == _dotdot || fn.at(fn.length() - 1) == '~') + continue; + +#ifdef DESKTOP_VERSION + + if (pathExp.search(fn) == -1) + continue; // No match + +#else +//US this should do the same: + if (pathExp.find(fn, 0) == -1) + continue; // No match +#endif + QString rfn = relPart+fn; + fn = prefix + fn; +//US if ( stat( QFile::encodeName(fn), &buff ) != 0 ) + QFileInfo fnInfo(QFile::encodeName(fn)); + if ( fnInfo.isReadable() == false ) + { +//US kdDebug() << "Error statting " << fn << " : " << perror << endl; + continue; // Couldn't stat (e.g. no permissions) + } +//US if ( S_ISDIR( buff.st_mode )) + if ( fnInfo.isDir() ) + + lookupPrefix(fn + '/', rest, rfn + '/', regexp, list, relList, recursive, uniq); + } + +//US closedir( dp ); + } else { + // Don't stat, if the dir doesn't exist we will find out + // when we try to open it. + lookupPrefix(prefix + path + '/', rest, + relPart + path + '/', regexp, list, + relList, recursive, uniq); + } +} + +QStringList +KStandardDirs::findAllResources( const char *type, + const QString& filter, + bool recursive, + bool uniq, + QStringList &relList) const +{ + QStringList list; + if (filter.at(0) == '/') // absolute paths we return + { + list.append( filter); + return list; + } + + QString filterPath; + QString filterFile; + + if (filter.length()) + { + int slash = filter.findRev('/'); + if (slash < 0) + filterFile = filter; + else { + filterPath = filter.left(slash + 1); + filterFile = filter.mid(slash + 1); + } + } + checkConfig(); + + if (d && d->restrictionsActive && (strcmp(type, "data")==0)) + applyDataRestrictions(filter); + QStringList candidates = resourceDirs(type); + if (filterFile.isEmpty()) + filterFile = "*"; + + QRegExp regExp(filterFile, true, true); + for (QStringList::ConstIterator it = candidates.begin(); + it != candidates.end(); it++) + { + lookupPrefix(*it, filterPath, "", regExp, list, + relList, recursive, uniq); + } + return list; +} + +QStringList +KStandardDirs::findAllResources( const char *type, + const QString& filter, + bool recursive, + bool uniq) const +{ + QStringList relList; + return findAllResources(type, filter, recursive, uniq, relList); +} + +QString +KStandardDirs::realPath(const QString &dirname) +{ +#ifdef _WIN32_ + return dirname; +#else +//US char realpath_buffer[MAXPATHLEN + 1]; +//US memset(realpath_buffer, 0, MAXPATHLEN + 1); + char realpath_buffer[250 + 1]; + memset(realpath_buffer, 0, 250 + 1); + + /* If the path contains symlinks, get the real name */ + if (realpath( QFile::encodeName(dirname).data(), realpath_buffer) != 0) { + // succes, use result from realpath + int len = strlen(realpath_buffer); + realpath_buffer[len] = '/'; + realpath_buffer[len+1] = 0; + return QFile::decodeName(realpath_buffer); + } + + return dirname; +#endif +} +/*US +void KStandardDirs::createSpecialResource(const char *type) +{ + char hostname[256]; + hostname[0] = 0; + gethostname(hostname, 255); + QString dir = QString("%1%2-%3").arg(localkdedir()).arg(type).arg(hostname); + char link[1024]; + link[1023] = 0; + int result = readlink(QFile::encodeName(dir).data(), link, 1023); + if ((result == -1) && (errno == ENOENT)) + { + QString srv = findExe(QString::fromLatin1("lnusertemp"), KDEDIR+QString::fromLatin1("/bin")); + if (srv.isEmpty()) + srv = findExe(QString::fromLatin1("lnusertemp")); + if (!srv.isEmpty()) + { + system(QFile::encodeName(srv)+" "+type); + result = readlink(QFile::encodeName(dir).data(), link, 1023); + } + } + if (result > 0) + { + link[result] = 0; + if (link[0] == '/') + dir = QFile::decodeName(link); + else + dir = QDir::cleanDirPath(dir+QFile::decodeName(link)); + } + addResourceDir(type, dir+'/'); +} +*/ + +QStringList KStandardDirs::resourceDirs(const char *type) const +{ + QStringList *candidates = dircache.find(type); + + if (!candidates) { // filling cache +/*US + if (strcmp(type, "socket") == 0) + const_cast(this)->createSpecialResource(type); + else if (strcmp(type, "tmp") == 0) + const_cast(this)->createSpecialResource(type); + else if (strcmp(type, "cache") == 0) + const_cast(this)->createSpecialResource(type); +*/ + QDir testdir; + + candidates = new QStringList(); + QStringList *dirs; + + bool restrictionActive = false; + if (d && d->restrictionsActive) + { + if (d->dataRestrictionActive) + restrictionActive = true; + else if (d->restrictions["all"]) + restrictionActive = true; + else if (d->restrictions[type]) + restrictionActive = true; + d->dataRestrictionActive = false; // Reset + } + + dirs = relatives.find(type); + if (dirs) + { + bool local = true; + const QStringList *prefixList = 0; + if (strncmp(type, "xdgdata-", 8) == 0) + prefixList = &(d->xdgdata_prefixes); + else if (strncmp(type, "xdgconf-", 8) == 0) + prefixList = &(d->xdgconf_prefixes); + else + prefixList = &prefixes; + + for (QStringList::ConstIterator pit = prefixList->begin(); + pit != prefixList->end(); + pit++) + { + for (QStringList::ConstIterator it = dirs->begin(); + it != dirs->end(); ++it) { + QString path = realPath(*pit + *it); + testdir.setPath(path); + if (local && restrictionActive) + continue; + if ((local || testdir.exists()) && !candidates->contains(path)) + candidates->append(path); + } + local = false; + } + } + dirs = absolutes.find(type); + if (dirs) + for (QStringList::ConstIterator it = dirs->begin(); + it != dirs->end(); ++it) + { + testdir.setPath(*it); + if (testdir.exists()) + { + QString filename = realPath(*it); + if (!candidates->contains(filename)) + candidates->append(filename); + } + } + dircache.insert(type, candidates); + } + +#if 0 + kdDebug() << "found dirs for resource " << type << ":" << endl; + for (QStringList::ConstIterator pit = candidates->begin(); + pit != candidates->end(); + pit++) + { + fprintf(stderr, "%s\n", (*pit).latin1()); + } +#endif + + + return *candidates; +} + +/*US +QString KStandardDirs::findExe( const QString& appname, + const QString& pstr, bool ignore) +{ + QFileInfo info; + + // absolute path ? + if (appname.startsWith(QString::fromLatin1("/"))) + { + info.setFile( appname ); + if( info.exists() && ( ignore || info.isExecutable() ) + && info.isFile() ) { + return appname; + } + return QString::null; + } + +//US QString p = QString("%1/%2").arg(__KDE_BINDIR).arg(appname); + QString p = QString("%1/%2").arg(appname).arg(appname); + qDebug("KStandardDirs::findExe this is probably wrong"); + + info.setFile( p ); + if( info.exists() && ( ignore || info.isExecutable() ) + && ( info.isFile() || info.isSymLink() ) ) { + return p; + } + + QStringList tokens; + p = pstr; + + if( p.isNull() ) { + p = getenv( "PATH" ); + } + + tokenize( tokens, p, ":\b" ); + + // split path using : or \b as delimiters + for( unsigned i = 0; i < tokens.count(); i++ ) { + p = tokens[ i ]; + + if ( p[ 0 ] == '~' ) + { + int len = p.find( '/' ); + if ( len == -1 ) + len = p.length(); + if ( len == 1 ) + p.replace( 0, 1, QDir::homeDirPath() ); + else + { + QString user = p.mid( 1, len - 1 ); + struct passwd *dir = getpwnam( user.local8Bit().data() ); + if ( dir && strlen( dir->pw_dir ) ) + p.replace( 0, len, QString::fromLocal8Bit( dir->pw_dir ) ); + } + } + + p += "/"; + p += appname; + + // Check for executable in this tokenized path + info.setFile( p ); + + if( info.exists() && ( ignore || info.isExecutable() ) + && ( info.isFile() || info.isSymLink() ) ) { + return p; + } + } + + // If we reach here, the executable wasn't found. + // So return empty string. + + return QString::null; +} + +int KStandardDirs::findAllExe( QStringList& list, const QString& appname, + const QString& pstr, bool ignore ) +{ + QString p = pstr; + QFileInfo info; + QStringList tokens; + + if( p.isNull() ) { + p = getenv( "PATH" ); + } + + list.clear(); + tokenize( tokens, p, ":\b" ); + + for ( unsigned i = 0; i < tokens.count(); i++ ) { + p = tokens[ i ]; + p += "/"; + p += appname; + + info.setFile( p ); + + if( info.exists() && (ignore || info.isExecutable()) + && info.isFile() ) { + list.append( p ); + } + + } + + return list.count(); +} +*/ + +static int tokenize( QStringList& tokens, const QString& str, + const QString& delim ) +{ + int len = str.length(); + QString token = ""; + + for( int index = 0; index < len; index++) + { + if ( delim.find( str[ index ] ) >= 0 ) + { + tokens.append( token ); + token = ""; + } + else + { + token += str[ index ]; + } + } + if ( token.length() > 0 ) + { + tokens.append( token ); + } + + return tokens.count(); +} + +QString KStandardDirs::kde_default(const char *type) { + if (!strcmp(type, "data")) + return "apps/"; + if (!strcmp(type, "html")) + return "share/doc/HTML/"; + if (!strcmp(type, "icon")) + return "share/icons/"; + if (!strcmp(type, "config")) + return "config/"; + if (!strcmp(type, "pixmap")) + return "share/pixmaps/"; + if (!strcmp(type, "apps")) + return "share/applnk/"; + if (!strcmp(type, "sound")) + return "share/sounds/"; + if (!strcmp(type, "locale")) + return "share/locale/"; + if (!strcmp(type, "services")) + return "share/services/"; + if (!strcmp(type, "servicetypes")) + return "share/servicetypes/"; + if (!strcmp(type, "mime")) + return "share/mimelnk/"; + if (!strcmp(type, "cgi")) + return "cgi-bin/"; + if (!strcmp(type, "wallpaper")) + return "share/wallpapers/"; + if (!strcmp(type, "templates")) + return "share/templates/"; + if (!strcmp(type, "exe")) + return "bin/"; + if (!strcmp(type, "lib")) + return "lib/"; + if (!strcmp(type, "module")) + return "lib/kde3/"; + if (!strcmp(type, "qtplugins")) + return "lib/kde3/plugins"; + if (!strcmp(type, "xdgdata-apps")) + return "applications/"; + if (!strcmp(type, "xdgdata-dirs")) + return "desktop-directories/"; + if (!strcmp(type, "xdgconf-menu")) + return "menus/"; + qFatal("unknown resource type %s", type); + return QString::null; +} + +QString KStandardDirs::saveLocation(const char *type, + const QString& suffix, + bool create) const +{ + //qDebug("KStandardDirs::saveLocation called %s %s", type,suffix.latin1() ); + //return ""; + checkConfig(); + + QString *pPath = savelocations.find(type); + if (!pPath) + { + QStringList *dirs = relatives.find(type); + if (!dirs && ( + (strcmp(type, "socket") == 0) || + (strcmp(type, "tmp") == 0) || + (strcmp(type, "cache") == 0) )) + { + (void) resourceDirs(type); // Generate socket|tmp|cache resource. + dirs = relatives.find(type); // Search again. + } + if (dirs) + { + // Check for existance of typed directory + suffix + if (strncmp(type, "xdgdata-", 8) == 0) + pPath = new QString(realPath(localxdgdatadir() + dirs->last())); + else if (strncmp(type, "xdgconf-", 8) == 0) + pPath = new QString(realPath(localxdgconfdir() + dirs->last())); + else + pPath = new QString(realPath(localkdedir() + dirs->last())); + } + else { + dirs = absolutes.find(type); + if (!dirs) + qFatal("KStandardDirs: The resource type %s is not registered", type); + pPath = new QString(realPath(dirs->last())); + } + + savelocations.insert(type, pPath); + } + + QString fullPath = *pPath + suffix; +//US struct stat st; +//US if (stat(QFile::encodeName(fullPath), &st) != 0 || !(S_ISDIR(st.st_mode))) + QFileInfo fullPathInfo(QFile::encodeName(fullPath)); + if (fullPathInfo.isReadable() || !fullPathInfo.isDir()) + + + { + if(!create) { +#ifndef NDEBUG + qDebug("save location %s doesn't exist", fullPath.latin1()); +#endif + return fullPath; + } + if(!makeDir(fullPath, 0700)) { + qWarning("failed to create %s", fullPath.latin1()); + return fullPath; + } + dircache.remove(type); + } + return fullPath; +} + +QString KStandardDirs::relativeLocation(const char *type, const QString &absPath) +{ + QString fullPath = absPath; + int i = absPath.findRev('/'); + if (i != -1) + { + fullPath = realPath(absPath.left(i+1))+absPath.mid(i+1); // Normalize + } + + QStringList candidates = resourceDirs(type); + + for (QStringList::ConstIterator it = candidates.begin(); + it != candidates.end(); it++) + if (fullPath.startsWith(*it)) + { + return fullPath.mid((*it).length()); + } + + return absPath; +} + + +bool KStandardDirs::makeDir(const QString& dir2, int mode) +{ + QString dir = QDir::convertSeparators( dir2 ); +#if 0 + //LR + + // we want an absolute path + if (dir.at(0) != '/') + return false; + + QString target = dir; + uint len = target.length(); + + // append trailing slash if missing + if (dir.at(len - 1) != '/') + target += '/'; + + QString base(""); + uint i = 1; + + while( i < len ) + { +//US struct stat st; + int pos = target.find('/', i); + base += target.mid(i - 1, pos - i + 1); + QCString baseEncoded = QFile::encodeName(base); + // bail out if we encountered a problem +//US if (stat(baseEncoded, &st) != 0) + QFileInfo baseEncodedInfo(baseEncoded); + if (!baseEncodedInfo.exists()) + { + // Directory does not exist.... + // Or maybe a dangling symlink ? +//US if (lstat(baseEncoded, &st) == 0) + if (baseEncodedInfo.isSymLink()) { +//US (void)unlink(baseEncoded); // try removing + QFile(baseEncoded).remove(); + } + +//US if ( mkdir(baseEncoded, (mode_t) mode) != 0) + QDir dirObj; + if ( dirObj.mkdir(baseEncoded) != true ) + { +//US perror("trying to create local folder"); + return false; // Couldn't create it :-( + } + } + i = pos + 1; + } + return true; +#endif + + // ******************************************** + // new code for WIN32 + QDir dirObj; + + + // we want an absolute path +#ifndef _WIN32_ + if (dir.at(0) != '/') + return false; +#endif + + QString target = dir; + uint len = target.length(); +#ifndef _WIN32_ + // append trailing slash if missing + if (dir.at(len - 1) != '/') + target += '/'; +#endif + + QString base(""); + uint i = 1; + + while( i < len ) + { +//US struct stat st; +#ifndef _WIN32_ + int pos = target.find('/', i); +#else + int pos = target.find('\\', i); +#endif + if ( pos < 0 ) + return true; + base += target.mid(i - 1, pos - i + 1); + //QMessageBox::information( 0,"cap111", base, 1 ); +/*US + QCString baseEncoded = QFile::encodeName(base); + // bail out if we encountered a problem + if (stat(baseEncoded, &st) != 0) + { + // Directory does not exist.... + // Or maybe a dangling symlink ? + if (lstat(baseEncoded, &st) == 0) + (void)unlink(baseEncoded); // try removing + + + if ( mkdir(baseEncoded, (mode_t) mode) != 0) { + perror("trying to create local folder"); + return false; // Couldn't create it :-( + } + } +*/ + + if (dirObj.exists(base) == false) + { + //qDebug("KStandardDirs::makeDir try to create : %s" , base.latin1()); + if (dirObj.mkdir(base) != true) + { + qDebug("KStandardDirs::makeDir could not create: %s" , base.latin1()); + return false; + } + } + + i = pos + 1; + } + return true; + +} + +static QString readEnvPath(const char *env) +{ +#ifdef _WIN32_ + return ""; +#else + QCString c_path = getenv(env); + if (c_path.isEmpty()) + return QString::null; + return QFile::decodeName(c_path); +#endif +} + +void KStandardDirs::addKDEDefaults() +{ + //qDebug("ERROR: KStandardDirs::addKDEDefaults() called "); + //return; + QStringList kdedirList; + + // begin KDEDIRS + QString kdedirs = readEnvPath("MICROKDEDIRS"); + if (!kdedirs.isEmpty()) + { + tokenize(kdedirList, kdedirs, ":"); + } + else + { + QString kdedir = readEnvPath("MICROKDEDIR"); + if (!kdedir.isEmpty()) + { + kdedir = KShell::tildeExpand(kdedir); + kdedirList.append(kdedir); + } + } +//US kdedirList.append(KDEDIR); + +#ifdef __KDE_EXECPREFIX + QString execPrefix(__KDE_EXECPREFIX); + if (execPrefix!="NONE") + kdedirList.append(execPrefix); +#endif + + QString localKdeDir; + +//US if (getuid()) + if (true) + { + localKdeDir = readEnvPath("MICROKDEHOME"); + if (!localKdeDir.isEmpty()) + { + if (localKdeDir.at(localKdeDir.length()-1) != '/') + localKdeDir += '/'; + } + else + { + localKdeDir = QDir::homeDirPath() + "/kdepim/"; + } + } + else + { + // We treat root different to prevent root messing up the + // file permissions in the users home directory. + localKdeDir = readEnvPath("MICROKDEROOTHOME"); + if (!localKdeDir.isEmpty()) + { + if (localKdeDir.at(localKdeDir.length()-1) != '/') + localKdeDir += '/'; + } + else + { +//US struct passwd *pw = getpwuid(0); +//US localKdeDir = QFile::decodeName((pw && pw->pw_dir) ? pw->pw_dir : "/root") + "/.microkde/"; + qDebug("KStandardDirs::addKDEDefaults: 1 has to be fixed"); + } + + } + +//US localKdeDir = appDir(); + +//US +// qDebug("KStandardDirs::addKDEDefaults: localKdeDir=%s", localKdeDir.latin1()); + if (localKdeDir != "-/") + { + localKdeDir = KShell::tildeExpand(localKdeDir); + addPrefix(localKdeDir); + } + + for (QStringList::ConstIterator it = kdedirList.begin(); + it != kdedirList.end(); it++) + { + QString dir = KShell::tildeExpand(*it); + addPrefix(dir); + } + // end KDEDIRS + + // begin XDG_CONFIG_XXX + QStringList xdgdirList; + QString xdgdirs = readEnvPath("XDG_CONFIG_DIRS"); + if (!xdgdirs.isEmpty()) + { + tokenize(xdgdirList, xdgdirs, ":"); + } + else + { + xdgdirList.clear(); + xdgdirList.append("/etc/xdg"); + } + + QString localXdgDir = readEnvPath("XDG_CONFIG_HOME"); + if (!localXdgDir.isEmpty()) + { + if (localXdgDir.at(localXdgDir.length()-1) != '/') + localXdgDir += '/'; + } + else + { +//US if (getuid()) + if (true) + { + localXdgDir = QDir::homeDirPath() + "/.config/"; + } + else + { +//US struct passwd *pw = getpwuid(0); +//US localXdgDir = QFile::decodeName((pw && pw->pw_dir) ? pw->pw_dir : "/root") + "/.config/"; + qDebug("KStandardDirs::addKDEDefaults: 2 has to be fixed"); + } + } + + localXdgDir = KShell::tildeExpand(localXdgDir); + addXdgConfigPrefix(localXdgDir); + + for (QStringList::ConstIterator it = xdgdirList.begin(); + it != xdgdirList.end(); it++) + { + QString dir = KShell::tildeExpand(*it); + addXdgConfigPrefix(dir); + } + // end XDG_CONFIG_XXX + + // begin XDG_DATA_XXX + xdgdirs = readEnvPath("XDG_DATA_DIRS"); + if (!xdgdirs.isEmpty()) + { + tokenize(xdgdirList, xdgdirs, ":"); + } + else + { + xdgdirList.clear(); + for (QStringList::ConstIterator it = kdedirList.begin(); + it != kdedirList.end(); it++) + { + QString dir = *it; + if (dir.at(dir.length()-1) != '/') + dir += '/'; + xdgdirList.append(dir+"share/"); + } + + xdgdirList.append("/usr/local/share/"); + xdgdirList.append("/usr/share/"); + } + + localXdgDir = readEnvPath("XDG_DATA_HOME"); + if (!localXdgDir.isEmpty()) + { + if (localXdgDir.at(localXdgDir.length()-1) != '/') + localXdgDir += '/'; + } + else + { +//US if (getuid()) + if (true) + { + localXdgDir = QDir::homeDirPath() + "/.local/share/"; + } + else + { +//US struct passwd *pw = getpwuid(0); +//US localXdgDir = QFile::decodeName((pw && pw->pw_dir) ? pw->pw_dir : "/root") + "/.local/share/"; + qDebug("KStandardDirs::addKDEDefaults: 3 has to be fixed"); + } + } + + localXdgDir = KShell::tildeExpand(localXdgDir); + addXdgDataPrefix(localXdgDir); + + for (QStringList::ConstIterator it = xdgdirList.begin(); + it != xdgdirList.end(); it++) + { + QString dir = KShell::tildeExpand(*it); + + addXdgDataPrefix(dir); + } + // end XDG_DATA_XXX + + + uint index = 0; + while (types[index] != 0) { + addResourceType(types[index], kde_default(types[index])); + index++; + } + + addResourceDir("home", QDir::homeDirPath()); +} + +void KStandardDirs::checkConfig() const +{ +/*US + if (!addedCustoms && KGlobal::_instance && KGlobal::_instance->_config) + const_cast(this)->addCustomized(KGlobal::_instance->_config); +*/ + if (!addedCustoms && KGlobal::config()) + const_cast(this)->addCustomized(KGlobal::config()); +} + +bool KStandardDirs::addCustomized(KConfig *config) +{ + if (addedCustoms) // there are already customized entries + return false; // we just quite and hope they are the right ones + + // save the numbers of config directories. If this changes, + // we will return true to give KConfig a chance to reparse + uint configdirs = resourceDirs("config").count(); + + // reading the prefixes in + QString oldGroup = config->group(); + config->setGroup("Directories"); + + QStringList list; + QStringList::ConstIterator it; + list = config->readListEntry("prefixes"); + for (it = list.begin(); it != list.end(); it++) + addPrefix(*it); + + // iterating over all entries in the group Directories + // to find entries that start with dir_$type +/*US + QMap entries = config->entryMap("Directories"); + + QMap::ConstIterator it2; + for (it2 = entries.begin(); it2 != entries.end(); it2++) + { + QString key = it2.key(); + if (key.left(4) == "dir_") { + // generate directory list, there may be more than 1. + QStringList dirs = QStringList::split(',', *it2); + QStringList::Iterator sIt(dirs.begin()); + QString resType = key.mid(4, key.length()); + for (; sIt != dirs.end(); ++sIt) { + addResourceDir(resType.latin1(), *sIt); + } + } + } + + // Process KIOSK restrictions. + config->setGroup("KDE Resource Restrictions"); + entries = config->entryMap("KDE Resource Restrictions"); + for (it2 = entries.begin(); it2 != entries.end(); it2++) + { + QString key = it2.key(); + if (!config->readBoolEntry(key, true)) + { + d->restrictionsActive = true; + d->restrictions.insert(key.latin1(), &d->restrictionsActive); // Anything will do + dircache.remove(key.latin1()); + } + } +*/ + // save it for future calls - that will return + addedCustoms = true; + config->setGroup(oldGroup); + + // return true if the number of config dirs changed + return (resourceDirs("config").count() != configdirs); +} + +QString KStandardDirs::localkdedir() const +{ + // Return the prefix to use for saving + return prefixes.first(); +} + +QString KStandardDirs::localxdgdatadir() const +{ + // Return the prefix to use for saving + return d->xdgdata_prefixes.first(); +} + +QString KStandardDirs::localxdgconfdir() const +{ + // Return the prefix to use for saving + return d->xdgconf_prefixes.first(); +} + +void KStandardDirs::setAppDir( const QString &appDir ) +{ + mAppDir = appDir; + + if ( mAppDir.right( 1 ) != "/" ) + mAppDir += "/"; +} + +QString KStandardDirs::appDir() +{ + return mAppDir; +} + +// just to make code more readable without macros +QString locate( const char *type, + const QString& filename/*US , const KInstance* inst*/ ) +{ +//US return inst->dirs()->findResource(type, filename); + return KGlobal::dirs()->findResource(type, filename); +} + +QString locateLocal( const char *type, + const QString& filename/*US , const KInstance* inst*/ ) +{ + + QString path = locateLocal(type, filename, true /*US, inst*/); + + +/* + static int ccc = 0; + ++ccc; + if ( ccc > 13 ) + abort(); +*/ + qDebug("locatelocal: %s" , path.latin1()); + return path; + +/*US why do we put all files into one directory. It is quit complicated. +why not staying with the original directorystructure ? + + + QString escapedFilename = filename; + escapedFilename.replace( QRegExp( "/" ), "_" ); + + QString path = KStandardDirs::appDir() + type + "_" + escapedFilename; + + kdDebug() << "locate: '" << path << "'" << endl; + qDebug("locate: %s" , path.latin1()); + return path; +*/ +//US so my proposal is this: + +// QString escapedFilename = filename; +// escapedFilename.replace( QRegExp( "/" ), "_" ); + +#if 0 +#ifdef _WIN32_ + QString path = QDir::convertSeparators(KStandardDirs::appDir() + type + "/" + filename); +#else + QString path = KStandardDirs::appDir() + type + "/" + filename; +#endif + + //US Create the containing dir if needed + QFileInfo fi ( path ); + + // QString dir=pathurl.directory(); + // QMessageBox::information( 0,"path", path, 1 ); + +#ifdef _WIN32_ + KStandardDirs::makeDir(path); +#else + KStandardDirs::makeDir(fi.dirPath( true )); +#endif + + qDebug("locate22: %s" , path.latin1()); + return path; + +#endif + +} + +QString locateLocal( const char *type, + const QString& filename, bool createDir/*US , const KInstance* inst*/ ) +{ + // try to find slashes. If there are some, we have to + // create the subdir first + int slash = filename.findRev('/')+1; + if (!slash) // only one filename +//US return inst->dirs()->saveLocation(type, QString::null, createDir) + filename; + return KGlobal::dirs()->saveLocation(type, QString::null, createDir) + filename; + + // split path from filename + QString dir = filename.left(slash); + QString file = filename.mid(slash); +//US return inst->dirs()->saveLocation(type, dir, createDir) + file; + return KGlobal::dirs()->saveLocation(type, dir, createDir) + file; + + // *************************************************************** +#if 0 + +/*US why do we put all files into one directory. It is quit complicated. +why not staying with the original directorystructure ? + + + QString escapedFilename = filename; + escapedFilename.replace( QRegExp( "/" ), "_" ); + + QString path = KStandardDirs::appDir() + type + "_" + escapedFilename; + + kdDebug() << "locate: '" << path << "'" << endl; + qDebug("locate: %s" , path.latin1()); + return path; +*/ +//US so my proposal is this: + +// QString escapedFilename = filename; +// escapedFilename.replace( QRegExp( "/" ), "_" ); + +#ifdef _WIN32_ + QString path = QDir::convertSeparators(KStandardDirs::appDir() + type + "/" + filename); +#else + QString path = KStandardDirs::appDir() + type + "/" + filename; +#endif + + //US Create the containing dir if needed + KURL pathurl; + pathurl.setPath(path); + QString dir=pathurl.directory(); + // QMessageBox::information( 0,"path", path, 1 ); +#ifdef _WIN32_ + KStandardDirs::makeDir(path); +#else + KStandardDirs::makeDir(dir); +#endif + + return path; +#endif +} diff --git a/microkde/kdecore/kstandarddirs.h b/microkde/kdecore/kstandarddirs.h new file mode 100644 index 0000000..c4e1108 --- a/dev/null +++ b/microkde/kdecore/kstandarddirs.h @@ -0,0 +1,681 @@ +/* + This file is part of the KDE libraries + Copyright (C) 1999 Sirtaj Singh Kang + Stephan Kulow + Waldo Bastian + + 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. +*/ + +#ifndef SSK_KSTDDIRS_H +#define SSK_KSTDDIRS_H + +#include +#include +#include +#include + +class KConfig; +class KStandardDirsPrivate; + + +/** + * @short Site-independent access to standard KDE directories. + * @author Stephan Kulow and Sirtaj Singh Kang + * @version $Id$ + * + * This is one of the most central classes in kdelibs as + * it provides a basic service: It knows where the files + * reside on the user's hard disk. And it's meant to be the + * only one that knows -- to make the real location as + * transparent as possible to both the user and the applications. + * + * To this end it insulates the application from all information + * and applications always refer to a file with a resource type + * (e.g. icon) and a filename (e.g. khexdit.xpm). In an ideal world + * the application would make no assumption where this file is and + * leave it up to @ref KStandardDirs::findResource("apps", "Home.desktop") + * to apply this knowledge to return /opt/kde/share/applnk/Home.desktop + * or ::locate("data", "kgame/background.jpg") to return + * /opt/kde/share/apps/kgame/background.jpg + * + * The main idea behind KStandardDirs is that there are several + * toplevel prefixes below which the files lie. One of these prefixes is + * the one where the user installed kdelibs, one is where the + * application was installed, and one is $HOME/.kde, but there + * may be even more. Under these prefixes there are several well + * defined suffixes where specific resource types are to be found. + * For example, for the resource type "html" the suffixes could be + * share/doc/HTML and share/doc/kde/HTML. + * So the search algorithm basicly appends to each prefix each registered + * suffix and tries to locate the file there. + * To make the thing even more complex, it's also possible to register + * absolute paths that KStandardDirs looks up after not finding anything + * in the former steps. They can be useful if the user wants to provide + * specific directories that aren't in his $HOME/.kde directory for, + * for example, icons. + * + * @sect Standard resources that kdelibs allocates are: + * + * @li apps - Applications menu (.desktop files). + * @li cache - Cached information (e.g. favicons, web-pages) + * @li cgi - CGIs to run from kdehelp. + * @li config - Configuration files. + * @li data - Where applications store data. + * @li exe - Executables in $prefix/bin. @ref findExe() for a function that takes $PATH into account. + * @li html - HTML documentation. + * @li icon - Icons, see @ref KIconLoader. + * @li lib - Libraries. + * @li locale - Translation files for @ref KLocale. + * @li mime - Mime types. + * @li module - Module (dynamically loaded library). + * @li qtplugins - Qt plugins (dynamically loaded objects for Qt) + * @li services - Services. + * @li servicetypes - Service types. + * @li scripts - Application scripting additions. + * @li sound - Application sounds. + * @li templates - Templates + * @li wallpaper - Wallpapers. + * @li tmp - Temporary files (specfic for both current host and current user) + * @li socket - UNIX Sockets (specific for both current host and current user) + * + * A type that is added by the class @ref KApplication if you use it, is + * appdata. This one makes the use of the type data a bit easier as it + * appends the name of the application. + * So while you had to ::locate("data", "appname/filename") so you can + * also write ::locate("appdata", "filename") if your KApplication instance + * is called "appname" (as set via KApplication's constructor or KAboutData, if + * you use the global KStandardDirs object @ref KGlobal::dirs()). + * Please note though that you cannot use the "appdata" + * type if you intend to use it in an applet for Kicker because 'appname' would + * be "Kicker" instead of the applet's name. Therefore, for applets, you've got + * to work around this by using ::locate("data", "appletname/filename"). + * + * @sect KStandardDirs supports the following environment variables: + * + * @li KDEDIRS: This may set an additional number of directory prefixes to + * search for resources. The directories should be seperated + * by ':'. The directories are searched in the order they are + * specified. + * @li KDEDIR: Used for backwards compatibility. As KDEDIRS but only a single + * directory may be specified. If KDEDIRS is set KDEDIR is + * ignored. + * @li KDEHOME: The directory where changes are saved to. This directory is + * used to search for resources first. If KDEHOME is not + * specified it defaults to "$HOME/.kde" + * @li KDEROOTHOME: Like KDEHOME, but used for the root user. + * If KDEROOTHOME is not set it defaults to the .kde directory in the + * home directory of root, usually "/root/.kde". + * Note that the setting of $HOME is ignored in this case. + * + * @see KGlobalSettings + */ +class KStandardDirs +{ +public: + /** + * KStandardDirs' constructor. It just initializes the caches. + **/ + KStandardDirs( ); + + /** + * KStandardDirs' destructor. + */ + virtual ~KStandardDirs(); + + /** + * Adds another search dir to front of the @p fsstnd list. + * + * @li When compiling kdelibs, the prefix is added to this. + * @li KDEDIRS or KDEDIR is taking into account + * @li Additional dirs may be loaded from kdeglobals. + * + * @param dir The directory to append relative paths to. + */ + void addPrefix( const QString& dir ); + + /** + * Adds another search dir to front of the XDG_CONFIG_XXX list + * of prefixes. + * This prefix is only used for resources that start with "xdgconf-" + * + * @param dir The directory to append relative paths to. + */ + void addXdgConfigPrefix( const QString& dir ); + + /** + * Adds another search dir to front of the XDG_DATA_XXX list + * of prefixes. + * This prefix is only used for resources that start with "xdgdata-" + * + * @param dir The directory to append relative paths to. + */ + void addXdgDataPrefix( const QString& dir ); + + /** + * Adds suffixes for types. + * + * You may add as many as you need, but it is advised that there + * is exactly one to make writing definite. + * All basic types (@ref kde_default) are added by @ref addKDEDefaults(), + * but for those you can add more relative paths as well. + * + * The later a suffix is added, the higher its priority. Note, that the + * suffix should end with / but doesn't have to start with one (as prefixes + * should end with one). So adding a suffix for app_pics would look + * like KGlobal::dirs()->addResourceType("app_pics", "share/app/pics"); + * + * @param type Specifies a short descriptive string to access + * files of this type. + * @param relativename Specifies a directory relative to the root + * of the KFSSTND. + * @return true if successful, false otherwise. + */ + bool addResourceType( const char *type, + const QString& relativename ); + + /** + * Adds absolute path at the end of the search path for + * particular types (for example in case of icons where + * the user specifies extra paths). + * + * You shouldn't need this + * function in 99% of all cases besides adding user-given + * paths. + * + * @param type Specifies a short descriptive string to access files + * of this type. + * @param absdir Points to directory where to look for this specific + * type. Non-existant directories may be saved but pruned. + * @return true if successful, false otherwise. + */ + bool addResourceDir( const char *type, + const QString& absdir); + + /** + * Tries to find a resource in the following order: + * @li All PREFIX/\ paths (most recent first). + * @li All absolute paths (most recent first). + * + * The filename should be a filename relative to the base dir + * for resources. So is a way to get the path to libkdecore.la + * to findResource("lib", "libkdecore.la"). KStandardDirs will + * then look into the subdir lib of all elements of all prefixes + * ($KDEDIRS) for a file libkdecore.la and return the path to + * the first one it finds (e.g. /opt/kde/lib/libkdecore.la) + * + * @param type The type of the wanted resource + * @param filename A relative filename of the resource. + * + * @return A full path to the filename specified in the second + * argument, or QString::null if not found. + */ + QString findResource( const char *type, + const QString& filename ) const; + + /** + * Checks whether a resource is restricted as part of the KIOSK + * framework. When a resource is restricted it means that user- + * specific files in the resource are ignored. + * + * E.g. by restricting the "wallpaper" resource, only system-wide + * installed wallpapers will be found by this class. Wallpapers + * installed under the $KDEHOME directory will be ignored. + * + * @param type The type of the resource to check + * @param relPath A relative path in the resource. + * + * @return True if the resource is restricted. + * @since 3.1 + */ + bool isRestrictedResource( const char *type, + const QString& relPath=QString::null ) const; + + /** + * Returns a number that identifies this version of the resource. + * When a change is made to the resource this number will change. + * + * @param type The type of the wanted resource + * @param filename A relative filename of the resource. + * @param deep If true, all resources are taken into account + * otherwise only the one returned by findResource(). + * + * @return A number identifying the current version of the + * resource. + */ +/*US + Q_UINT32 calcResourceHash( const char *type, + const QString& filename, bool deep) const; +*/ + /** + * Tries to find all directories whose names consist of the + * specified type and a relative path. So would + * findDirs("apps", "Settings") return + * @li /opt/kde/share/applnk/Settings/ + * @li /home/joe/.kde/share/applnk/Settings/ + * + * Note that it appends / to the end of the directories, + * so you can use this right away as directory names. + * + * @param type The type of the base directory. + * @param reldir Relative directory. + * + * @return A list of matching directories, or an empty + * list if the resource specified is not found. + */ + QStringList findDirs( const char *type, + const QString& reldir ) const; + + /** + * Tries to find the directory the file is in. + * It works the same as @ref findResource(), but it doesn't + * return the filename but the name of the directory. + * + * This way the application can access a couple of files + * that have been installed into the same directory without + * having to look for each file. + * + * findResourceDir("lib", "libkdecore.la") would return the + * path of the subdir libkdecore.la is found first in + * (e.g. /opt/kde/lib/) + * + * @param type The type of the wanted resource + * @param filename A relative filename of the resource. + * @return The directory where the file specified in the second + * argument is located, or QString::null if the type + * of resource specified is unknown or the resource + * cannot be found. + */ + QString findResourceDir( const char *type, + const QString& filename) const; + + + /** + * Tries to find all resources with the specified type. + * + * The function will look into all specified directories + * and return all filenames in these directories. + * + * @param type The type of resource to locate directories for. + * @param filter Only accept filenames that fit to filter. The filter + * may consist of an optional directory and a @ref QRegExp + * wildcard expression. E.g. "images\*.jpg". Use QString::null + * if you do not want a filter. + * @param recursive Specifies if the function should decend + * into subdirectories. + * @param uniq If specified, only return items which have + * unique suffixes - suppressing duplicated filenames. + * + * @return A list of directories matching the resource specified, + * or an empty list if the resource type is unknown. + */ + QStringList findAllResources( const char *type, + const QString& filter = QString::null, + bool recursive = false, + bool uniq = false) const; + + /** + * Tries to find all resources with the specified type. + * + * The function will look into all specified directories + * and return all filenames (full and relative paths) in + * these directories. + * + * @param type The type of resource to locate directories for. + * @param filter Only accept filenames that fit to filter. The filter + * may consist of an optional directory and a @ref QRegExp + * wildcard expression. E.g. "images\*.jpg". Use QString::null + * if you do not want a filter. + * @param recursive Specifies if the function should decend + * into subdirectories. + * @param uniq If specified, only return items which have + * unique suffixes. + * @param list Of relative paths for the given type. + * @param relPaths The list to store the relative paths into + * These can be used later to ::locate() the file + * + * @return A list of directories matching the resource specified, + * or an empty list if the resource type is unknown. + */ + QStringList findAllResources( const char *type, + const QString& filter, + bool recursive, + bool uniq, + QStringList &relPaths) const; + + /** + * Finds the executable in the system path. + * + * A valid executable must + * be a file and have its executable bit set. + * + * @param appname The name of the executable file for which to search. + * @param pathstr The path which will be searched. If this is + * null (default), the $PATH environment variable will + * be searched. + * @param ignoreExecBit If true, an existing file will be returned + * even if its executable bit is not set. + * + * @return The path of the executable. If it was not found, + * it will return QString::null. + * @see findAllExe() + */ +/*US + static QString findExe( const QString& appname, + const QString& pathstr=QString::null, + bool ignoreExecBit=false ); +*/ + + /** + * Finds all occurences of an executable in the system path. + * + * @param list Will be filled with the pathnames of all the + * executables found. Will be empty if the executable + * was not found. + * @param appname The name of the executable for which to + * search. + * @param pathstr The path list which will be searched. If this + * is 0 (default), the $PATH environment variable will + * be searched. + * @param ignoreExecBit If true, an existing file will be returned + * even if its executable bit is not set. + * + * @return The number of executables found, 0 if none were found. + * + * @see findExe() + */ + static int findAllExe( QStringList& list, const QString& appname, + const QString& pathstr=QString::null, + bool ignoreExecBit=false ); + + /** + * This function adds the defaults that are used by the current + * KDE version. + * + * It's a series of @ref addResourceTypes() + * and @ref addPrefix() calls. + * You normally wouldn't call this function because it's called + * for you from @ref KGlobal. + */ + void addKDEDefaults(); + + /** + * Reads customized entries out of the given config object and add + * them via @ref addResourceDirs(). + * + * @param config The object the entries are read from. This should + * contain global config files + * @return true if new config paths have been added + * from @p config. + **/ + bool addCustomized(KConfig *config); + + /** + * This function is used internally by almost all other function as + * it serves and fills the directories cache. + * + * @param type The type of resource + * @return The list of possible directories for the specified @p type. + * The function updates the cache if possible. If the resource + * type specified is unknown, it will return an empty list. + * Note, that the directories are assured to exist beside the save + * location, which may not exist, but is returned anyway. + */ + QStringList resourceDirs(const char *type) const; + + /** + * This function will return a list of all the types that KStandardDirs + * supports. + * + * @return All types that KDE supports + */ + QStringList allTypes() const; + + /** + * Finds a location to save files into for the given type + * in the user's home directory. + * + * @param type The type of location to return. + * @param suffix A subdirectory name. + * Makes it easier for you to create subdirectories. + * You can't pass filenames here, you _have_ to pass + * directory names only and add possible filename in + * that directory yourself. A directory name always has a + * trailing slash ('/'). + * @param create If set, saveLocation() will create the directories + * needed (including those given by @p suffix). + * + * @return A path where resources of the specified type should be + * saved, or QString::null if the resource type is unknown. + */ + QString saveLocation(const char *type, + const QString& suffix = QString::null, + bool create = true) const; + + /** + * Converts an absolute path to a path relative to a certain + * resource. + * + * If "abs = ::locate(resource, rel)" + * then "rel = relativeLocation(resource, abs)" and vice versa. + * + * @param type The type of resource. + * + * @param absPath An absolute path to make relative. + * + * @return A relative path relative to resource @p type that + * will find @p absPath. If no such relative path exists, absPath + * will be returned unchanged. + */ + QString relativeLocation(const char *type, const QString &absPath); + + /** + * Recursively creates still-missing directories in the given path. + * + * The resulting permissions will depend on the current umask setting. + * permission = mode & ~umask. + * + * @param dir Absolute path of the directory to be made. + * @param mode Directory permissions. + * @return true if successful, false otherwise + */ + static bool makeDir(const QString& dir, int mode = 0755); + + /** + * This returns a default relative path for the standard KDE + * resource types. Below is a list of them so you get an idea + * of what this is all about. + * + * @li data - share/apps + * @li html - share/doc/HTML + * @li icon - share/icon + * @li config - share/config + * @li pixmap - share/pixmaps + * @li apps - share/applnk + * @li sound - share/sounds + * @li locale - share/locale + * @li services - share/services + * @li servicetypes - share/servicetypes + * @li mime - share/mimelnk + * @li wallpaper - share/wallpapers + * @li templates - share/templates + * @li exe - bin + * @li lib - lib + * + * @returns Static default for the specified resource. You + * should probably be using locate() or locateLocal() + * instead. + * @see locate() + * @see locateLocal() + */ + static QString kde_default(const char *type); + + /** + * @internal (for use by sycoca only) + */ + QString kfsstnd_prefixes(); + + /** + * Returns the toplevel directory in which KStandardDirs + * will store things. Most likely $HOME/.kde + * Don't use this function if you can use locateLocal + * @return the toplevel directory + */ + QString localkdedir() const; + + /** + * @return $XDG_DATA_HOME + * See also http://www.freedesktop.org/standards/basedir/draft/basedir-spec/basedir-spec.html + */ + QString localxdgdatadir() const; + + /** + * @return $XDG_CONFIG_HOME + * See also http://www.freedesktop.org/standards/basedir/draft/basedir-spec/basedir-spec.html + */ + QString localxdgconfdir() const; + + /** + * Checks for existence and accessability. + * Faster than creating a QFileInfo first. + * @param fullPath the path to check + * @return true if the directory exists + */ + static bool exists(const QString &fullPath); + + /** + * Expands all symbolic links and resolves references to + * '/./', '/../' and extra '/' characters in @p dirname + * and returns the canonicalized absolute pathname. + * The resulting path will have no symbolic link, '/./' + * or '/../' components. + * @since 3.1 + */ + static QString realPath(const QString &dirname); + + static void setAppDir( const QString & ); + static QString appDir(); + + private: + + QStringList prefixes; + + // Directory dictionaries + QDict absolutes; + QDict relatives; + + mutable QDict dircache; + mutable QDict savelocations; + + // Disallow assignment and copy-construction + KStandardDirs( const KStandardDirs& ); + KStandardDirs& operator= ( const KStandardDirs& ); + + bool addedCustoms; + + class KStandardDirsPrivate; + KStandardDirsPrivate *d; +//US + static QString mAppDir; + + void checkConfig() const; + void applyDataRestrictions(const QString &) const; +//US void createSpecialResource(const char*); +}; + +/** + * \addtogroup locates Locate Functions + * @{ + * On The Usage Of 'locate' and 'locateLocal' + * + * Typical KDE applications use resource files in one out of + * three ways: + * + * 1) A resource file is read but is never written. A system + * default is supplied but the user can override this + * default in his local .kde directory: + * + * \code + * // Code example + * myFile = locate("appdata", "groups.lst"); + * myData = myReadGroups(myFile); // myFile may be null + * \endcode + * + * 2) A resource file is read and written. If the user has no + * local version of the file the system default is used. + * The resource file is always written to the users local + * .kde directory. + * + * \code + * // Code example + * myFile = locate("appdata", "groups.lst") + * myData = myReadGroups(myFile); + * ... + * doSomething(myData); + * ... + * myFile = locateLocal("appdata", "groups.lst"); + * myWriteGroups(myFile, myData); + * \endcode + * + * 3) A resource file is read and written. No system default + * is used if the user has no local version of the file. + * The resource file is always written to the users local + * .kde directory. + * + * \code + * // Code example + * myFile = locateLocal("appdata", "groups.lst"); + * myData = myReadGroups(myFile); + * ... + * doSomething(myData); + * ... + * myFile = locateLocal("appdata", "groups.lst"); + * myWriteGroups(myFile, myData); + * \endcode + **/ + +/*! + * \relates KStandardDirs + * This function is just for convenience. It simply calls + *instance->dirs()->\link KStandardDirs::findResource() findResource\endlink(type, filename). + **/ +QString locate( const char *type, const QString& filename /*US , const KInstance* instance = KGlobal::instance()*/ ); + +/*! + * \relates KStandardDirs + * This function is much like locate. However it returns a + * filename suitable for writing to. No check is made if the + * specified filename actually exists. Missing directories + * are created. If filename is only a directory, without a + * specific file, filename must have a trailing slash. + * + **/ +QString locateLocal( const char *type, const QString& filename /*US , const KInstance* instance = KGlobal::instance() */ ); + +/*! + * \relates KStandardDirs + * This function is much like locate. No check is made if the + * specified filename actually exists. Missing directories + * are created if @p createDir is true. If filename is only + * a directory, without a specific file, + * filename must have a trailing slash. + * + **/ +QString locateLocal( const char *type, const QString& filename, bool createDir /*US , const KInstance* instance = KGlobal::instance() */); + +/*! @} */ + +#endif // SSK_KSTDDIRS_H diff --git a/microkde/kdecore/kstringhandler.cpp b/microkde/kdecore/kstringhandler.cpp new file mode 100644 index 0000000..b737e97 --- a/dev/null +++ b/microkde/kdecore/kstringhandler.cpp @@ -0,0 +1,650 @@ +/* This file is part of the KDE libraries + Copyright (C) 1999 Ian Zepp (icszepp@islc.net) + + 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. +*/ + +/* AIX needs strings.h for str*casecmp(), and our config.h loads it on AIX + So we don't need to include strings.h explicitly */ + +//US #include "config.h" + +#include "kstringhandler.h" +/*US +QString KStringHandler::word( const QString &text , uint pos ) +{ + QStringList list = QStringList::split( " ", text , true ); + + if ( pos < list.count() ) + return list[ pos ]; + + return ""; +} + +QString KStringHandler::word( const QString &text , const char *range ) +{ + // Format in: START:END + // Note index starts a 0 (zero) + // + // 0: first word to end + // 1:3 second to fourth words + QStringList list = QStringList::split( " ", text , true ); + QString tmp = ""; + QString r = range; + + if ( text.isEmpty() ) + return tmp; + + // do stuff here + QRegExp reg; + + int at = 0; + int pos = 0; + int cnt = 0; + + if ( r.find(QRegExp("[0-9]+:[0-9]+")) != -1 ) + { + at = r.find(":"); + pos = atoi( r.left(at).ascii() ); + cnt = atoi( r.remove(0,at+1).ascii() ); + } + else if ( r.find(QRegExp(":+[0-9]+")) != -1 ) + { + at = r.find(":"); + pos = 0; + cnt = atoi( r.remove(0,at+1).ascii() ); + } + else if ( r.find(QRegExp("[0-9]+:+")) != -1 ) + { + at = r.find(":"); + pos = atoi( r.left(at).ascii() ); + cnt = list.count(); // zero index + } + else if ( r.find(QRegExp("[0-9]+")) != -1 ) + { + pos = atoi( r.ascii() ); + cnt = pos; + } + else + { + return tmp; // not found/implemented + } + + // + // Extract words + // + int wordsToExtract = cnt-pos+1; + QStringList::Iterator it = list.at( pos); + + while ( (it != list.end()) && (wordsToExtract-- > 0)) + { + tmp += *it; + tmp += " "; + it++; + } + + return tmp.stripWhiteSpace(); +} + +// +// Insertion and removal routines +// +QString KStringHandler::insword( const QString &text , const QString &word , uint pos ) +{ + if ( text.isEmpty() ) + return word; + + if ( word.isEmpty() ) + return text; + + // Split words and add into list + QStringList list = QStringList::split( " ", text, true ); + + if ( pos >= list.count() ) + list.append( word ); + else + list.insert( list.at(pos) , word ); + + // Rejoin + return list.join( " " ); +} + +QString KStringHandler::setword( const QString &text , const QString &word , uint pos ) +{ + if ( text.isEmpty() ) + return word; + + if ( word.isEmpty() ) + return text; + + // Split words and add into list + QStringList list = QStringList::split( " ", text, true ); + + if ( pos >= list.count() ) + list.append( word ); + else + { + list.insert( list.remove( list.at(pos) ) , word ); + } + + // Rejoin + return list.join( " " ); +} + +QString KStringHandler::remrange( const QString &text , const char *range ) +{ + // Format in: START:END + // Note index starts a 0 (zero) + // + // 0: first word to end + // 1:3 second to fourth words + QStringList list = QStringList::split( " ", text , true ); + QString tmp = ""; + QString r = range; + + if ( text.isEmpty() ) + return tmp; + + // do stuff here + QRegExp reg; + + int at = 0; + int pos = 0; + int cnt = 0; + + if ( r.find(QRegExp("[0-9]+:[0-9]+")) != -1 ) + { + at = r.find(':'); + pos = atoi( r.left(at).ascii() ); + cnt = atoi( r.remove(0,at+1).ascii() ); + } + else if ( r.find(QRegExp(":+[0-9]+")) != -1 ) + { + at = r.find(':'); + pos = 0; + cnt = atoi( r.remove(0,at+1).ascii() ); + } + else if ( r.find(QRegExp("[0-9]+:+")) != -1 ) + { + at = r.find(':'); + pos = atoi( r.left(at).ascii() ); + cnt = list.count(); // zero index + } + else if ( r.find(QRegExp("[0-9]+")) != -1 ) + { + pos = atoi( r.ascii() ); + cnt = pos; + } + else + { + return text; // not found/implemented + } + + // + // Remove that range of words + // + int wordsToDelete = cnt-pos+1; + QStringList::Iterator it = list.at( pos); + + while ( (it != list.end()) && (wordsToDelete-- > 0)) + it = list.remove( it ); + + return list.join( " " ); +} + +QString KStringHandler::remword( const QString &text , uint pos ) +{ + QString tmp = ""; + + if ( text.isEmpty() ) + return tmp; + + // Split words and add into list + QStringList list = QStringList::split( " ", text, true ); + + if ( pos < list.count() ) + list.remove( list.at( pos ) ); + + // Rejoin + return list.join( " " ); +} + +QString KStringHandler::remword( const QString &text , const QString &word ) +{ + QString tmp = ""; + + if ( text.isEmpty() ) + return tmp; + + if ( word.isEmpty() ) + return text; + + // Split words and add into list + QStringList list = QStringList::split( " ", text, true ); + + QStringList::Iterator it = list.find(word); + + if (it != list.end()) + list.remove( it ); + + // Rejoin + return list.join( " " ); +} + +// +// Capitalization routines +// +QString KStringHandler::capwords( const QString &text ) +{ + QString tmp = ""; + + if ( text.isEmpty() ) + return tmp; + + QStringList list = QStringList::split( " ", text, true ); + + return capwords( QStringList::split( " ", text, true )).join( " " ); +} + +QStringList KStringHandler::capwords( const QStringList &list ) +{ + QStringList tmp; + QString word; + + if ( list.count() == 0 ) + return tmp; + + for ( QStringList::ConstIterator it= list.begin(); + it != list.end(); + it++) + { + word = *it; + word = word.left(1).upper() + word.remove(0,1); + + tmp.append( word ); // blank list to start with + } + + return tmp; +} + +// +// Reverse routines +// +QString KStringHandler::reverse( const QString &text ) +{ + QString tmp; + + if ( text.isEmpty() ) + return tmp; + + QStringList list; + list = QStringList::split( " ", text, true ); + list = reverse( list ); + + return list.join( " " ); +} + +QStringList KStringHandler::reverse( const QStringList &list ) +{ + QStringList tmp; + + if ( list.count() == 0 ) + return tmp; + + for ( QStringList::ConstIterator it= list.begin(); + it != list.end(); + it++) + tmp.prepend( *it ); + + return tmp; +} + +// +// Left, Right, Center justification +// +QString KStringHandler::ljust( const QString &text , uint width ) +{ + QString tmp = text; + tmp = tmp.stripWhiteSpace(); // remove leading/trailing spaces + + if ( tmp.length() >= width ) + return tmp; + + for ( uint pos = tmp.length() ; pos < width ; pos++ ) + tmp.append(" "); + + return tmp; +} + +QString KStringHandler::rjust( const QString &text , uint width ) +{ + QString tmp = text; + tmp = tmp.stripWhiteSpace(); // remove leading/trailing spaces + + if ( tmp.length() >= width ) + return tmp; + + for ( uint pos = tmp.length() ; pos < width ; pos++ ) + tmp.prepend(" "); + + return tmp; +} + +QString KStringHandler::center( const QString &text , uint width ) +{ + // Center is slightly different, in that it will add + // spaces to the RIGHT side (left-justified) before + // it adds a space to the LEFT side. + + QString tmp = text; + tmp = tmp.stripWhiteSpace(); // remove leading/trailing spaces + + if ( tmp.length() >= width ) + return tmp; + + bool left = false; // start at right side. + + for ( uint pos = tmp.length() ; pos < width ; pos++ ) + { + if ( left ) + tmp.prepend(" "); + else + tmp.append(" "); + + // Reverse bool + left = !left; + } + + return tmp; +} + +QString KStringHandler::lsqueeze( const QString & str, uint maxlen ) +{ + if (str.length() > maxlen) { + int part = maxlen-3; + return QString("..." + str.right(part)); + } + else return str; +} + +QString KStringHandler::csqueeze( const QString & str, uint maxlen ) +{ + if (str.length() > maxlen && maxlen > 3) { + int part = (maxlen-3)/2; + return QString(str.left(part) + "..." + str.right(part)); + } + else return str; +} + +QString KStringHandler::rsqueeze( const QString & str, uint maxlen ) +{ + if (str.length() > maxlen) { + int part = maxlen-3; + return QString(str.left(part) + "..."); + } + else return str; +} + +QString KStringHandler::lEmSqueeze(const QString &name, const QFontMetrics& fontMetrics, uint maxlen) +{ + return lPixelSqueeze(name, fontMetrics, fontMetrics.maxWidth() * maxlen); +} + +static inline int emSqueezeLimit(int delta, int min, int max) +{ + if (delta < min) return min; + if (delta > max) return max; + return delta; +} + +QString KStringHandler::lPixelSqueeze(const QString& name, const QFontMetrics& fontMetrics, uint maxPixels) +{ + uint nameWidth = fontMetrics.width(name); + + if (maxPixels < nameWidth) + { + QString tmp = name; + const uint em = fontMetrics.maxWidth(); + maxPixels -= fontMetrics.width("..."); + + while (maxPixels < nameWidth && !tmp.isEmpty()) + { + int delta = (nameWidth - maxPixels) / em; + delta = emSqueezeLimit(delta, 1, delta); // no max + + tmp.remove(0, delta); + nameWidth = fontMetrics.width(tmp); + } + + return ("..." + tmp); + } + + return name; +} + +QString KStringHandler::cEmSqueeze(const QString& name, const QFontMetrics& fontMetrics, uint maxlen) +{ + return cPixelSqueeze(name, fontMetrics, fontMetrics.maxWidth() * maxlen); +} + +QString KStringHandler::cPixelSqueeze(const QString& name, const QFontMetrics& fontMetrics, uint maxPixels) +{ + uint nameWidth = fontMetrics.width(name); + + if (maxPixels < nameWidth) + { + QString tmp = name; + const uint em = fontMetrics.maxWidth(); + maxPixels -= fontMetrics.width("..."); + + while (maxPixels < nameWidth && !tmp.isEmpty()) + { + int length = tmp.length(); + int delta = (nameWidth - maxPixels) / em; + delta = emSqueezeLimit(delta, 1, length) ; + + tmp.remove((length / 2) - (delta / 2), delta); + nameWidth = fontMetrics.width(tmp); + } + + return tmp.insert((tmp.length() + 1) / 2, "..."); + } + + return name; +} + +QString KStringHandler::rEmSqueeze(const QString& name, const QFontMetrics& fontMetrics, uint maxlen) +{ + return rPixelSqueeze(name, fontMetrics, fontMetrics.maxWidth() * maxlen); +} + +QString KStringHandler::rPixelSqueeze(const QString& name, const QFontMetrics& fontMetrics, uint maxPixels) +{ + uint nameWidth = fontMetrics.width(name); + + if (maxPixels < nameWidth) + { + QString tmp = name; + const uint em = fontMetrics.maxWidth(); + maxPixels -= fontMetrics.width("..."); + + while (maxPixels < nameWidth && !tmp.isEmpty()) + { + int length = tmp.length(); + int delta = (nameWidth - maxPixels) / em; + delta = emSqueezeLimit(delta, 1, length) ; + + tmp.remove(length - delta, delta); + nameWidth = fontMetrics.width(tmp); + } + + return (tmp + "..."); + } + + return name; +} + +///// File name patterns (like *.txt) + +bool KStringHandler::matchFileName( const QString& filename, const QString& pattern ) +{ + int len = filename.length(); + int pattern_len = pattern.length(); + + if (!pattern_len) + return false; + + // Patterns like "Makefile*" + if ( pattern[ pattern_len - 1 ] == '*' && len + 1 >= pattern_len ) { + const QChar *c1 = pattern.unicode(); + const QChar *c2 = filename.unicode(); + int cnt = 1; + while ( cnt < pattern_len && *c1++ == *c2++ ) + ++cnt; + return cnt == pattern_len; + } + + // Patterns like "*~", "*.extension" + if ( pattern[ 0 ] == '*' && len + 1 >= pattern_len ) + { + const QChar *c1 = pattern.unicode() + pattern_len - 1; + const QChar *c2 = filename.unicode() + len - 1; + int cnt = 1; + while ( cnt < pattern_len && *c1-- == *c2-- ) + ++cnt; + return cnt == pattern_len; + } + + // Patterns like "Makefile" + return ( filename == pattern ); +} + + QStringList +KStringHandler::perlSplit(const QString & sep, const QString & s, uint max) +{ + bool ignoreMax = 0 == max; + + QStringList l; + + int searchStart = 0; + + int tokenStart = s.find(sep, searchStart); + + while (-1 != tokenStart && (ignoreMax || l.count() < max - 1)) + { + if (!s.mid(searchStart, tokenStart - searchStart).isEmpty()) + l << s.mid(searchStart, tokenStart - searchStart); + + searchStart = tokenStart + sep.length(); + tokenStart = s.find(sep, searchStart); + } + + if (!s.mid(searchStart, s.length() - searchStart).isEmpty()) + l << s.mid(searchStart, s.length() - searchStart); + + return l; +} + + QStringList +KStringHandler::perlSplit(const QChar & sep, const QString & s, uint max) +{ + bool ignoreMax = 0 == max; + + QStringList l; + + int searchStart = 0; + + int tokenStart = s.find(sep, searchStart); + + while (-1 != tokenStart && (ignoreMax || l.count() < max - 1)) + { + if (!s.mid(searchStart, tokenStart - searchStart).isEmpty()) + l << s.mid(searchStart, tokenStart - searchStart); + + searchStart = tokenStart + 1; + tokenStart = s.find(sep, searchStart); + } + + if (!s.mid(searchStart, s.length() - searchStart).isEmpty()) + l << s.mid(searchStart, s.length() - searchStart); + + return l; +} + + QStringList +KStringHandler::perlSplit(const QRegExp & sep, const QString & s, uint max) +{ + bool ignoreMax = 0 == max; + + QStringList l; + + int searchStart = 0; + int tokenStart = sep.search(s, searchStart); + int len = sep.matchedLength(); + + while (-1 != tokenStart && (ignoreMax || l.count() < max - 1)) + { + if (!s.mid(searchStart, tokenStart - searchStart).isEmpty()) + l << s.mid(searchStart, tokenStart - searchStart); + + searchStart = tokenStart + len; + tokenStart = sep.search(s, searchStart); + len = sep.matchedLength(); + } + + if (!s.mid(searchStart, s.length() - searchStart).isEmpty()) + l << s.mid(searchStart, s.length() - searchStart); + + return l; +} +US end */ + +/*US + QString +KStringHandler::tagURLs( const QString& text ) +{ + QRegExp urlEx("(www\\.(?!\\.)|(f|ht)tp(|s)://)[\\d\\w\\./,:_~\\?=&;#@\\-\\+\\%]+[\\d\\w/]"); + + QString richText( text ); + int urlPos = 0, urlLen; + while ((urlPos = urlEx.search(richText, urlPos)) >= 0) + { + urlLen = urlEx.matchedLength(); + QString href = richText.mid( urlPos, urlLen ); + // Qt doesn't support (?<=pattern) so we do it here + if((urlPos > 0) && richText[urlPos-1].isLetterOrNumber()){ + urlPos++; + continue; + } + // Don't use QString::arg since %01, %20, etc could be in the string + QString anchor = "" + href + ""; + richText.replace( urlPos, urlLen, anchor ); + + + urlPos += anchor.length(); + } + return richText; +} +*/ +QString KStringHandler::obscure( const QString &str ) +{ + QString result; + for ( uint i = 0; i < str.length(); ++i ) + result += ( str.at( i ).unicode() < 0x20 ) ? str.at( i ) : + QChar( 0x1001F - str.at( i ).unicode() ); + + return result; +} diff --git a/microkde/kdecore/kstringhandler.h b/microkde/kdecore/kstringhandler.h new file mode 100644 index 0000000..d07b1e2 --- a/dev/null +++ b/microkde/kdecore/kstringhandler.h @@ -0,0 +1,417 @@ +/* This file is part of the KDE libraries + Copyright (C) 1999 Ian Zepp (icszepp@islc.net) + Copyright (C) 2000 Rik Hemsley (rikkus) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + 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. +*/ +#ifndef KSTRINGHANDLER_H +#define KSTRINGHANDLER_H + +#include // for atoi() +#include +#include +#include // for the word ranges +#include + +/** + * This class contains utility functions for handling strings. + * + * This class is @em not a substitute for the @ref QString class. What + * I tried to do with this class is provide an easy way to + * cut/slice/splice words inside sentences in whatever order desired. + * While the main focus of this class are words (ie characters + * separated by spaces/tabs), the two core functions here (@ref split() + * and @ref join() ) will function given any char to use as a separator. + * This will make it easy to redefine what a 'word' means in the + * future if needed. + * + * I freely stole some of the function names from python. I also think + * some of these were influenced by mIRC (yes, believe it if you will, I + * used to write a LOT of scripts in mIRC). + * + * The ranges are a fairly powerful way of getting/stripping words from + * a string. These ranges function, for the large part, as they would in + * python. See the @ref word(const QString&, int) and @ref remword(const QString&, int) functions for more detail. + * + * This class contains no data members of it own. All strings are cut + * on the fly and returned as new qstrings/qstringlists. + * + * Quick example on how to use: + * + *
+ * KStringHandler kstr;
+ * QString line = "This is a test of the strings";
+ *
+ * cout << "1> " << kstr.word( line , "4:" ) << "\n";
+ * cout << "2> " << kstr.remrange( line , "2:5" ) << "\n";
+ * cout << "2> " << kstr.reverse( line ) << "\n";
+ * cout << "2> " << kstr.center( kstr.word( line , 4 ) , 15 ) << "\n";
+ * 
+ * + * and so forth. + * + * @short Class for manipulating words and sentences in strings + * @author Ian Zepp + */ +class KStringHandler +{ +public: + /** Returns the nth word in the string if found + * Returns a EMPTY (not null) string otherwise. + * Note that the FIRST index is 0. + * @param text the string to search for the words + * @param pos the position of the word to search + * @return the word, or an empty string if not found + */ +//US static QString word( const QString &text , uint pos ); + + /** Returns a range of words from that string. + * Ie: + * @li "0" returns the very first word + * @li "0:" returns the first to the last word + * @li "0:3" returns the first to fourth words + * @li ":3" returns everything up to the fourth word + * + * If you grok python, you're set. + * @param text the string to search for the words + * @param range the words to return (see description) + * @return the words, or an empty string if not found + */ +//US static QString word( const QString &text , const char *range ); + + /** Inserts a word into the string, and returns + * a new string with the word included. the first + * index is zero (0). If there are not @p pos words in the original + * string, the new word will be appended to the end. + * @param text the original text + * @param word the word to insert + * @param pos the position (in words) for the new word + * @return the resulting string + */ +//US static QString insword( const QString &text , const QString &word , uint pos ); + + /** Replaces a word in the string, and returns + * a new string with the word included. the first + * index is zero (0). If there are not @p pos words in the original + * string, the new word will be appended to the end. + * @param text the original text + * @param word the word to insert + * @param pos the position (in words) for the new word + * @return the resulting string + */ +//US static QString setword( const QString &text , const QString &word , uint pos ); + + /** Removes a word or ranges of words from the string, + * and returns a new string. The ranges definitions + * follow the definitions for the word() function. + * + * @li "0" removes the very first word + * @li "0:" removes the first the the last word + * @li "0:3" removes the first to fourth words + * @li ":3" removes everything up to the fourth word + * @param text the original text + * @param range the words to remove (see description) + * @return the resulting string + */ +//US static QString remrange( const QString &text , const char *range ); + + + /** Removes a word at the given index, and returns a + * new string. The first index is zero (0). + * @param text the original text + * @param pos the position (in words) of thw word to delete + * @return the resulting string + */ +//US static QString remword( const QString &text , uint pos ); + + /** Removes a matching word from the string, and returns + * a new string. Note that only ONE match is removed. + * @param text the original text + * @param word the word to remove + * @return the resulting string + */ +//US static QString remword( const QString &text , const QString &word ); + + /** Capitalizes each word in the string + * "hello there" becomes "Hello There" (string) + * @param text the text to capitalize + * @return the resulting string + */ +//US static QString capwords( const QString &text ); + + /** Capitalizes each word in the list + * [hello, there] becomes [Hello, There] (list) + * @param list the list to capitalize + * @return the resulting list + */ +//US static QStringList capwords( const QStringList &list ); + + /** Reverses the order of the words in a string + * "hello there" becomes "there hello" (string) + * @param text the text to reverse + * @return the resulting string + */ +//US static QString reverse( const QString &text ); + + /** Reverses the order of the words in a list + * [hello, there] becomes [there, hello] (list) + * @param list the list to reverse + * @return the resulting list + */ +//US static QStringList reverse( const QStringList &list ); + + /** Left-justifies a string and returns a string at least 'width' characters + * wide. + * If the string is longer than the @p width, the original + * string is returned. It is never truncated. + * @param text the text to justify + * @param width the desired width of the new string + * @return the resulting string + */ +//US static QString ljust( const QString &text , uint width ); + + /** Right-justifies a string and returns a string at least 'width' characters + * wide. + * If the string is longer than the @p width, the original + * string is returned. It is never truncated. + * @param text the text to justify + * @param width the desired width of the new string + * @return the resulting string + */ +//US static QString rjust( const QString &text , uint width ); + + /** Centers a string and returns a string at least 'width' characters + * wide. + * If the string is longer than the @p width, the original + * string is returned. It is never truncated. + * @param text the text to justify + * @param width the desired width of the new string + * @return the resulting string + */ +//US static QString center( const QString &text , uint width ); + + /** Substitute characters at the beginning of a string by "...". + * @param str is the string to modify + * @param maxlen is the maximum length the modified string will have + * If the original string is shorter than "maxlen", it is returned verbatim + * @return the modified string + */ +//US static QString lsqueeze( const QString & str, uint maxlen = 40 ); + + /** Substitute characters at the beginning of a string by "...". Similar to + * method above, except that it truncates based on pixel width rather than + * the number of characters + * @param name is the string to modify + * @param fontMetrics is the font metrics to use to calculate character sizes + * @param maxlen is the maximum length in ems the modified string will have + * If the original string is shorter than "maxlen", it is returned verbatim + * @return the modified string + * @since 3.2 + */ +//US static QString lEmSqueeze( const QString & name, +//US const QFontMetrics& fontMetrics, +//US uint maxlen = 30 ); + + /** Substitute characters at the beginning of a string by "...". Similar to + * method above, except that maxlen is the width in pixels to truncate to + * @param name is the string to modify + * @param fontMetrics is the font metrics to use to calculate character sizes + * @param maxPixels is the maximum pixel length the modified string will have + * If the original string is shorter than "maxlen", it is returned verbatim + * @return the modified string + * @since 3.2 + */ +//US static QString lPixelSqueeze( const QString & name, +//US const QFontMetrics& fontMetrics, +//US uint maxPixels ); + + /** Substitute characters at the middle of a string by "...". + * @param str is the string to modify + * @param maxlen is the maximum length the modified string will have + * If the original string is shorter than "maxlen", it is returned verbatim + * @return the modified string + */ +//US static QString csqueeze( const QString & str, uint maxlen = 40 ); + + /** Substitute characters in the middle of a string by "...". Similar to + * method above, except that it truncates based on pixel width rather than + * the number of characters + * @param name is the string to modify + * @param fontMetrics is the font metrics to use to calculate character sizes + * @param maxlen is the maximum length in ems the modified string will have + * If the original string is shorter than "maxlen", it is returned verbatim + * @return the modified string + * @since 3.2 + */ +//US static QString cEmSqueeze( const QString & name, +//US const QFontMetrics& fontMetrics, +//US uint maxlen = 30 ); + + /** Substitute characters in the middle of a string by "...". Similar to + * method above, except that maxlen is the width in pixels to truncate to + * @param name is the string to modify + * @param fontMetrics is the font metrics to use to calculate character sizes + * @param maxPixels is the maximum pixel length the modified string will have + * If the original string is shorter than "maxlen", it is returned verbatim + * @return the modified string + * @since 3.2 + */ +//US static QString cPixelSqueeze( const QString & name, +//US const QFontMetrics& fontMetrics, +//US uint maxPixels ); + + /** Substitute characters at the end of a string by "...". + * @param str is the string to modify + * @param maxlen is the maximum length the modified string will have + * If the original string is shorter than "maxlen", it is returned verbatim + * @return the modified string + */ + static QString rsqueeze( const QString & str, uint maxlen = 40 ); + + /** Substitute characters at the end of a string by "...". Similar to + * method above, except that it truncates based on pixel width rather than + * the number of characters + * @param name is the string to modify + * @param fontMetrics is the font metrics to use to calculate character sizes + * @param maxlen is the maximum length in ems the modified string will have + * If the original string is shorter than "maxlen", it is returned verbatim + * @return the modified string + * @since 3.2 + */ +//US static QString rEmSqueeze( const QString & name, +//US const QFontMetrics& fontMetrics, +//US uint maxlen = 30 ); + + /** Substitute characters at the end of a string by "...". Similar to + * method above, except that maxlen is the width in pixels to truncate to + * @param name is the string to modify + * @param fontMetrics is the font metrics to use to calculate character sizes + * @param maxPixels is the maximum pixel length the modified string will have + * If the original string is shorter than "maxlen", it is returned verbatim + * @return the modified string + * @since 3.2 + */ +//US static QString rPixelSqueeze( const QString & name, +//US const QFontMetrics& fontMetrics, +//US uint maxPixels ); + + /** + * Match a filename. + * @param filename is the real decoded filename (or dirname + * without trailing '/'). + * @param pattern is a pattern like *.txt, *.tar.gz, Makefile.*, etc. + * Patterns with two asterisks like "*.*pk" are not supported. + * @return true if the given filename matches the given pattern + */ +//US static bool matchFileName( const QString& filename, const QString& pattern ); + + /** + * Split a QString into a QStringList in a similar fashion to the static + * QStringList function in Qt, except you can specify a maximum number + * of tokens. If max is specified (!= 0) then only that number of tokens + * will be extracted. The final token will be the remainder of the string. + * + * Example: + *
+     * perlSplit("__", "some__string__for__you__here", 4)
+     * QStringList contains: "some", "string", "for", "you__here"
+     * 
+ * + * @param sep is the string to use to delimit s. + * @param s is the input string + * @param max is the maximum number of extractions to perform, or 0. + * @return A QStringList containing tokens extracted from s. + */ +//US static QStringList perlSplit +//US (const QString & sep, const QString & s, uint max = 0); + + /** + * Split a QString into a QStringList in a similar fashion to the static + * QStringList function in Qt, except you can specify a maximum number + * of tokens. If max is specified (!= 0) then only that number of tokens + * will be extracted. The final token will be the remainder of the string. + * + * Example: + *
+     * perlSplit(' ', "kparts reaches the parts other parts can't", 3)
+     * QStringList contains: "kparts", "reaches", "the parts other parts can't"
+     * 
+ * + * @param sep is the character to use to delimit s. + * @param s is the input string + * @param max is the maximum number of extractions to perform, or 0. + * @return A QStringList containing tokens extracted from s. + */ +//US static QStringList perlSplit +//US (const QChar & sep, const QString & s, uint max = 0); + + /** + * Split a QString into a QStringList in a similar fashion to the static + * QStringList function in Qt, except you can specify a maximum number + * of tokens. If max is specified (!= 0) then only that number of tokens + * will be extracted. The final token will be the remainder of the string. + * + * Example: + *
+     * perlSplit(QRegExp("[! ]", "Split me up ! I'm bored ! OK ?", 3)
+     * QStringList contains: "Split", "me", "up ! I'm bored, OK ?"
+     * 
+ * + * @param sep is the regular expression to use to delimit s. + * @param s is the input string + * @param max is the maximum number of extractions to perform, or 0. + * @return A QStringList containing tokens extracted from s. + */ +//US static QStringList perlSplit +//US (const QRegExp & sep, const QString & s, uint max = 0); + + /** + * This method auto-detects URLs in strings, and adds HTML markup to them + * so that richtext or HTML-enabled widgets (such as KActiveLabel) + * will display the URL correctly. + * @param text the string which may contain URLs + * @return the resulting text + * @since 3.1 + */ +//US static QString tagURLs( const QString& text ); + + /** + Obscure string by using a simple symmetric encryption. Applying the + function to a string obscured by this function will result in the original + string. + + The function can be used to obscure passwords stored to configuration + files. Note that this won't give you any more security than preventing + that the password is directly copied and pasted. + + @param str string to be obscured + @return obscured string + @since 3.2 + */ + static QString obscure( const QString &str ); + +#ifdef KDE_NO_COMPAT +private: +#endif + /** + * @deprecated Use @see matchFileName () instead. + */ +/*US static bool matchFilename( const QString& filename, const QString& pattern ) + { + return matchFileName (filename, pattern); + }; +*/ +}; +#endif -- cgit v0.9.0.2