summaryrefslogtreecommitdiffstats
path: root/src/kvilib/system
diff options
context:
space:
mode:
authortpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-02-24 02:13:59 +0000
committertpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-02-24 02:13:59 +0000
commita6d58bb6052ac8cb01805a48c4ad2f129126116f (patch)
treedd867a099fcbb263a8009a9fb22695b87855dad6 /src/kvilib/system
downloadkvirc-a6d58bb6052ac8cb01805a48c4ad2f129126116f.tar.gz
kvirc-a6d58bb6052ac8cb01805a48c4ad2f129126116f.zip
Added KDE3 version of kvirc
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/kvirc@1095341 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'src/kvilib/system')
-rw-r--r--src/kvilib/system/Makefile.am5
-rw-r--r--src/kvilib/system/kvi_byteorder.h62
-rw-r--r--src/kvilib/system/kvi_env.cpp89
-rw-r--r--src/kvilib/system/kvi_env.h60
-rw-r--r--src/kvilib/system/kvi_library.h115
-rw-r--r--src/kvilib/system/kvi_locale.cpp1191
-rw-r--r--src/kvilib/system/kvi_locale.h146
-rw-r--r--src/kvilib/system/kvi_process.h37
-rw-r--r--src/kvilib/system/kvi_stdarg.h65
-rw-r--r--src/kvilib/system/kvi_thread.cpp644
-rw-r--r--src/kvilib/system/kvi_thread.h378
-rw-r--r--src/kvilib/system/kvi_time.cpp135
-rw-r--r--src/kvilib/system/kvi_time.h92
-rw-r--r--src/kvilib/system/moc_kvi_locale.cpp92
-rw-r--r--src/kvilib/system/moc_kvi_thread.cpp104
15 files changed, 3215 insertions, 0 deletions
diff --git a/src/kvilib/system/Makefile.am b/src/kvilib/system/Makefile.am
new file mode 100644
index 00000000..c84487eb
--- /dev/null
+++ b/src/kvilib/system/Makefile.am
@@ -0,0 +1,5 @@
+###############################################################################
+# KVirc IRC client Makefile - 16.12.98 Szymon Stefanek <[email protected]>
+###############################################################################
+
+EXTRA_DIST = *.cpp *.h
diff --git a/src/kvilib/system/kvi_byteorder.h b/src/kvilib/system/kvi_byteorder.h
new file mode 100644
index 00000000..dea1902d
--- /dev/null
+++ b/src/kvilib/system/kvi_byteorder.h
@@ -0,0 +1,62 @@
+#ifndef _KVI_BYTEORDER_H_
+#define _KVI_BYTEORDER_H_
+
+//=============================================================================
+//
+// File : kvi_byteorder.h
+// Creation date : Mon Dec 25 2006 19:56:16 CEST by Szymon Stefanek
+//
+// This file is part of the KVirc irc client distribution
+// Copyright (C) 2006 Szymon Stefanek (pragma at kvirc dot net)
+//
+// This program is FREE software. You can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your opinion) any later version.
+//
+// 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 General Public License
+// along with this program. If not, write to the Free Software Foundation,
+// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+//=============================================================================
+
+#include "kvi_settings.h"
+#include "kvi_bswap.h"
+#include "kvi_inttypes.h"
+
+
+//
+// Byte Orders Reminder
+// Number 0xaabbccdd
+// Little Endian Stores 0xdd 0xcc 0xbb 0xaa
+// Big Endian Stores 0xaa 0xbb 0xcc 0xdd
+// Perverse Middle Endian 0xbb 0xaa 0xdd 0xcc or another braindamaged combination (unsupported)
+// Network Byte Order is Big Endian
+// Intel Stuff uses Little Endian
+//
+
+#ifdef BIG_ENDIAN_MACHINE_BYTE_ORDER
+ #define kvi_localCpuToLittleEndian16(u) kvi_swap16((kvi_u16_t)(u))
+ #define kvi_localCpuToLittleEndian32(u) kvi_swap32((kvi_u32_t)(u))
+ #define kvi_localCpuToLittleEndian64(u) kvi_swap64((kvi_u64_t)(u))
+ #define kvi_littleEndianToLocalCpu16(u) kvi_swap16((kvi_u16_t)(u))
+ #define kvi_littleEndianToLocalCpu32(u) kvi_swap32((kvi_u32_t)(u))
+ #define kvi_littleEndianToLocalCpu64(u) kvi_swap64((kvi_u64_t)(u))
+#else
+ // We ASSUME that the local cpu is little endian.. if it isn't.. well :)
+ #define LOCAL_CPU_LITTLE_ENDIAN
+ #define kvi_localCpuToLittleEndian16(u) (u)
+ #define kvi_localCpuToLittleEndian32(u) (u)
+ #define kvi_localCpuToLittleEndian64(u) (u)
+ #define kvi_littleEndianToLocalCpu16(u) (u)
+ #define kvi_littleEndianToLocalCpu32(u) (u)
+ #define kvi_littleEndianToLocalCpu64(u) (u)
+#endif
+
+
+#endif // !_KVI_BYTEORDER_H_
diff --git a/src/kvilib/system/kvi_env.cpp b/src/kvilib/system/kvi_env.cpp
new file mode 100644
index 00000000..1497632e
--- /dev/null
+++ b/src/kvilib/system/kvi_env.cpp
@@ -0,0 +1,89 @@
+//=============================================================================
+//
+// File : kvi_env.cpp
+// Creation date : Sat May 05 2002 02:15:21 CEST by Szymon Stefanek
+//
+// This file is part of the KVirc irc client distribution
+// Copyright (C) 2002 Szymon Stefanek ([email protected])
+//
+// This program is FREE software. You can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your opinion) any later version.
+//
+// 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 General Public License
+// along with this program. If not, write to the Free Software Foundation,
+// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+//=============================================================================
+#define __KVILIB__
+
+#define _KVI_ENV_CPP_
+
+#include "kvi_env.h"
+#include "kvi_string.h"
+#include "kvi_malloc.h"
+#include "kvi_memmove.h"
+
+#ifndef COMPILE_ON_WINDOWS
+
+bool kvi_setenv(const char * name,const char * value)
+{
+#ifdef HAVE_SETENV
+ return (setenv(name,value,1) == 0);
+#else
+ #ifdef HAVE_PUTENV
+ int iLen1 = kvi_strLen(name);
+ int iLen2 = kvi_strLen(value);
+ char * buf = (char *)kvi_malloc(iLen1 + iLen2 + 2);
+ kvi_memmove(buf,name,iLen1);
+ *(buf + iLen1) = '=';
+ kvi_memmove(buf + iLen1 + 1,value,iLen2);
+ *(buf + iLen1 + iLen2 + 1) = '\0';
+ int iRet = putenv(buf);
+ if(iRet != 0)
+ {
+ kvi_free(buf);
+ return false;
+ }
+ return true;
+ #else
+ // no setenv , no putenv.. what the hell of system is this ?
+ return false;
+ #endif
+#endif
+}
+
+void kvi_unsetenv(const char * name)
+{
+#ifdef HAVE_UNSETENV
+ unsetenv(name);
+#else
+ #ifdef HAVE_PUTENV
+ int iLen1 = kvi_strLen(name);
+ char * buf = (char *)kvi_malloc(iLen1 + 1);
+ kvi_memmove(buf,name,iLen1);
+ *(buf + iLen1) = '\0';
+ int iRet = putenv(buf);
+ if(iRet != 0)
+ {
+ kvi_free(buf);
+ } else {
+ // hmmm
+ if(kvi_getenv(name) == 0)
+ {
+ // ok , the string is not in the environment
+ // we can free it
+ kvi_free(buf);
+ } // else this system sux
+ }
+ #endif
+#endif
+}
+
+#endif //!COMPILE_ON_WINDOWS
diff --git a/src/kvilib/system/kvi_env.h b/src/kvilib/system/kvi_env.h
new file mode 100644
index 00000000..b3b24a2f
--- /dev/null
+++ b/src/kvilib/system/kvi_env.h
@@ -0,0 +1,60 @@
+#ifndef _KVI_ENV_H_
+#define _KVI_ENV_H_
+
+//=============================================================================
+//
+// File : kvi_env.h
+// Creation date : Sat May 05 2002 02:15:21 CEST by Szymon Stefanek
+//
+// This file is part of the KVirc irc client distribution
+// Copyright (C) 2002 Szymon Stefanek ([email protected])
+//
+// This program is FREE software. You can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your opinion) any later version.
+//
+// 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 General Public License
+// along with this program. If not, write to the Free Software Foundation,
+// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+//=============================================================================
+
+//=============================================================================
+// Enviroinement function wrappers
+//=============================================================================
+
+#include "kvi_settings.h"
+
+
+
+#include <stdlib.h>
+
+inline char * kvi_getenv(const char * name)
+{
+#ifdef HAVE_GETENV
+ return getenv(name);
+#else
+ return 0;
+#endif
+}
+
+#ifdef COMPILE_ON_WINDOWS
+ #define kvi_setenv(__name,__value) SetEnvironmentVariable(__name,__value)
+ #define kvi_unsetenv(__name) SetEnvironmentVariable(__name,NULL)
+#else
+ #ifndef _KVI_ENV_CPP_
+ KVILIB_API extern bool kvi_setenv(const char * name,const char * value);
+ KVILIB_API extern void kvi_unsetenv(const char * name);
+ #endif
+#endif
+
+
+
+
+#endif //_KVI_ENV_H_
diff --git a/src/kvilib/system/kvi_library.h b/src/kvilib/system/kvi_library.h
new file mode 100644
index 00000000..393ed5c7
--- /dev/null
+++ b/src/kvilib/system/kvi_library.h
@@ -0,0 +1,115 @@
+#ifndef _KVI_LIBRARY_H_
+#define _KVI_LIBRARY_H_
+
+//=====================================================================================
+//
+// File : kvi_library.h
+// Creation date : Tue Sep 25 16:20:40 2001 GMT by Szymon Stefanek
+//
+// This file is part of the KVirc irc client distribution
+// Copyright (C) 2001 Szymon Stefanek (pragma at kvirc dot net)
+//
+// This program is FREE software. You can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your opinion) any later version.
+//
+// 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 General Public License
+// along with this program. If not, write to the Free Software Foundation,
+// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+//=====================================================================================
+
+
+//=====================================================================================
+// System dynamic linker interface abstraction
+//=====================================================================================
+
+
+#include "kvi_settings.h"
+
+
+#ifdef COMPILE_ON_WINDOWS
+
+ //#include <windows.h>
+ #include <winsock2.h> // this will pull in windows.h
+
+ typedef HMODULE kvi_library_t;
+
+ inline kvi_library_t kvi_library_open(const char * path)
+ {
+#ifndef DEBUG
+ // this is to avoid the ugly message boxes when the dll has
+ // ... but do it only in release mode
+ UINT nOldErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
+#endif
+ kvi_library_t ret = LoadLibrary(path);
+#ifndef DEBUG
+ SetErrorMode(nOldErrorMode);
+#endif
+ return ret;
+ };
+
+ inline void kvi_library_close(kvi_library_t lib)
+ {
+ FreeLibrary(lib);
+ };
+
+ inline void * kvi_library_symbol(kvi_library_t lib,const char * symName)
+ {
+ return GetProcAddress(lib,symName);
+ };
+
+ inline const char * kvi_library_error()
+ {
+ return "Windoze-like error";
+ };
+
+#else
+
+ #include <dlfcn.h>
+
+ // sparc-unknown-openbsd3.0 (At least) has only RTLD_LAZY
+ #ifndef RTLD_NOW
+ #define RTLD_NOW RTLD_LAZY
+ #endif
+ #ifndef RTLD_GLOBAL
+ #define RTLD_GLOBAL 0
+ #endif
+
+ typedef void * kvi_library_t;
+
+ inline kvi_library_t kvi_library_open(const char * path)
+ {
+ return dlopen(path,RTLD_GLOBAL | RTLD_NOW);
+ };
+
+ inline void kvi_library_close(kvi_library_t lib)
+ {
+ dlclose(lib);
+ };
+
+
+ inline void * kvi_library_symbol(kvi_library_t lib,const char * symName)
+ {
+ return dlsym(lib,symName);
+ };
+
+ inline const char * kvi_library_error()
+ {
+ return dlerror();
+ };
+
+
+#endif //!COMPILE_ON_WINDOWS
+
+
+#define kvi_library_load kvi_library_open
+#define kvi_library_unload kvi_library_close
+
+#endif //_KVI_LIBRARY_H_
diff --git a/src/kvilib/system/kvi_locale.cpp b/src/kvilib/system/kvi_locale.cpp
new file mode 100644
index 00000000..f49eabe4
--- /dev/null
+++ b/src/kvilib/system/kvi_locale.cpp
@@ -0,0 +1,1191 @@
+//=============================================================================
+//
+// File : kvi_locale.cpp
+// Creation date : Fri Mar 19 1999 19:08:41 by Szymon Stefanek
+//
+// This file is part of the KVirc irc client distribution
+// Copyright (C) 1999-2002 Szymon Stefanek (pragma at kvirc dot net)
+//
+// This program is FREE software. You can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your opinion) any later version.
+//
+// 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 General Public License
+// along with this program. If not, write to the Free Software Foundation,
+// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+//=============================================================================
+
+#define __KVILIB__
+
+
+//#define _KVI_DEBUG_CHECK_RANGE_
+#include "kvi_debug.h"
+#include "kvi_malloc.h"
+#include "kvi_bswap.h"
+
+#define _KVI_LOCALE_CPP_
+#include "kvi_locale.h"
+
+#include <qglobal.h> //for debug()
+#include <qtextcodec.h>
+#include <qdir.h>
+
+#ifdef COMPILE_USE_QT4
+ #include <qlocale.h>
+#endif
+
+#include "kvi_string.h"
+#include "kvi_qcstring.h"
+#include "kvi_env.h"
+#include "kvi_fileutils.h"
+#include "kvi_file.h"
+
+
+KVILIB_API KviMessageCatalogue * g_pMainCatalogue = 0;
+
+static KviStr g_szLang;
+static KviTranslator * g_pTranslator = 0;
+static KviPointerHashTable<const char *,KviMessageCatalogue> * g_pCatalogueDict = 0;
+static QTextCodec * g_pUtf8TextCodec = 0;
+
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// The following code was extracted and adapted from gutf8.c
+// from the GNU GLIB2 package.
+//
+// gutf8.c - Operations on UTF-8 strings.
+//
+// Copyright (C) 1999 Tom Tromey
+// Copyright (C) 2000 Red Hat, Inc.
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser 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
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the
+// Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+// Boston, MA 02110-1301, USA.
+//
+/////////////////////////////////////////////////////////////////////////////////////////////////////
+
+typedef char gchar;
+typedef unsigned char guchar;
+typedef signed int gssize;
+typedef unsigned int gunichar;
+
+
+
+#define UNICODE_VALID(Char) \
+ ((Char) < 0x110000 && \
+ (((Char) & 0xFFFFF800) != 0xD800) && \
+ ((Char) < 0xFDD0 || (Char) > 0xFDEF) && \
+ ((Char) & 0xFFFE) != 0xFFFE)
+
+#define CONTINUATION_CHAR \
+ if ((*(guchar *)p & 0xc0) != 0x80) /* 10xxxxxx */ \
+ goto error; \
+ val <<= 6; \
+ val |= (*(guchar *)p) & 0x3f;
+
+
+static const char *
+fast_validate (const char *str)
+
+{
+ gunichar val = 0;
+ gunichar min = 0;
+ const gchar *p;
+
+ for (p = str; *p; p++)
+ {
+ if (*(guchar *)p < 128)
+ /* done */;
+ else
+ {
+ const gchar *last;
+
+ last = p;
+ if ((*(guchar *)p & 0xe0) == 0xc0) /* 110xxxxx */
+ {
+ if ((*(guchar *)p & 0x1e) == 0)
+ goto error;
+ p++;
+ if ((*(guchar *)p & 0xc0) != 0x80) /* 10xxxxxx */
+ goto error;
+ }
+ else
+ {
+ if ((*(guchar *)p & 0xf0) == 0xe0) /* 1110xxxx */
+ {
+ min = (1 << 11);
+ val = *(guchar *)p & 0x0f;
+ goto TWO_REMAINING;
+ }
+ else if ((*(guchar *)p & 0xf8) == 0xf0) /* 11110xxx */
+ {
+ min = (1 << 16);
+ val = *(guchar *)p & 0x07;
+ }
+ else
+ goto error;
+
+ p++;
+ CONTINUATION_CHAR;
+ TWO_REMAINING:
+ p++;
+ CONTINUATION_CHAR;
+ p++;
+ CONTINUATION_CHAR;
+
+ if (val < min)
+ goto error;
+
+ if (!UNICODE_VALID(val))
+ goto error;
+ }
+
+ continue;
+
+ error:
+ return last;
+ }
+ }
+
+ return p;
+}
+
+static const gchar *
+fast_validate_len (const char *str,
+ gssize max_len)
+
+{
+ gunichar val = 0;
+ gunichar min = 0;
+ const gchar *p;
+
+ for (p = str; (max_len < 0 || (p - str) < max_len) && *p; p++)
+ {
+ if (*(guchar *)p < 128)
+ /* done */;
+ else
+ {
+ const gchar *last;
+
+ last = p;
+ if ((*(guchar *)p & 0xe0) == 0xc0) /* 110xxxxx */
+ {
+ if (max_len >= 0 && max_len - (p - str) < 2)
+ goto error;
+
+ if ((*(guchar *)p & 0x1e) == 0)
+ goto error;
+ p++;
+ if ((*(guchar *)p & 0xc0) != 0x80) /* 10xxxxxx */
+ goto error;
+ }
+ else
+ {
+ if ((*(guchar *)p & 0xf0) == 0xe0) /* 1110xxxx */
+ {
+ if (max_len >= 0 && max_len - (p - str) < 3)
+ goto error;
+
+ min = (1 << 11);
+ val = *(guchar *)p & 0x0f;
+ goto TWO_REMAINING;
+ }
+ else if ((*(guchar *)p & 0xf8) == 0xf0) /* 11110xxx */
+ {
+ if (max_len >= 0 && max_len - (p - str) < 4)
+ goto error;
+
+ min = (1 << 16);
+ val = *(guchar *)p & 0x07;
+ }
+ else
+ goto error;
+
+ p++;
+ CONTINUATION_CHAR;
+ TWO_REMAINING:
+ p++;
+ CONTINUATION_CHAR;
+ p++;
+ CONTINUATION_CHAR;
+
+ if (val < min)
+ goto error;
+ if (!UNICODE_VALID(val))
+ goto error;
+ }
+
+ continue;
+
+ error:
+ return last;
+ }
+ }
+
+ return p;
+}
+
+static bool g_utf8_validate (const char *str,
+ gssize max_len,
+ const gchar **end)
+
+{
+ const gchar *p;
+
+ if (max_len < 0)
+ p = fast_validate (str);
+ else
+ p = fast_validate_len (str, max_len);
+
+ if (end)
+ *end = p;
+
+ if ((max_len >= 0 && p != str + max_len) ||
+ (max_len < 0 && *p != '\0'))
+ return false;
+ else
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////
+// End of gutf8.c
+///////////////////////////////////////////////////////////////////////////////////////////////
+
+
+class KviSmartTextCodec : public QTextCodec
+{
+protected:
+ KviQCString m_szName;
+ QTextCodec * m_pRecvCodec;
+ QTextCodec * m_pSendCodec;
+public:
+ KviSmartTextCodec(const char * szName,const char * szChildCodecName,bool bSendInUtf8)
+ : QTextCodec()
+ {
+ m_szName = szName;
+ if(!g_pUtf8TextCodec)
+ {
+ g_pUtf8TextCodec = QTextCodec::codecForName("UTF-8");
+ if(!g_pUtf8TextCodec)
+ {
+ debug("Can't find the global utf8 text codec!");
+ g_pUtf8TextCodec = QTextCodec::codecForLocale(); // try anything else...
+ }
+ }
+ m_pRecvCodec = QTextCodec::codecForName(szChildCodecName);
+ if(!m_pRecvCodec)
+ {
+ debug("Can't find the codec for name %s (composite codec creation)",szName);
+ m_pRecvCodec = g_pUtf8TextCodec;
+ }
+ if(bSendInUtf8)
+ m_pSendCodec = g_pUtf8TextCodec;
+ else
+ m_pSendCodec = m_pRecvCodec;
+ }
+public:
+ bool ok(){ return m_pRecvCodec && g_pUtf8TextCodec; };
+
+ virtual int mibEnum () const { return 0; };
+
+#ifdef COMPILE_USE_QT4
+ virtual QByteArray name() const { return m_szName; };
+protected:
+ virtual QByteArray convertFromUnicode(const QChar * input,int number,ConverterState * state) const
+ {
+ return m_pSendCodec->fromUnicode(input,number,state);
+ }
+ virtual QString convertToUnicode(const char * chars,int len,ConverterState * state) const
+ {
+ if(g_utf8_validate(chars,len,NULL))return g_pUtf8TextCodec->toUnicode(chars,len,state);
+ return m_pRecvCodec->toUnicode(chars,len,state);
+ }
+#else
+public:
+ virtual const char * mimeName () const { return m_pRecvCodec->mimeName(); };
+ virtual const char * name () const { return m_szName.data(); };
+ virtual QTextDecoder * makeDecoder () const { return m_pRecvCodec->makeDecoder(); };
+ virtual QTextEncoder * makeEncoder () const { return m_pSendCodec->makeEncoder(); };
+ QCString fromUnicode (const QString & uc) const { return m_pSendCodec->fromUnicode(uc); };
+ virtual QCString fromUnicode (const QString & uc,int & lenInOut) const { return m_pSendCodec->fromUnicode(uc,lenInOut); };
+ QString toUnicode(const char * chars) const
+ {
+ if(g_utf8_validate(chars,-1,NULL))return g_pUtf8TextCodec->toUnicode(chars);
+ return m_pRecvCodec->toUnicode(chars);
+ };
+ virtual QString toUnicode(const char * chars,int len) const
+ {
+ if(g_utf8_validate(chars,len,NULL))return g_pUtf8TextCodec->toUnicode(chars,len);
+ return m_pRecvCodec->toUnicode(chars,len);
+ };
+ QString toUnicode(const QByteArray & a,int len) const
+ {
+ if(g_utf8_validate(a.data(),len,NULL))return g_pUtf8TextCodec->toUnicode(a,len);
+ return m_pRecvCodec->toUnicode(a,len);
+ };
+ QString toUnicode(const QByteArray & a) const
+ {
+ if(g_utf8_validate(a.data(),a.size(),NULL))return g_pUtf8TextCodec->toUnicode(a);
+ return m_pRecvCodec->toUnicode(a);
+ };
+ QString toUnicode(const QCString & a,int len) const
+ {
+ if(g_utf8_validate(a.data(),len,NULL))return g_pUtf8TextCodec->toUnicode(a,len);
+ return m_pRecvCodec->toUnicode(a,len);
+ };
+ QString toUnicode(const QCString & a) const
+ {
+ if(g_utf8_validate(a.data(),-1,NULL))return g_pUtf8TextCodec->toUnicode(a);
+ return m_pRecvCodec->toUnicode(a);
+ };
+
+ virtual bool canEncode(QChar ch) const { return m_pSendCodec->canEncode(ch); };
+ virtual bool canEncode(const QString &s) const { return m_pSendCodec->canEncode(s); };
+ virtual int heuristicContentMatch(const char * chars,int len) const
+ {
+ int iii = g_pUtf8TextCodec->heuristicContentMatch(chars,len);
+ if(iii < 0)return m_pRecvCodec->heuristicContentMatch(chars,len);
+ return iii;
+ }
+ virtual int heuristicNameMatch(const char * hint) const { return 0; };
+#endif
+};
+
+static KviPointerHashTable<const char *,KviSmartTextCodec> * g_pSmartCodecDict = 0;
+
+
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// The following code was extracted and adapted from gettext.h and gettextP.h
+// from the GNU gettext package.
+//
+// Internal header for GNU gettext internationalization functions.
+// Copyright (C) 1995, 1997 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2, or (at your option)
+// any later version.
+//
+// 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 the GNU C Library; see the file COPYING.LIB. If not,
+// write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+// Boston, MA 02110-1301, USA.
+//
+/////////////////////////////////////////////////////////////////////////////////////////////////////
+
+#include <stdio.h>
+
+#if HAVE_LIMITS_H || _LIBC
+ #include <limits.h>
+#endif
+
+// The magic number of the GNU message catalog format.
+#define KVI_LOCALE_MAGIC 0x950412de
+#define KVI_LOCALE_MAGIC_SWAPPED 0xde120495
+
+// Revision number of the currently used .mo (binary) file format.
+#define MO_REVISION_NUMBER 0
+
+
+// Header for binary .mo file format.
+struct GnuMoFileHeader
+{
+ // The magic number.
+ kvi_u32_t magic;
+ // The revision number of the file format.
+ kvi_u32_t revision;
+ // The number of strings pairs.
+ kvi_u32_t nstrings;
+ // Offset of table with start offsets of original strings.
+ kvi_u32_t orig_tab_offset;
+ // Offset of table with start offsets of translation strings.
+ kvi_u32_t trans_tab_offset;
+ // Size of hashing table.
+ kvi_u32_t hash_tab_size;
+ // Offset of first hashing entry.
+ kvi_u32_t hash_tab_offset;
+};
+
+struct GnuMoStringDescriptor
+{
+ // Length of addressed string.
+ kvi_u32_t length;
+ // Offset of string in file.
+ kvi_u32_t offset;
+};
+
+#define KVI_SWAP_IF_NEEDED(flag,value) (flag ? kvi_swap32(value) : (value))
+
+///////////////////////////////////////////////////////////////////////////////////////////////
+// End of gettext.h & gettextP.h
+///////////////////////////////////////////////////////////////////////////////////////////////
+
+
+// HELPERS
+
+static int somePrimeNumbers[90]=
+{
+ 257 , 521 , 769 , 1031, 1087, 1091, 1103, 1117, 1123, 1151, // Incomplete *.mo files
+ 1163, 1171, 1181, 1193, 1201, 1213, 1217, 1223, 1229, 1231, // Complete *.mo files
+ 1237, 1249, 1259, 1277, 1283, 1289, 1291, 1297, 1307, 1319,
+ 1321, 1327, 1361, 1367, 1373, 1381, 1399, 1409, 1423, 1433,
+ 1447, 1459, 1471, 1481, 1493, 1511, 1523, 1531, 1543, 1553,
+ 1567, 1571, 1583, 1597, 1609, 1619, 1627, 1637, 1657, 1667, // Too big for KVIrc *.mo files
+ 1693, 1709, 1721, 1733, 1741, 1753, 1777, 1789, 1811, 1831,
+ 1907, 2069, 2111, 2221, 2309, 2441, 2531, 2617, 2731, 2837,
+ 2903, 3121, 3329, 3331, 3767, 4127, 5051, 6089, 7039, 9973
+};
+
+int kvi_getFirstBiggerPrime(int number)
+{
+ for(int i=0;i<90;i++){
+ if(somePrimeNumbers[i] >= number)return somePrimeNumbers[i];
+ }
+ return 9973; //error!
+}
+
+
+KviMessageCatalogue::KviMessageCatalogue()
+{
+ //m_uEncoding = 0;
+ m_pTextCodec = QTextCodec::codecForLocale();
+
+ //m_pMessages = new KviPointerHashTable<const char *,KviTranslationEntry>(1123,true,false); // dictSize, case sensitive , don't copy keys
+ m_pMessages = new KviPointerHashTable<const char *,KviTranslationEntry>(32,true,false); // dictSize, case sensitive , don't copy keys
+ m_pMessages->setAutoDelete(true);
+}
+
+KviMessageCatalogue::~KviMessageCatalogue()
+{
+ if(m_pMessages)
+ delete m_pMessages;
+}
+
+bool KviMessageCatalogue::load(const QString& name)
+{
+ QString szCatalogueFile(name);
+
+ // Try to load the header
+ KviFile f(szCatalogueFile);
+ if(!f.openForReading())
+ {
+ debug("[KviLocale]: Failed to open the messages file %s: probably doesn't exist",KviQString::toUtf8(szCatalogueFile).data());
+ return false;
+ }
+
+ GnuMoFileHeader hdr;
+
+ if(f.readBlock((char *)&hdr,sizeof(GnuMoFileHeader)) < (int)sizeof(GnuMoFileHeader))
+ {
+ debug("KviLocale: Failed to read header of %s",KviQString::toUtf8(szCatalogueFile).data());
+ f.close();
+ return false;
+ }
+
+ bool bMustSwap = false;
+
+ if(hdr.magic != KVI_LOCALE_MAGIC)
+ {
+ if(hdr.magic == KVI_LOCALE_MAGIC_SWAPPED)
+ {
+ debug("KviLocale: Swapped magic for file %s: swapping data too",KviQString::toUtf8(szCatalogueFile).data());
+ bMustSwap = true;
+ } else {
+ debug("KviLocale: Bad locale magic for file %s: not a *.mo file ?",KviQString::toUtf8(szCatalogueFile).data());
+ f.close();
+ return false;
+ }
+ }
+
+ if(KVI_SWAP_IF_NEEDED(bMustSwap,hdr.revision) != MO_REVISION_NUMBER)
+ {
+ debug("KviLocale: Invalid *.mo file revision number for file %s",KviQString::toUtf8(szCatalogueFile).data());
+ f.close();
+ return false;
+ }
+
+ int numberOfStrings = KVI_SWAP_IF_NEEDED(bMustSwap,hdr.nstrings);
+
+ if(numberOfStrings <= 0)
+ {
+ debug("KviLocale: No translated messages found in file %s",KviQString::toUtf8(szCatalogueFile).data());
+ f.close();
+ return false;
+ }
+
+ if(numberOfStrings >= 9972)
+ {
+ debug("Number of strings too big...sure that it is a KVIrc catalog file ?");
+ numberOfStrings = 9972;
+ }
+
+ // return back
+ f.seek(0);
+
+ unsigned int fSize = f.size();
+ char * buffer = (char *)kvi_malloc(fSize);
+
+ // FIXME: maybe read it in blocks eh ?
+ if(f.readBlock(buffer,fSize) < (int)fSize)
+ {
+ debug("KviLocale: Error while reading the translation file %s",KviQString::toUtf8(szCatalogueFile).data());
+ kvi_free(buffer);
+ f.close();
+ return false;
+ }
+
+ // Check for broken *.mo files
+ if(fSize < (24 + (sizeof(GnuMoStringDescriptor) * numberOfStrings)))
+ {
+ debug("KviLocale: Broken translation file %s (too small for all descriptors)",KviQString::toUtf8(szCatalogueFile).data());
+ kvi_free(buffer);
+ f.close();
+ return false;
+ }
+
+ GnuMoStringDescriptor * origDescriptor = (GnuMoStringDescriptor *)(buffer + KVI_SWAP_IF_NEEDED(bMustSwap,hdr.orig_tab_offset));
+ GnuMoStringDescriptor * transDescriptor = (GnuMoStringDescriptor *)(buffer + KVI_SWAP_IF_NEEDED(bMustSwap,hdr.trans_tab_offset));
+
+ // Check again for broken *.mo files
+ int expectedFileSize = KVI_SWAP_IF_NEEDED(bMustSwap,transDescriptor[numberOfStrings - 1].offset) +
+ KVI_SWAP_IF_NEEDED(bMustSwap,transDescriptor[numberOfStrings - 1].length);
+
+ if(fSize < (unsigned int)expectedFileSize)
+ {
+ debug("KviLocale: Broken translation file %s (too small for all the message strings)",KviQString::toUtf8(szCatalogueFile).data());
+ kvi_free(buffer);
+ f.close();
+ return false;
+ }
+
+ // Ok...we can run now
+
+ int dictSize = kvi_getFirstBiggerPrime(numberOfStrings);
+ if(m_pMessages)
+ delete m_pMessages;
+ m_pMessages = new KviPointerHashTable<const char *,KviTranslationEntry>(dictSize,true,false); // dictSize, case sensitive , don't copy keys
+ m_pMessages->setAutoDelete(true);
+
+ KviStr szHeader;
+
+ for(int i=0;i < numberOfStrings;i++)
+ {
+ // FIXME: "Check for NULL inside strings here ?"
+ //debug("original seems to be at %u and %u byttes long",KVI_SWAP_IF_NEEDED(bMustSwap,origDescriptor[i].offset),
+ // KVI_SWAP_IF_NEEDED(bMustSwap,origDescriptor[i].length));
+ //debug("translated seems to be at %u and %u byttes long",KVI_SWAP_IF_NEEDED(bMustSwap,transDescriptor[i].offset),
+ // KVI_SWAP_IF_NEEDED(bMustSwap,transDescriptor[i].length));
+
+ KviTranslationEntry * e = new KviTranslationEntry(
+ (char *)(buffer + KVI_SWAP_IF_NEEDED(bMustSwap,origDescriptor[i].offset)),
+ KVI_SWAP_IF_NEEDED(bMustSwap,origDescriptor[i].length),
+ (char *)(buffer + KVI_SWAP_IF_NEEDED(bMustSwap,transDescriptor[i].offset)),
+ KVI_SWAP_IF_NEEDED(bMustSwap,transDescriptor[i].length));
+
+ // In some (or all?) *.mo files the first string
+ // is zero bytes long and the translated one contains
+ // informations about the translation
+ if(e->m_szKey.len() == 0)
+ {
+ szHeader = e->m_szEncodedTranslation;
+ delete e;
+ continue;
+ }
+
+ m_pMessages->insert(e->m_szKey.ptr(),e);
+ }
+
+ kvi_free(buffer);
+ f.close();
+
+ m_pTextCodec = 0;
+
+ // find out the text encoding , if possible
+ if(szHeader.hasData())
+ {
+ // find "charset=*\n"
+ int idx = szHeader.findFirstIdx("charset=");
+ if(idx != -1)
+ {
+ szHeader.cutLeft(idx + 8);
+ szHeader.cutFromFirst('\n');
+ szHeader.stripWhiteSpace();
+ m_pTextCodec = KviLocale::codecForName(szHeader.ptr());
+ if(!m_pTextCodec)
+ {
+ debug("Can't find the codec for charset=%s",szHeader.ptr());
+ debug("Falling back to codecForLocale()");
+ m_pTextCodec = QTextCodec::codecForLocale();
+ }
+ }
+ }
+
+ if(!m_pTextCodec)
+ {
+ debug("The message catalogue does not have a \"charset\" header");
+ debug("Assuming utf8"); // FIXME: or codecForLocale() ?
+ m_pTextCodec = QTextCodec::codecForName("UTF-8");
+ }
+
+ return true;
+}
+
+const char * KviMessageCatalogue::translate(const char *text)
+{
+ KviTranslationEntry * aux = m_pMessages->find(text);
+ if(aux)return aux->m_szEncodedTranslation.ptr();
+ return text;
+}
+
+const QString & KviMessageCatalogue::translateToQString(const char *text)
+{
+ KviTranslationEntry * aux = m_pMessages->find(text);
+ if(aux)
+ {
+ if(aux->m_pQTranslation)return *(aux->m_pQTranslation);
+ aux->m_pQTranslation = new QString(m_pTextCodec->toUnicode(aux->m_szEncodedTranslation.ptr()));
+ return *(aux->m_pQTranslation);
+ }
+ // no translation is available: let's avoid continous string decoding
+ aux = new KviTranslationEntry(text);
+ m_pMessages->insert(aux->m_szKey.ptr(),aux);
+ aux->m_pQTranslation = new QString(m_pTextCodec->toUnicode(aux->m_szEncodedTranslation.ptr()));
+ return *(aux->m_pQTranslation);
+}
+
+
+
+
+namespace KviLocale
+{
+#ifndef QT_NO_BIG_CODECS
+ #define NUM_ENCODINGS 109
+#else
+ #define NUM_ENCODINGS 85
+#endif
+
+
+
+ static EncodingDescription supported_encodings[]=
+ {
+ { "UTF-8" , 0 , 0 , "8-bit Unicode" },
+ { "ISO-8859-1" , 0 , 0 , "Western, Latin-1" },
+ { "ISO-8859-2" , 0 , 0 , "Central European 1" },
+ { "ISO-8859-3" , 0 , 0 , "Central European 2" },
+ { "ISO-8859-4" , 0 , 0 , "Baltic, Standard" },
+ { "ISO-8859-5" , 0 , 0 , "Cyrillic, ISO" },
+ { "ISO-8859-6" , 0 , 0 , "Arabic, Standard" },
+ { "ISO-8859-7" , 0 , 0 , "Greek" },
+ { "ISO-8859-8" , 0 , 0 , "Hebrew, visually ordered" },
+ { "ISO-8859-8-i" , 0 , 0 , "Hebrew, logically ordered" },
+ { "ISO-8859-9" , 0 , 0 , "Turkish, Latin-5" },
+ { "ISO-8859-15" , 0 , 0 , "Western, Latin-1 + Euro" },
+ { "KOI8-R" , 0 , 0 , "Cyrillic, KOI" },
+ { "KOI8-U" , 0 , 0 , "Ukrainian" },
+ { "CP-1250" , 0 , 0 , "Central European 3" },
+ { "CP-1251" , 0 , 0 , "Cyrillic, Windows" },
+ { "CP-1252" , 0 , 0 , "Western, CP" },
+ { "CP-1253" , 0 , 0 , "Greek, CP" },
+ { "CP-1256" , 0 , 0 , "Arabic, CP" },
+ { "CP-1257" , 0 , 0 , "Baltic, CP" },
+ { "CP-1255" , 0 , 0 , "Hebrew, CP" },
+ { "CP-1254" , 0 , 0 , "Turkish, CP" },
+ { "TIS-620" , 0 , 0 , "Thai" },
+#ifndef QT_NO_BIG_CODECS
+ { "Big5" , 0 , 0 , "Chinese Traditional" },
+ { "Big5-HKSCS" , 0 , 0 , "Chinese Traditional, Hong Kong" },
+ { "GB18030" , 0 , 0 , "Chinese Simplified" },
+ { "JIS7" , 0 , 0 , "Japanese (JIS7)" },
+ { "Shift-JIS" , 0 , 0 , "Japanese (Shift-JIS)" },
+ { "EUC-JP" , 0 , 0 , "Japanese (EUC-JP)" },
+ { "EUC-KR" , 0 , 0 , "Korean" },
+ { "TSCII" , 0 , 0 , "Tamil" },
+#endif
+ { "ISO-8859-10" , 0 , 0 , "ISO-8859-10" },
+ { "ISO-8859-13" , 0 , 0 , "ISO-8859-13" },
+ { "ISO-8859-14" , 0 , 0 , "ISO-8859-14" },
+ { "IBM-850" , 0 , 0 , "IBM-850" },
+ { "IBM-866" , 0 , 0 , "IBM-866" },
+ { "CP874" , 0 , 0 , "CP874" },
+
+ // smart codecs that send in the local charset
+ { "ISO-8859-1 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Western Latin-1, O: Western Latin-1" },
+ { "ISO-8859-2 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Central European 1, O: Central European 1" },
+ { "ISO-8859-3 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Central European 2, O: Central European 2" },
+ { "ISO-8859-4 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Baltic, Standard, O: Baltic, Standard" },
+ { "ISO-8859-5 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Cyrillic, ISO, O: Cyrillic, ISO" },
+ { "ISO-8859-6 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Arabic, Standard, O: Arabic, Standard" },
+ { "ISO-8859-7 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Greek, O: Greek" },
+ { "ISO-8859-8 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Hebrew, visually ordered, O: Hebrew, visually ordered" },
+ { "ISO-8859-8-i [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Hebrew, logically ordered, O: Hebrew, logically ordered" },
+ { "ISO-8859-9 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Turkish, Latin-5, O: Turkish, Latin-5" },
+ { "ISO-8859-15 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Western, Latin-1 + Euro, O: Western, Latin-1 + Euro" },
+ { "KOI8-R [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Cyrillic, KOI, O: Cyrillic, KOI" },
+ { "KOI8-U [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Ukrainian, O: Ukrainian" },
+ { "CP-1250 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Central European 3, O: Central European 3" },
+ { "CP-1251 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Cyrillic, Windows, O: Cyrillic, Windows" },
+ { "CP-1252 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Western, CP, O: Western, CP" },
+ { "CP-1253 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Greek, CP, O: Greek, CP" },
+ { "CP-1256 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Arabic, CP, O: Arabic, CP" },
+ { "CP-1257 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Baltic, CP, O: Baltic, CP" },
+ { "CP-1255 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Hebrew, CP, O: Hebrew, CP" },
+ { "CP-1254 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Turkish, CP, O: Turkish, CP" },
+ { "TIS-620 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Thai, O: Thai" },
+#ifndef QT_NO_BIG_CODECS
+ { "Big5 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Chinese Traditional, O: Chinese Traditional" },
+ { "Big5-HKSCS [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Chinese Traditional, Hong Kong, O: Chinese Traditional, Hong Kong" },
+ { "GB18030 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Chinese Simplified, O: Chinese Simplified" },
+ { "JIS7 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Japanese (JIS7), O: Japanese " },
+ { "Shift-JIS [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Japanese (Shift-JIS), O: Japanese (Shift-JIS)" },
+ { "EUC-JP [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Japanese (EUC-JP), O: Japanese (EUC-JP)" },
+ { "EUC-KR [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Korean, O: Korean" },
+ { "TSCII [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Tamil, O: Tamil" },
+#endif
+ { "ISO-8859-10 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / ISO-8859-10, O: ISO-8859-10" },
+ { "ISO-8859-13 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / ISO-8859-13, O: ISO-8859-13" },
+ { "ISO-8859-14 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / ISO-8859-14, O: ISO-8859-14" },
+ { "IBM-850 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / IBM-850, O: IBM-850" },
+ { "IBM-866 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / IBM-866, O: IBM-866" },
+ { "CP874 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / CP874, O: CP874" },
+
+ // smart codecs that send in utf8
+ { "UTF-8 [ISO-8859-1]" , 1 , 1 , "I: 8-bit Unicode / Western Latin-1, O: 8-bit Unicode" },
+ { "UTF-8 [ISO-8859-2]" , 1 , 1 , "I: 8-bit Unicode / Central European 1, O: 8-bit Unicode" },
+ { "UTF-8 [ISO-8859-3]" , 1 , 1 , "I: 8-bit Unicode / Central European 2, O: 8-bit Unicode" },
+ { "UTF-8 [ISO-8859-4]" , 1 , 1 , "I: 8-bit Unicode / Baltic, Standard, O: 8-bit Unicode" },
+
+ { "UTF-8 [ISO-8859-5]" , 1 , 1 , "I: 8-bit Unicode / Cyrillic, ISO, O: 8-bit Unicode" },
+ { "UTF-8 [ISO-8859-6]" , 1 , 1 , "I: 8-bit Unicode / Arabic, Standard, O: 8-bit Unicode" },
+ { "UTF-8 [ISO-8859-7]" , 1 , 1 , "I: 8-bit Unicode / Greek, O: 8-bit Unicode" },
+ { "UTF-8 [ISO-8859-8]" , 1 , 1 , "I: 8-bit Unicode / Hebrew, visually ordered, O: 8-bit Unicode" },
+
+ { "UTF-8 [ISO-8859-8-i]" , 1 , 1 , "I: 8-bit Unicode / Hebrew, logically ordered, O: 8-bit Unicode" },
+ { "UTF-8 [ISO-8859-9]" , 1 , 1 , "I: 8-bit Unicode / Turkish, Latin-5, O: 8-bit Unicode" },
+ { "UTF-8 [ISO-8859-15]" , 1 , 1 , "I: 8-bit Unicode / Western, Latin-1 + Euro, O: 8-bit Unicode" },
+ { "UTF-8 [KOI8-R]" , 1 , 1 , "I: 8-bit Unicode / Cyrillic, KOI, O: 8-bit Unicode" },
+
+ { "UTF-8 [KOI8-U]" , 1 , 1 , "I: 8-bit Unicode / Ukrainian, O: 8-bit Unicode" },
+ { "UTF-8 [CP-1250]" , 1 , 1 , "I: 8-bit Unicode / Central European 3, O: 8-bit Unicode" },
+ { "UTF-8 [CP-1251]" , 1 , 1 , "I: 8-bit Unicode / Cyrillic, Windows, O: 8-bit Unicode" },
+ { "UTF-8 [CP-1252]" , 1 , 1 , "I: 8-bit Unicode / Western, CP, O: 8-bit Unicode" },
+
+ { "UTF-8 [CP-1253]" , 1 , 1 , "I: 8-bit Unicode / Greek, CP, O: 8-bit Unicode" },
+ { "UTF-8 [CP-1256]" , 1 , 1 , "I: 8-bit Unicode / Arabic, CP, O: 8-bit Unicode" },
+ { "UTF-8 [CP-1257]" , 1 , 1 , "I: 8-bit Unicode / Baltic, CP, O: 8-bit Unicode" },
+ { "UTF-8 [CP-1255]" , 1 , 1 , "I: 8-bit Unicode / Hebrew, CP, O: 8-bit Unicode" },
+
+ { "UTF-8 [CP-1254]" , 1 , 1 , "I: 8-bit Unicode / Turkish, CP, O: 8-bit Unicode" },
+ { "UTF-8 [TIS-620]" , 1 , 1 , "I: 8-bit Unicode / Thai, O: 8-bit Unicode" },
+#ifndef QT_NO_BIG_CODECS
+ { "UTF-8 [Big5]" , 1 , 1 , "I: 8-bit Unicode / Chinese Traditional, O: 8-bit Unicode" },
+ { "UTF-8 [Big5-HKSCS]" , 1 , 1 , "I: 8-bit Unicode / Chinese Traditional, Hong Kong, O: 8-bit Unicode" },
+
+ { "UTF-8 [GB18030]" , 1 , 1 , "I: 8-bit Unicode / Chinese Simplified, O: 8-bit Unicode" },
+ { "UTF-8 [JIS7]" , 1 , 1 , "I: 8-bit Unicode / Japanese (JIS7), O: 8-bit Unicode" },
+ { "UTF-8 [Shift-JIS]" , 1 , 1 , "I: 8-bit Unicode / Japanese (Shift-JIS), O: Japanese (Shift-JIS)" },
+ { "UTF-8 [EUC-JP]" , 1 , 1 , "I: 8-bit Unicode / Japanese (EUC-JP), O: Japanese (EUC-JP)" },
+
+ { "UTF-8 [EUC-KR]" , 1 , 1 , "I: 8-bit Unicode / Korean, O: 8-bit Unicode" },
+ { "UTF-8 [TSCII]" , 1 , 1 , "I: 8-bit Unicode / Tamil, O: 8-bit Unicode" },
+#endif
+ { "UTF-8 [ISO-8859-10]" , 1 , 1 , "I: 8-bit Unicode / ISO-8859-10, O: 8-bit Unicode" },
+ { "UTF-8 [ISO-8859-13]" , 1 , 1 , "I: 8-bit Unicode / ISO-8859-13, O: 8-bit Unicode" },
+
+ { "UTF-8 [ISO-8859-14]" , 1 , 1 , "I: 8-bit Unicode / ISO-8859-14, O: 8-bit Unicode" },
+ { "UTF-8 [IBM-850]" , 1 , 1 , "I: 8-bit Unicode / IBM-850, O: 8-bit Unicode" },
+ { "UTF-8 [IBM-866]" , 1 , 1 , "I: 8-bit Unicode / IBM-866, O: 8-bit Unicode" },
+ { "UTF-8 [CP874]" , 1 , 1 , "I: 8-bit Unicode / CP874, O: 8-bit Unicode" },
+
+ { 0 , 0 , 0 , 0 }
+ };
+
+ EncodingDescription * encodingDescription(int iIdx)
+ {
+ if(iIdx > NUM_ENCODINGS)return &(supported_encodings[NUM_ENCODINGS]);
+ return &(supported_encodings[iIdx]);
+ }
+
+ QTextCodec * codecForName(const char * szName)
+ {
+ KviStr szTmp = szName;
+ int idx = szTmp.findFirstIdx('[');
+ if(idx != -1)
+ {
+ // composite codec: either UTF-8 [child codec] or child codec [UTF-8]
+ KviSmartTextCodec * c = g_pSmartCodecDict->find(szName);
+ if(c)return c;
+
+
+ if(kvi_strEqualCIN("UTF-8 [",szName,7))
+ {
+ szTmp.replaceAll("UTF-8 [","");
+ szTmp.replaceAll("]","");
+ // smart codec that sends UTF-8
+ c = new KviSmartTextCodec(szName,szTmp.ptr(),true);
+ } else {
+ szTmp.cutFromFirst(' ');
+ // smart codec that sends child encoding
+ c = new KviSmartTextCodec(szName,szTmp.ptr(),false);
+ }
+ if(c->ok())
+ {
+ g_pSmartCodecDict->replace(szName,c);
+ return c;
+ } else {
+ delete c;
+ }
+ }
+ return QTextCodec::codecForName(szName);
+ }
+
+ const KviStr & localeName()
+ {
+ return g_szLang;
+ }
+
+ bool loadCatalogue(const QString &name,const QString &szLocaleDir)
+ {
+ //debug("Looking up catalogue %s",name);
+ if(g_pCatalogueDict->find(KviQString::toUtf8(name).data()))return true; // already loaded
+
+ QString szBuffer;
+
+ if(findCatalogue(szBuffer,name,szLocaleDir))
+ {
+ KviMessageCatalogue * c = new KviMessageCatalogue();
+ if(c->load(szBuffer))
+ {
+ //debug("KviLocale: loaded catalogue %s",name);
+ g_pCatalogueDict->insert(KviQString::toUtf8(name).data(),c);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool unloadCatalogue(const QString &name)
+ {
+ //debug("Unloading catalogue : %s",name);
+ return g_pCatalogueDict->remove(KviQString::toUtf8(name).data());
+ }
+
+ bool findCatalogue(QString &szBuffer,const QString& name,const QString& szLocaleDir)
+ {
+ KviStr szLocale = g_szLang;
+
+ QString szLocDir = szLocaleDir;
+ KviQString::ensureLastCharIs(szLocDir,KVI_PATH_SEPARATOR_CHAR);
+
+ KviQString::sprintf(szBuffer,"%Q%Q_%s.mo",&szLocDir,&name,szLocale.ptr());
+
+ if(KviFileUtils::fileExists(szBuffer))return true;
+
+ if(szLocale.findFirstIdx('.') != -1)
+ {
+ // things like en_GB.utf8
+ // kill them
+ szLocale.cutFromFirst('.');
+
+ KviQString::sprintf(szBuffer,"%Q%Q_%s.mo",&szLocDir,&name,szLocale.ptr());
+ if(KviFileUtils::fileExists(szBuffer))return true;
+ }
+
+ if(szLocale.findFirstIdx('@') != -1)
+ {
+ // things like @euro ?
+ // kill them
+ szLocale.cutFromFirst('@');
+ KviQString::sprintf(szBuffer,"%Q%Q_%s.mo",&szLocDir,&name,szLocale.ptr());
+ if(KviFileUtils::fileExists(szBuffer))return true;
+ }
+
+ if(szLocale.findFirstIdx('_') != -1)
+ {
+ // things like en_GB
+ // kill them
+ szLocale.cutFromFirst('_');
+ KviQString::sprintf(szBuffer,"%Q%Q_%s.mo",&szLocDir,&name,szLocale.ptr());
+ if(KviFileUtils::fileExists(szBuffer))return true;
+ }
+
+ // try the lower case version too
+ szLocale.toLower();
+ KviQString::sprintf(szBuffer,"%Q%Q_%s.mo",&szLocDir,&name,szLocale.ptr());
+ if(KviFileUtils::fileExists(szBuffer))return true;
+
+ return false;
+ }
+
+ //
+ // This function attempts to determine the current locale
+ // and then load the corresponding translation file
+ // from the KVIrc locale directory
+ // Returns true if the locale was correctly set
+ // i.e. the locale is C or POSIX (no translation needed)
+ // or the locale is correctly defined and the
+ // translation map was sucesfully loaded
+ //
+
+ void init(QApplication * app,const QString &localeDir)
+ {
+ // first of all try to find out the current locale
+ g_szLang="";
+#ifdef COMPILE_USE_QT4
+ QString szLangFile=QString("%1/.kvirc_force_locale").arg(QDir::homePath());
+#else
+ QString szLangFile=QString("%1/.kvirc_force_locale").arg(QDir::homeDirPath());
+#endif
+ if(KviFileUtils::fileExists(szLangFile))
+ {
+ QString szTmp;
+ KviFileUtils::readFile(szLangFile,szTmp);
+ g_szLang=szTmp;
+ }
+ if(g_szLang.isEmpty())g_szLang = kvi_getenv("KVIRC_LANG");
+#ifdef COMPILE_USE_QT4
+ if(g_szLang.isEmpty())g_szLang = QLocale::system().name();
+#else
+ if(g_szLang.isEmpty())g_szLang = QTextCodec::locale();
+#endif
+ if(g_szLang.isEmpty())g_szLang = kvi_getenv("LC_MESSAGES");
+ if(g_szLang.isEmpty())g_szLang = kvi_getenv("LANG");
+ if(g_szLang.isEmpty())g_szLang = "en";
+ g_szLang.stripWhiteSpace();
+
+ // the main catalogue is supposed to be kvirc_<language>.mo
+ g_pMainCatalogue = new KviMessageCatalogue();
+ // the catalogue dict
+ g_pCatalogueDict = new KviPointerHashTable<const char *,KviMessageCatalogue>;
+ g_pCatalogueDict->setAutoDelete(true);
+
+ // the smart codec dict
+ g_pSmartCodecDict = new KviPointerHashTable<const char *,KviSmartTextCodec>;
+ // the Qt docs explicitly state that we shouldn't delete
+ // the codecs by ourselves...
+ g_pSmartCodecDict->setAutoDelete(false);
+
+ if(g_szLang.hasData())
+ {
+ QString szBuffer;
+ if(findCatalogue(szBuffer,"kvirc",localeDir))
+ {
+ g_pMainCatalogue->load(szBuffer);
+ g_pTranslator = new KviTranslator(app,"kvirc_translator");
+ app->installTranslator(g_pTranslator);
+ } else {
+ KviStr szTmp = g_szLang;
+ szTmp.cutFromFirst('.');
+ szTmp.cutFromFirst('_');
+ szTmp.cutFromFirst('@');
+ szTmp.toLower();
+ if(!(kvi_strEqualCI(szTmp.ptr(),"en") ||
+ kvi_strEqualCI(szTmp.ptr(),"c") ||
+ kvi_strEqualCI(szTmp.ptr(),"us") ||
+ kvi_strEqualCI(szTmp.ptr(),"gb") ||
+ kvi_strEqualCI(szTmp.ptr(),"posix")))
+ {
+ // FIXME: THIS IS NO LONGER VALID!!!
+ debug("Can't find the catalogue for locale \"%s\" (%s)",g_szLang.ptr(),szTmp.ptr());
+ debug("There is no such translation or the $LANG variable was incorrectly set");
+ debug("You can use $KVIRC_LANG to override the catalogue name");
+ debug("For example you can set KVIRC_LANG to it_IT to force usage of the it.mo catalogue");
+ }
+ }
+ }
+
+ //g_pTextCodec = QTextCodec::codecForLocale();
+ //if(!g_pTextCodec)g_pTextCodec = QTextCodec::codecForLocale();
+ }
+
+ void done(QApplication * app)
+ {
+ delete g_pMainCatalogue;
+ delete g_pCatalogueDict;
+ delete g_pSmartCodecDict;
+ g_pMainCatalogue = 0;
+ g_pCatalogueDict = 0;
+ g_pSmartCodecDict = 0;
+ if(g_pTranslator)
+ {
+ app->removeTranslator(g_pTranslator);
+ delete g_pTranslator;
+ g_pTranslator = 0;
+ }
+ }
+
+ KviMessageCatalogue * getLoadedCatalogue(const QString& name)
+ {
+ return g_pCatalogueDict->find(KviQString::toUtf8(name).data());
+ }
+
+
+ const char * translate(const char * text,const char * context)
+ {
+ if(context)
+ {
+ KviMessageCatalogue * c = g_pCatalogueDict->find(context);
+ if(!c)
+ {
+ // FIXME: Should really try to load the catalogue here!
+ c = new KviMessageCatalogue();
+ g_pCatalogueDict->insert(context,c);
+ }
+ return c->translate(text);
+ }
+ return g_pMainCatalogue->translate(text);
+ }
+
+ const QString & translateToQString(const char * text,const char * context)
+ {
+ if(context)
+ {
+ KviMessageCatalogue * c = g_pCatalogueDict->find(context);
+ if(!c)
+ {
+ // FIXME: Should really try to load the catalogue here!
+ c = new KviMessageCatalogue();
+ g_pCatalogueDict->insert(context,c);
+ }
+ return c->translateToQString(text);
+ }
+ return g_pMainCatalogue->translateToQString(text);
+ }
+};
+
+KviTranslator::KviTranslator(QObject * par,const char * nam)
+#ifdef COMPILE_USE_QT4
+: QTranslator(par)
+#else
+: QTranslator(par,nam)
+#endif
+{
+}
+
+KviTranslator::~KviTranslator()
+{
+}
+
+#ifdef COMPILE_USE_QT4
+QString KviTranslator::translate(const char *context,const char * message,const char * comment) const
+{
+ // we ignore contexts and comments for qt translations
+ return g_pMainCatalogue->translateToQString(message);
+}
+#endif
+
+QString KviTranslator::find(const char *context,const char * message) const
+{
+ // we ignore contexts for qt translations
+ return g_pMainCatalogue->translateToQString(message);
+}
+
+#ifndef COMPILE_USE_QT4
+QTranslatorMessage KviTranslator::findMessage(const char * context,const char * sourceText,const char * comment) const
+{
+ // we ignore contexts for qt translations
+ return QTranslatorMessage(context,sourceText,comment,g_pMainCatalogue->translateToQString(sourceText));
+}
+#endif
+
+#if 0
+
+// a fake table that will force these translations
+// to be included in the *.pot file
+
+static QString fake_translations_table[]=
+{
+ // global
+ __tr2qs("OK"),
+ __tr2qs("Cancel"),
+ // color dialog
+ __tr2qs("Select color"),
+ __tr2qs("&Basic colors"),
+ __tr2qs("&Custom colors"),
+ __tr2qs("&Red"),
+ __tr2qs("&Green"),
+ __tr2qs("Bl&ue"),
+ __tr2qs("&Define Custom Colors >>"),
+ __tr2qs("&Add to Custom Colors"),
+ // font dialog
+ __tr2qs("Select Font"),
+ __tr2qs("&Font"),
+ __tr2qs("Font st&yle"),
+ __tr2qs("&Size"),
+ __tr2qs("Sample"),
+ __tr2qs("Effects"),
+ __tr2qs("Stri&keout"),
+ __tr2qs("&Underline"),
+ __tr2qs("Scr&ipt"),
+ //File selector
+ __tr2qs("Parent Directory"),
+ __tr2qs("Back"),
+ __tr2qs("Forward"),
+ __tr2qs("Reload"),
+ __tr2qs("New Directory"),
+ __tr2qs("Bookmarks"),
+ __tr2qs("Add Bookmark"),
+ __tr2qs("&Edit Bookmarks"),
+ __tr2qs("New Bookmark Folder..."),
+ __tr2qs("Configure"),
+ __tr2qs("Sorting"),
+ __tr2qs("By Name"),
+ __tr2qs("By Date"),
+ __tr2qs("By Size"),
+ __tr2qs("Reverse"),
+ __tr2qs("Directories First"),
+ __tr2qs("Case Insensitive"),
+ __tr2qs("Short View"),
+ __tr2qs("Detailed View"),
+ __tr2qs("Show Hidden Files"),
+ __tr2qs("Show Quick Access Navigation Panel"),
+ __tr2qs("Show Preview"),
+ __tr2qs("Separate Directories"),
+ __tr2qs("Often used directories"),
+ __tr2qs("Desktop"),
+ __tr2qs("Home Directory"),
+ __tr2qs("Floppy"),
+ __tr2qs("Temporary Files"),
+ __tr2qs("Network"),
+ __tr2qs("New Directory..."),
+ __tr2qs("Delete"),
+ __tr2qs("Thumbnail Previews"),
+ __tr2qs("Large Icons"),
+ __tr2qs("Small Icons"),
+ __tr2qs("Properties..."),
+ __tr2qs("&Automatic Preview"),
+ __tr2qs("&Preview"),
+ __tr2qs("&Location:"),
+ __tr2qs("&Filter:"),
+ __tr2qs("All Files"),
+ __tr2qs("&OK"),
+ __tr2qs("&Cancel")
+
+}
+
+#endif
diff --git a/src/kvilib/system/kvi_locale.h b/src/kvilib/system/kvi_locale.h
new file mode 100644
index 00000000..bc3ed8eb
--- /dev/null
+++ b/src/kvilib/system/kvi_locale.h
@@ -0,0 +1,146 @@
+#ifndef _KVI_LOCALE_H_
+#define _KVI_LOCALE_H_
+
+//=============================================================================
+//
+// File : kvi_locale.h
+// Creation date : Sat Jan 16 1999 18:15:01 by Szymon Stefanek
+//
+// This file is part of the KVirc irc client distribution
+// Copyright (C) 1999-2000 Szymon Stefanek (pragma at kvirc dot net)
+//
+// This program is FREE software. You can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your opinion) any later version.
+//
+// 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 General Public License
+// along with this program. If not, write to the Free Software Foundation,
+// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+//=============================================================================
+
+
+#include "kvi_settings.h"
+#include "kvi_qstring.h"
+#include "kvi_string.h"
+#include "kvi_pointerhashtable.h"
+
+#include <qapplication.h>
+
+class QTextCodec;
+class KviMessageCatalogue;
+
+namespace KviLocale
+{
+ typedef struct _EncodingDescription
+ {
+ char * szName;
+ char bSmart; // is it a smart codec ?
+ char bSendUtf8; // does it send utf8 or the local charset ?
+ char * szDescription;
+ } EncodingDescription;
+
+ // you MUST start iterating from 0 and terminate when
+ // you get an entry with a NULL szName
+ KVILIB_API EncodingDescription * encodingDescription(int iIdx);
+ KVILIB_API QTextCodec * codecForName(const char * szName);
+ KVILIB_API const KviStr & localeName();
+ KVILIB_API bool findCatalogue(QString &szBuffer,const QString& name,const QString& szLocaleDir);
+ KVILIB_API bool loadCatalogue(const QString& name,const QString& szLocaleDir);
+ KVILIB_API KviMessageCatalogue * getLoadedCatalogue(const QString& name);
+ KVILIB_API bool unloadCatalogue(const QString& name);
+ KVILIB_API void init(QApplication * app,const QString& localeDir);
+ KVILIB_API void done(QApplication * app);
+ KVILIB_API const char * translate(const char * text,const char * context);
+ KVILIB_API const QString & translateToQString(const char * text,const char * context);
+};
+
+// not exported
+class KviTranslationEntry
+{
+public:
+ KviStr m_szKey;
+ KviStr m_szEncodedTranslation;
+ QString * m_pQTranslation;
+public:
+ KviTranslationEntry(char * keyptr,int keylen,char * trptr,int trlen)
+ : m_szKey(keyptr,keylen) , m_szEncodedTranslation(trptr,trlen)
+ {
+ m_pQTranslation = 0;
+ }
+
+ KviTranslationEntry(const char * keyandtr)
+ : m_szKey(keyandtr) , m_szEncodedTranslation(keyandtr)
+ {
+ m_pQTranslation = 0;
+ }
+
+ ~KviTranslationEntry()
+ {
+ if(m_pQTranslation)delete m_pQTranslation;
+ }
+};
+
+
+class KVILIB_API KviMessageCatalogue
+{
+public:
+ KviMessageCatalogue();
+ ~KviMessageCatalogue();
+protected:
+ //KviPointerHashTable<const char *,KviTranslationEntry> * m_pMessages;
+ KviPointerHashTable<const char *,KviTranslationEntry> * m_pMessages;
+ QTextCodec * m_pTextCodec;
+public:
+ bool load(const QString& name);
+ const char * translate(const char * text);
+ const QString & translateToQString(const char * text);
+};
+
+#ifndef _KVI_LOCALE_CPP_
+ extern KVILIB_API KviMessageCatalogue * g_pMainCatalogue;
+#endif // !_KVI_LOCALE_CPP_
+
+#define __tr(__text__) g_pMainCatalogue->translate(__text__)
+#define __tr_no_lookup(__text__) __text__
+#define __tr_no_xgettext(__text__) g_pMainCatalogue->translate(__text__)
+
+#define __tr2qs(__text__) g_pMainCatalogue->translateToQString(__text__)
+#define __tr2qs_no_xgettext(__text__) g_pMainCatalogue->translateToQString(__text__)
+
+#define __tr_ctx(__text__,__context__) KviLocale::translate(__text__,__context__)
+#define __tr_no_lookup_ctx(__text__,__context__) __text__
+#define __tr_no_xgettext_ctx(__text__,__context__) KviLocale::translate(__text__,__context__)
+#define __tr2qs_ctx(__text__,__context__) KviLocale::translateToQString(__text__,__context__)
+#define __tr2qs_ctx_no_xgettext(__text__,__context__) KviLocale::translateToQString(__text__,__context__)
+#define __tr2qs_no_lookup(__text__) __text__
+
+#include <qtranslator.h>
+#include <qstring.h>
+
+class KVILIB_API KviTranslator : public QTranslator
+{
+ Q_OBJECT
+ public:
+ KviTranslator(QObject * parent,const char * name);
+ ~KviTranslator();
+ public:
+#ifdef COMPILE_USE_QT4
+ virtual QString translate(const char * context,const char * message,const char * comment) const;
+#endif
+ // Deprecated in qt 4.x
+ virtual QString find(const char * context,const char * message) const;
+#ifndef COMPILE_USE_QT4
+ // Dead in qt 4.x
+ virtual QTranslatorMessage findMessage(const char * context,const char * sourceText,const char * comment = 0) const;
+#endif
+};
+
+
+#endif //!_KVI_LOCALE_H_
diff --git a/src/kvilib/system/kvi_process.h b/src/kvilib/system/kvi_process.h
new file mode 100644
index 00000000..ea2275dc
--- /dev/null
+++ b/src/kvilib/system/kvi_process.h
@@ -0,0 +1,37 @@
+#ifndef _KVI_PROCESS_H_
+#define _KVI_PROCESS_H_
+//=============================================================================
+//
+// File : kvi_process.h
+// Creation date : Tue Jan 30 2007 04:05:41 CEST by Szymon Stefanek
+//
+// This file is part of the KVirc irc client distribution
+// Copyright (C) 2007 Szymon Stefanek (pragma at kvirc dot net)
+//
+// This program is FREE software. You can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your opinion) any later version.
+//
+// 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 General Public License
+// along with this program. If not, write to the Free Software Foundation,
+// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+//=============================================================================
+
+#include "kvi_settings.h"
+
+#ifdef COMPILE_USE_QT4
+ #include <q3process.h>
+ #define KviProcess Q3Process
+#else
+ #include <qprocess.h>
+ #define KviProcess QProcess
+#endif
+
+#endif //!_KVI_PROCESS_H_
diff --git a/src/kvilib/system/kvi_stdarg.h b/src/kvilib/system/kvi_stdarg.h
new file mode 100644
index 00000000..15c5e078
--- /dev/null
+++ b/src/kvilib/system/kvi_stdarg.h
@@ -0,0 +1,65 @@
+#ifndef _KVI_STDARG_H_
+#define _KVI_STDARG_H_
+
+//=============================================================================
+//
+// File : kvi_stdarg.h
+// Creation date : Sat Jan 03 2004 02:08:14 CEST by Szymon Stefanek
+//
+// This file is part of the KVirc irc client distribution
+// Copyright (C) 2004 Szymon Stefanek (pragma at kvirc dot net)
+//
+// This program is FREE software. You can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your opinion) any later version.
+//
+// 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 General Public License
+// along with this program. If not, write to the Free Software Foundation,
+// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+//=============================================================================
+
+#include "kvi_settings.h"
+#include <stdarg.h>
+
+#define kvi_va_list va_list
+#define kvi_va_start va_start
+//
+// kvi_va_start_by_reference should be used when the last known argument
+// is a reference type and not a pointer
+//
+// int SomeClass::sprintf(const QString &fmt,...)
+// {
+// kvi_va_list list;
+// kvi_va_start_by_reference(list,fmt);
+// ...
+// }
+//
+//
+#ifdef COMPILE_ON_WINDOWS
+ #define kvi_va_start_by_reference(__list,__arg) \
+ { \
+ int supercalifragilisticoespiralidoso=_INTSIZEOF(__arg); \
+ __asm lea eax,__arg \
+ __asm add eax,supercalifragilisticoespiralidoso \
+ __asm mov __list,eax \
+ }
+#elif defined(__GNUC__)
+ // gcc doesn't use the second argument
+ // so we just fool it to avoid the warnings
+ #define kvi_va_start_by_reference(__list,__arg) va_start(__list,((const char *)(&(__arg))))
+#else
+ #define kvi_va_start_by_reference va_start
+#endif
+#define kvi_va_arg va_arg
+#define kvi_va_end va_end
+
+
+
+#endif //_KVI_STDARG_H_
diff --git a/src/kvilib/system/kvi_thread.cpp b/src/kvilib/system/kvi_thread.cpp
new file mode 100644
index 00000000..e9ec3ac5
--- /dev/null
+++ b/src/kvilib/system/kvi_thread.cpp
@@ -0,0 +1,644 @@
+//=============================================================================
+//
+// File : kvi_thread.cpp
+// Creation date : Tue Jul 6 1999 16:04:45 CEST by Szymon Stefanek
+//
+// This file is part of the KVirc irc client distribution
+// Copyright (C) 1999-2005 Szymon Stefanek (pragma at kvirc dot net)
+//
+// This program is FREE software. You can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your opinion) any later version.
+//
+// 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 General Public License
+// along with this program. If not, write to the Free Software Foundation,
+// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+//=============================================================================
+
+#define __KVILIB__
+
+
+#ifndef _GNU_SOURCE
+ #define _GNU_SOURCE
+#endif
+
+#include "kvi_thread.h"
+
+#ifdef COMPILE_ON_WINDOWS
+ #include <io.h> // for _pipe()
+#else
+ #include <unistd.h> //for pipe() and other tricks
+ #include <signal.h> // on Windows it is useless
+ #include <fcntl.h>
+#endif
+
+#include <errno.h>
+
+
+#include "kvi_string.h"
+#include "kvi_settings.h"
+#include "kvi_error.h"
+
+
+#include <qapplication.h>
+
+
+static void kvi_threadIgnoreSigalarm()
+{
+ // On Windows this stuff is useless anyway
+#ifdef COMPILE_IGNORE_SIGALARM
+ #ifndef COMPILE_ON_WINDOWS
+ // Funky hack for some Solaris machines (maybe others ?)
+ // For an obscure (at least to me) reason
+ // when using threads ,some part of the system
+ // starts kidding us by sending a SIGALRM in apparently
+ // "random" circumstances. (Xlib ?) (XServer ?)
+ // The default action for SIGALRM is to exit the application.
+ // Could not guess more about this stuff...
+ // Here goes a "blind" hack for that.
+
+ // Update: now we have an explaination too
+ //
+ // From: "Andre Stechert" (astechert at email dot com)
+ // To: pragma at kvirc dot net
+ // Subject: sigalarm on solaris ...
+ // Date: 26/7/2005 09:36
+
+ // Hi,
+ //    I noticed in your readme that you were having problems with sigalarm
+ // in your solaris port and you weren't sure why.  I quickly scanned your
+ // source code and noticed that you use usleep and threads.  That's the problem,
+ // if you haven't already figured it out. On Solaris, usleep is implemented with
+ // SIGALARM. So is threading. So if you the active thread changes while
+ // a usleep is in progress, bang, the process is dead.
+ //
+ // There is no real feedback on this at the moment: if somebody
+ // experiences the problems please drop me a mail at pragma at kvirc dot net
+ // and we'll try to look for a better solution.
+ // If the explaination is correct then KVIrc could even lock up on those machines
+ // (never returning from an usleep() call ?)...
+
+ struct sigaction ignr_act;
+ ignr_act.sa_handler = SIG_IGN;
+ sigemptyset(&ignr_act.sa_mask);
+
+ #ifdef SA_NOMASK
+ ignr_act.sa_flags = SA_NOMASK;
+ #else
+ ignr_act.sa_flags = 0;
+ #endif
+
+ #ifdef SA_RESTART
+ ignr_act.sa_flags |= SA_RESTART;
+ #endif
+
+ if(sigaction(SIGALRM,&ignr_act,0) == -1)debug("Failed to set SIG_IGN for SIGALRM.");
+ #endif
+#endif
+}
+
+#ifndef COMPILE_ON_WINDOWS
+
+static void kvi_threadSigpipeHandler(int)
+{
+ debug("Thread ????: Caught SIGPIPE: ignoring.");
+}
+
+#endif
+
+static void kvi_threadCatchSigpipe()
+{
+ // On windows this stuff is useless
+#ifndef COMPILE_ON_WINDOWS
+ struct sigaction act;
+ act.sa_handler=&kvi_threadSigpipeHandler;
+ sigemptyset(&(act.sa_mask));
+ sigaddset(&(act.sa_mask), SIGPIPE);
+ // CC: take care of SunOS which automatically restarts interrupted system
+ // calls (and thus does not have SA_RESTART)
+#ifdef SA_NOMASK
+ act.sa_flags = SA_NOMASK;
+#else
+ act.sa_flags = 0;
+#endif
+
+#ifdef SA_RESTART
+ act.sa_flags |= SA_RESTART;
+#endif
+
+ if(sigaction(SIGPIPE,&act,0L) == -1)debug("Failed to set the handler for SIGPIPE.");
+#endif
+}
+
+static void kvi_threadInitialize()
+{
+#ifndef COMPILE_ON_WINDOWS
+ kvi_threadIgnoreSigalarm();
+ kvi_threadCatchSigpipe();
+#endif
+}
+
+
+
+#define KVI_THREAD_PIPE_SIDE_MASTER 0
+#define KVI_THREAD_PIPE_SIDE_SLAVE 1
+
+// the maximum length of the slave->master queue
+// over this length , the slave is forced to usleep()
+#define KVI_THREAD_MAX_EVENT_QUEUE_LENGTH 50
+
+static KviThreadManager * g_pThreadManager = 0;
+
+void KviThreadManager::globalInit()
+{
+ kvi_threadInitialize(); // we want this to apply to the main thread too
+ g_pThreadManager = new KviThreadManager();
+}
+
+void KviThreadManager::globalDestroy()
+{
+ delete g_pThreadManager;
+ g_pThreadManager = 0;
+}
+
+KviThreadManager::KviThreadManager()
+: QObject()
+{
+ if(g_pThreadManager)debug("Hey...what are ya doing ?");
+
+
+ m_pMutex = new KviMutex();
+ m_pThreadList = new KviPointerList<KviThread>;
+ m_pThreadList->setAutoDelete(false);
+
+ m_iWaitingThreads = 0;
+
+#ifndef COMPILE_ON_WINDOWS
+
+ m_iTriggerCount = 0;
+
+ m_pEventQueue = new KviPointerList<KviThreadPendingEvent>;
+ m_pEventQueue->setAutoDelete(true);
+
+ if(pipe(m_fd) != 0)
+ {
+ debug("Ops...thread manager pipe creation failed (%s)",KviQString::toUtf8(KviError::getDescription(KviError::translateSystemError(errno))).data());
+ }
+
+ if(fcntl(m_fd[KVI_THREAD_PIPE_SIDE_SLAVE],F_SETFL,O_NONBLOCK) == -1)
+ {
+ debug("Ops...thread manager slave pipe initialisation failed (%s)",KviQString::toUtf8(KviError::getDescription(KviError::translateSystemError(errno))).data());
+ }
+
+ if(fcntl(m_fd[KVI_THREAD_PIPE_SIDE_MASTER],F_SETFL,O_NONBLOCK) == -1)
+ {
+ debug("Ops...thread manager master pipe initialisation failed (%s)",KviQString::toUtf8(KviError::getDescription(KviError::translateSystemError(errno))).data());
+ }
+
+ m_pSn = new QSocketNotifier(m_fd[KVI_THREAD_PIPE_SIDE_MASTER],QSocketNotifier::Read);
+ connect(m_pSn,SIGNAL(activated(int)),this,SLOT(eventsPending(int)));
+ m_pSn->setEnabled(true);
+#endif
+}
+
+
+KviThreadManager::~KviThreadManager()
+{
+ m_pMutex->lock();
+ // Terminate all the slaves
+ while(KviThread *t = m_pThreadList->first())
+ {
+ m_pMutex->unlock();
+ delete t;
+ m_pMutex->lock();
+ }
+
+ // there are no more child threads
+ // thus no more slave events are sent.
+ // Disable the socket notifier, we no longer need it
+#ifndef COMPILE_ON_WINDOWS
+ m_pSn->setEnabled(false);
+ delete m_pSn;
+ m_pSn = 0;
+#endif
+
+ // we're no longer in this world
+ g_pThreadManager = 0;
+
+#ifndef COMPILE_ON_WINDOWS
+ // close the pipes
+ close(m_fd[KVI_THREAD_PIPE_SIDE_SLAVE]);
+ close(m_fd[KVI_THREAD_PIPE_SIDE_MASTER]);
+ // Kill the pending events
+ while(KviThreadPendingEvent *ev = m_pEventQueue->first())
+ {
+ delete ev->e;
+ m_pEventQueue->removeFirst();
+ }
+ delete m_pEventQueue;
+ m_pEventQueue = 0;
+#endif
+
+ m_pMutex->unlock();
+
+ // finish the cleanup
+ delete m_pMutex;
+ m_pMutex = 0;
+ delete m_pThreadList;
+ m_pThreadList = 0;
+
+ // byez :)
+}
+
+void KviThreadManager::killPendingEvents(QObject * receiver)
+{
+#ifndef COMPILE_ON_WINDOWS
+ if(!g_pThreadManager)return;
+ g_pThreadManager->killPendingEventsByReceiver(receiver);
+#endif
+}
+
+void KviThreadManager::killPendingEventsByReceiver(QObject * receiver)
+{
+#ifndef COMPILE_ON_WINDOWS
+ KviPointerList<KviThreadPendingEvent> l;
+ l.setAutoDelete(false);
+ m_pMutex->lock();
+ for(KviThreadPendingEvent * ev = m_pEventQueue->first();ev;ev = m_pEventQueue->next())
+ {
+ if(ev->o == receiver)l.append(ev);
+ }
+ for(KviThreadPendingEvent * ev = l.first();ev;ev = l.next())
+ {
+ delete ev->e;
+ m_pEventQueue->removeRef(ev);
+ }
+ m_pMutex->unlock();
+#endif
+}
+
+void KviThreadManager::registerSlaveThread(KviThread *t)
+{
+ m_pMutex->lock();
+ m_pThreadList->append(t);
+ m_pMutex->unlock();
+}
+
+void KviThreadManager::unregisterSlaveThread(KviThread *t)
+{
+ m_pMutex->lock();
+ m_pThreadList->removeRef(t);
+ m_pMutex->unlock();
+}
+
+void KviThreadManager::postSlaveEvent(QObject *o,QEvent *e)
+{
+#ifdef COMPILE_ON_WINDOWS
+ QApplication::postEvent(o,e); // we believe this to be thread-safe
+#else
+ KviThreadPendingEvent * ev = new KviThreadPendingEvent;
+ ev->o = o;
+ ev->e = e;
+
+ m_pMutex->lock();
+
+ // if the queue gets too long , make this (slave) thread sleep
+
+ // there is a special case where we can't stop the slaves posting events
+ // it's when a thread-master-side is waiting for it's thread-slave-side
+ // it the thread-master-side runs in the application main thread then
+ // the main thread is sleeping and can't process events.
+ // Since we can't be really sure that the thread-master-side will be running
+ // on the main application thread we also can't artificially process the events.
+ // So the solution is to skip this algorithm when at least one
+ // thread is in waiting state.
+ while((m_pEventQueue->count() > KVI_THREAD_MAX_EVENT_QUEUE_LENGTH) && (m_iWaitingThreads < 1))
+ {
+ // wait for the master to process the queue
+
+ m_pMutex->unlock();
+
+ // WARNING : This will fail if for some reason
+ // the master thread gets here! It will wait indefinitely for itself
+ // if(pthread_self() != m_hMasterThread) ... ????
+
+#ifdef COMPILE_ON_WINDOWS
+ ::Sleep(1); // 1ms
+#else
+ // FIXME : use nanosleep() ?
+ ::usleep(1000); // 1 ms
+#endif
+ m_pMutex->lock();
+ }
+
+ m_pEventQueue->append(ev);
+ // Write bulk to the pipe... but only if there is no other wakeup pending
+ if(m_iTriggerCount < 1)
+ {
+ // I don't know if writing to a pipe is reentrant
+ // thus, in doubt, the write is interlocked (it's non blocking anyway)
+ int written = write(m_fd[KVI_THREAD_PIPE_SIDE_SLAVE],"?",1);
+ if(written < 1)
+ {
+ // ops.. failed to write down the event..
+ // this is quite irritating now...
+ debug("Ops.. failed to write down the trigger");
+ // FIXME: maybe a single shot timer ?
+ } else {
+ m_iTriggerCount++;
+ }
+ } // else no need to trigger : there is a wakeup pending in there
+
+ m_pMutex->unlock();
+
+#endif
+}
+
+void KviThreadManager::eventsPending(int fd)
+{
+#ifndef COMPILE_ON_WINDOWS
+ char buf[10];
+ // do we need to check for errors here ?
+ int readed = read(fd,buf,10);
+
+ m_pMutex->lock();
+ // welcome to the critical section :)
+
+ // grab the first event in the queue
+ while(KviThreadPendingEvent *ev = m_pEventQueue->first())
+ {
+ // allow the other threads to post events:
+ // unlock the event queue
+ m_pMutex->unlock();
+ // let the app process the event
+ // DANGER !
+ QApplication::postEvent(ev->o,ev->e);
+
+ // jump out of the loop if we have been destroyed
+ if(!g_pThreadManager)return;
+ // ufff... we're still alive :)))
+
+ // regrab the event queue
+ m_pMutex->lock();
+ // remove the event we have just processed
+ m_pEventQueue->removeRef(ev);
+ // here we're looping locked and havn't decremended the trigger count
+ }
+ // decrement the trigger count on the line: still atomic
+ if(readed >= 0)
+ {
+ if(readed < m_iTriggerCount)
+ {
+ m_iTriggerCount -= readed;
+ } else {
+ m_iTriggerCount = 0;
+ }
+ }
+
+ // ok , job done.. can relax now
+ m_pMutex->unlock();
+
+#endif
+}
+
+void KviThreadManager::threadEnteredWaitState()
+{
+ m_pMutex->lock();
+ m_iWaitingThreads++;
+ m_pMutex->unlock();
+}
+
+void KviThreadManager::threadLeftWaitState()
+{
+ m_pMutex->lock();
+ m_iWaitingThreads--;
+ if(m_iWaitingThreads < 0)
+ {
+ debug("Ops.. got a negative number of waiting threads ?");
+ m_iWaitingThreads = 0;
+ }
+ m_pMutex->unlock();
+}
+
+#ifndef COMPILE_ON_WINDOWS
+ bool KviMutex::locked()
+ {
+ if(!kvi_threadMutexTryLock(&m_mutex))return true;
+ kvi_threadMutexUnlock(&m_mutex);
+ return false;
+ }
+#endif
+
+#ifdef COMPILE_ON_WINDOWS
+DWORD WINAPI internal_start_thread(LPVOID arg)
+{
+ // Slave thread...
+ ((KviThread *)arg)->internalThreadRun_doNotTouchThis();
+ return 0;
+}
+#else
+static void * internal_start_thread(void * arg)
+{
+ // Slave thread...
+ ((KviThread *)arg)->internalThreadRun_doNotTouchThis();
+ return 0;
+}
+#endif
+
+KviThread::KviThread()
+{
+ g_pThreadManager->registerSlaveThread(this);
+ m_pRunningMutex = new KviMutex();
+ setRunning(false);
+ setStartingUp(false);
+}
+
+KviThread::~KviThread()
+{
+// debug(">> KviThread::~KviThread() : (this = %d)",this);
+ wait();
+ delete m_pRunningMutex;
+ g_pThreadManager->unregisterSlaveThread(this);
+// debug("<< KviThread::~KviThread() : (this = %d)",this);
+}
+
+void KviThread::setRunning(bool bRunning)
+{
+ m_pRunningMutex->lock();
+ m_bRunning = bRunning;
+ m_pRunningMutex->unlock();
+}
+
+void KviThread::setStartingUp(bool bStartingUp)
+{
+ m_pRunningMutex->lock();
+ m_bStartingUp = bStartingUp;
+ m_pRunningMutex->unlock();
+}
+
+bool KviThread::isRunning()
+{
+ bool bRunning = true;
+ m_pRunningMutex->lock();
+ bRunning = m_bRunning;
+ m_pRunningMutex->unlock();
+ return bRunning;
+}
+
+bool KviThread::isStartingUp()
+{
+ bool bIsStartingUp = true;
+ m_pRunningMutex->lock();
+ bIsStartingUp = m_bStartingUp;
+ m_pRunningMutex->unlock();
+ return bIsStartingUp;
+}
+
+bool KviThread::start()
+{
+ // We're on the master side thread here!
+ if(isStartingUp() || isRunning())return false;
+ setStartingUp(true);
+ return kvi_threadCreate(&m_thread,internal_start_thread,this);
+}
+
+void KviThread::wait()
+{
+ // We're on the master side here...and we're waiting the slave to exit
+// debug(">> KviThread::wait() (this=%d)",this);
+ while(isStartingUp())usleep(500); // sleep 500 microseconds
+// debug("!! KviThread::wait() (this=%d)",this);
+ g_pThreadManager->threadEnteredWaitState();
+ while(isRunning())
+ {
+ usleep(500); // sleep 500 microseconds
+ }
+ g_pThreadManager->threadLeftWaitState();
+// debug("<< KviThread::wait() (this=%d)",this);
+}
+
+void KviThread::exit()
+{
+ // We're on the slave side thread here! (m_bRunning is true , m_bStartingUp is false)
+ setRunning(false);
+ kvi_threadExit();
+}
+
+void KviThread::internalThreadRun_doNotTouchThis()
+{
+ // we're on the slave thread here!
+// debug(">> KviThread::internalRun (this=%d)",this);
+ setRunning(true);
+ setStartingUp(false);
+ kvi_threadInitialize();
+ run();
+ setRunning(false);
+// debug("<< KviThread::internalRun (this=%d",this);
+}
+
+void KviThread::usleep(unsigned long usec)
+{
+#ifdef COMPILE_ON_WINDOWS
+ int s = usec / 1000;
+ if(s < 1)s = 1;
+ ::Sleep(s); // Sleep one millisecond...this is the best that we can do
+#else
+ // FIXME : use nanosleep() ?
+ ::usleep(usec);
+#endif
+}
+
+void KviThread::msleep(unsigned long msec)
+{
+#ifdef COMPILE_ON_WINDOWS
+ ::Sleep(msec);
+#else
+ // FIXME : use nanosleep() ?
+ ::usleep(msec * 1000);
+#endif
+}
+
+void KviThread::sleep(unsigned long sec)
+{
+#ifdef COMPILE_ON_WINDOWS
+ ::Sleep(sec * 1000);
+#else
+ ::sleep(sec);
+#endif
+}
+
+void KviThread::postEvent(QObject * o,QEvent *e)
+{
+ // slave side
+ g_pThreadManager->postSlaveEvent(o,e);
+}
+
+
+
+KviSensitiveThread::KviSensitiveThread()
+: KviThread()
+{
+ m_pLocalEventQueueMutex = new KviMutex();
+ m_pLocalEventQueue = new KviPointerList<KviThreadEvent>;
+ m_pLocalEventQueue->setAutoDelete(false);
+}
+
+KviSensitiveThread::~KviSensitiveThread()
+{
+// debug("Entering KviSensitiveThread::~KviSensitiveThread (this=%d)",this);
+ terminate();
+// debug("KviSensitiveThread::~KviSensitiveThread : terminate called (This=%d)",this);
+ m_pLocalEventQueueMutex->lock();
+ m_pLocalEventQueue->setAutoDelete(true);
+ delete m_pLocalEventQueue;
+ m_pLocalEventQueue = 0;
+ m_pLocalEventQueueMutex->unlock();
+ delete m_pLocalEventQueueMutex;
+ m_pLocalEventQueueMutex = 0;
+// debug("Exiting KviSensitiveThread::~KviSensitiveThread (this=%d)",this);
+}
+
+void KviSensitiveThread::enqueueEvent(KviThreadEvent *e)
+{
+// debug(">>> KviSensitiveThread::enqueueEvent() (this=%d)",this);
+ m_pLocalEventQueueMutex->lock();
+ if(!m_pLocalEventQueue)
+ {
+ // ops...already terminated (???)...eat the event and return
+ delete e;
+ m_pLocalEventQueueMutex->unlock();
+ return;
+ }
+ m_pLocalEventQueue->append(e);
+ m_pLocalEventQueueMutex->unlock();
+// debug("<<< KviSensitiveThread::enqueueEvent() (this=%d)",this);
+}
+
+KviThreadEvent * KviSensitiveThread::dequeueEvent()
+{
+// debug(">>> KviSensitiveThread::dequeueEvent() (this=%d)",this);
+ KviThreadEvent * ret;
+ m_pLocalEventQueueMutex->lock();
+ ret = m_pLocalEventQueue->first();
+ if(ret)m_pLocalEventQueue->removeFirst();
+ m_pLocalEventQueueMutex->unlock();
+// debug("<<< KviSensitiveThread::dequeueEvent() (this=%d)",this);
+ return ret;
+}
+
+void KviSensitiveThread::terminate()
+{
+// debug("Entering KviSensitiveThread::terminate (this=%d)",this);
+ enqueueEvent(new KviThreadEvent(KVI_THREAD_EVENT_TERMINATE));
+// debug("KviSensitiveThread::terminate() : event enqueued waiting (this=%d)",this);
+ wait();
+// debug("Exiting KviSensitiveThread::terminate (this=%d)",this);
+}
+
diff --git a/src/kvilib/system/kvi_thread.h b/src/kvilib/system/kvi_thread.h
new file mode 100644
index 00000000..bd6dab3b
--- /dev/null
+++ b/src/kvilib/system/kvi_thread.h
@@ -0,0 +1,378 @@
+#ifndef _KVI_THREAD_H_
+#define _KVI_THREAD_H_
+//
+// File : kvi_thread.h
+// Creation date : Mon May 17 1999 04:26:41 CEST by Szymon Stefanek
+//
+// This file is part of the KVirc irc client distribution
+// Copyright (C) 1999-2000 Szymon Stefanek (pragma at kvirc dot net)
+//
+// This program is FREE software. You can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your opinion) any later version.
+//
+// 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 General Public License
+// along with this program. If not, write to the Free Software Foundation,
+// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+
+#include "kvi_settings.h"
+#include "kvi_heapobject.h"
+#include "kvi_string.h"
+
+#include <qnamespace.h>
+#include <qobject.h>
+#include <qsocketnotifier.h>
+#include "kvi_pointerlist.h"
+#include <qevent.h>
+
+
+//
+// Simple thread implementation
+// This is enough for KVIrc needs
+// HANDLE WITH CARE
+//
+
+
+// Portability stuff
+
+#ifdef COMPILE_ON_WINDOWS
+
+ #include <winsock2.h> // this will pull in windows.h and will avoid windock.h inclusion
+ //#include <windows.h>
+ // Windoze thread abstraction layer
+ #define kvi_mutex_t HANDLE
+ inline void kvi_threadMutexInit(kvi_mutex_t * _pMutex_t)
+ {
+ *_pMutex_t = CreateMutex(0,0,NULL);
+ }
+ #define kvi_threadMutexLock(_pMutex_t) WaitForSingleObject(*_pMutex_t,INFINITE)
+ #define kvi_threadMutexUnlock(_pMutex_t) ReleaseMutex(*_pMutex_t)
+ #define kvi_threadMutexDestroy(_pMutex_t) CloseHandle(*_pMutex_t)
+ inline bool kvi_threadMutexTryLock(kvi_mutex_t *_pMutex_t)
+ {
+ return (WaitForSingleObject(*_pMutex_t,0) == WAIT_OBJECT_0);
+ }
+
+ #define kvi_thread_t HANDLE
+
+ inline bool kvi_threadCreate(kvi_thread_t *t,LPTHREAD_START_ROUTINE start_routine,void * arg)
+ {
+ DWORD dwThreadId;
+ *t = CreateThread(NULL,0,start_routine,arg,0,&dwThreadId);
+ return (*t != NULL);
+ }
+
+ #define kvi_threadExit() ExitThread(0)
+
+#else
+ #ifdef COMPILE_THREADS_USE_POSIX
+ // Glibc pthread implementation
+
+ #include <pthread.h>
+ #include <errno.h> // for EBUSY
+
+ // Mutex stuff
+ #define kvi_mutex_t pthread_mutex_t
+ #define kvi_threadMutexInit(_pMutex_t) pthread_mutex_init(_pMutex_t,0)
+ #define kvi_threadMutexLock(_pMutex_t) pthread_mutex_lock(_pMutex_t)
+ #define kvi_threadMutexUnlock(_pMutex_t) pthread_mutex_unlock(_pMutex_t)
+ #define kvi_threadMutexDestroy(_pMutex_t) pthread_mutex_destroy(_pMutex_t)
+ inline bool kvi_threadMutexTryLock(kvi_mutex_t *_pMutex_t)
+ {
+ return (pthread_mutex_trylock(_pMutex_t) != EBUSY);
+ }
+ // Actually unused
+ // #define kvi_threadMutexTryLock(_pMutex_t) pthread_mutex_trylock(_pMutex_t)
+
+ // Thread stuff
+ #define kvi_thread_t pthread_t
+
+ inline bool kvi_threadCreate(kvi_thread_t *t,void * (*start_routine)(void *),void * arg)
+ {
+ pthread_attr_t a;
+ pthread_attr_init(&a);
+ pthread_attr_setinheritsched(&a,PTHREAD_INHERIT_SCHED);
+ pthread_attr_setdetachstate(&a,PTHREAD_CREATE_DETACHED);
+
+ int ret = pthread_create(t,&a,start_routine,arg);
+
+ pthread_attr_destroy(&a);
+ return (ret == 0);
+ }
+
+ // We don't care about exit codes at all
+ #define kvi_threadExit() pthread_exit(0)
+ #else
+ #ifdef COMPILE_THREADS_USE_SOLARIS_LIBTHREAD
+ // Native solaris implementation
+ #include <thread.h>
+ #include <synch.h>
+ #include <errno.h>
+
+ // Mutex stuff
+ #define kvi_mutex_t mutex_t
+ #define kvi_threadMutexInit(_pMutex_t) mutex_init(_pMutex_t,0,0)
+ #define kvi_threadMutexLock(_pMutex_t) mutex_lock(_pMutex_t)
+ #define kvi_threadMutexUnlock(_pMutex_t) mutex_unlock(_pMutex_t)
+ #define kvi_threadMutexDestroy(_pMutex_t) mutex_destroy(_pMutex_t)
+ inline bool kvi_threadMutexTryLock(kvi_mutex_t *_pMutex_t)
+ {
+ return (mutex_trylock(_pMutex_t) != EBUSY);
+ };
+ // Actually unused
+ // #define kvi_threadMutexTryLock(_pMutex_t) mutex_trylock(_pMutex_t)
+
+ // Thread stuff
+ #define kvi_thread_t thread_t
+
+ inline bool kvi_threadCreate(kvi_thread_t *t,void * (*start_routine)(void *),void *arg)
+ {
+ return (thr_create(0,0,start_routine,arg,THR_DETACHED,t) == 0);
+ }
+
+ // We don't care about exit codes at all
+ #define kvi_threadExit() thr_exit(0)
+ #else
+// FIXME: #warning "Missing a decent thread implementation: we're going to fail , sorry!"
+ #endif
+ #endif
+#endif
+
+class KVILIB_API KviMutex : public KviHeapObject
+{
+private:
+ kvi_mutex_t m_mutex;
+#ifdef COMPILE_ON_WINDOWS
+ bool m_bLocked;
+#endif
+public:
+ KviMutex(){ kvi_threadMutexInit(&m_mutex); };
+ virtual ~KviMutex(){ kvi_threadMutexDestroy(&m_mutex); };
+public:
+#ifdef COMPILE_ON_WINDOWS
+ void lock(){ kvi_threadMutexLock(&m_mutex); m_bLocked = true; };
+ void unlock(){ m_bLocked = false; kvi_threadMutexUnlock(&m_mutex); };
+ bool locked(){ return m_bLocked; };
+#else
+ void lock(){ kvi_threadMutexLock(&m_mutex); };
+ void unlock(){ kvi_threadMutexUnlock(&m_mutex); };
+ bool locked();
+#endif
+};
+
+
+// simple thread class implementation
+// this is also called "Blind" thread class
+
+class KVILIB_API KviThread : public KviHeapObject
+{
+public:
+ KviThread();
+ virtual ~KviThread();
+private:
+ kvi_thread_t m_thread;
+ bool m_bRunning;
+ bool m_bStartingUp;
+ KviMutex * m_pRunningMutex;
+ KviPointerList<QEvent> * m_pLocalEventQueue;
+public:
+ // public KviThread interface
+ // HANDLE WITH CARE
+
+ // Runs the thread...call only from external threads!!! :)
+ // This function returns true if the child thread has been succesfully created
+ // this des not mean that run() is being already executed...
+ // isStartingUp() will return true from this moment until
+ // the child thread jumps into run() where it will be set to running state (isRunning() == true)
+ // and removed from startingUp state.
+ bool start();
+ // Returns the state of the thread...safe to call from anywhere
+ bool isRunning();
+ // Returns the state of the thread...safe to call from anywhere
+ bool isStartingUp(); // start() called , but not in run() yet...
+ // Waits for the termination of this thread: call only from external threads!!! :)
+ void wait();
+ // DO NOT TOUCH THIS ONE!
+ void internalThreadRun_doNotTouchThis();
+
+ static void sleep(unsigned long sec);
+ static void msleep(unsigned long msec);
+ static void usleep(unsigned long usec);
+protected:
+ // protected KviThread interface
+ // HANDLE WITH CARE TOO!
+
+ // Reimplement this with your job
+ virtual void run(){};
+ // Terminates the execution of the calling thread
+ void exit();
+ // The tricky part: threadsafe event dispatching
+ // Slave thread -> main thread objects
+ void postEvent(QObject *o,QEvent *e);
+private:
+ void setRunning(bool bRunning);
+ void setStartingUp(bool bStartingUp);
+};
+
+// QEvent::Type for Thread events
+#define KVI_THREAD_EVENT (((int)QEvent::User) + 2000)
+
+// CONSTANTS FOR KviThreadEvent::eventId();
+
+///////////////////////////////////////////////////////////////
+// extern -> slave thread
+
+// Your reimplementation of KviSensitiveThread MUST handle this
+// and exit when this event is received
+
+// Terminate is a plain KviThreadEvent
+#define KVI_THREAD_EVENT_TERMINATE 0
+
+///////////////////////////////////////////////////////////////
+// slave thread -> master object
+
+// The following standard events are sent from the thread to the master object
+
+// The following are plain KviThreadEvent objects
+#define KVI_THREAD_EVENT_SUCCESS 100
+
+// The following are KviThreadDataEvent<int>
+#define KVI_THREAD_EVENT_STATECHANGE 150
+
+// The following are KviThreadDataEvent<KviStr>
+#define KVI_THREAD_EVENT_MESSAGE 200
+#define KVI_THREAD_EVENT_WARNING 201
+#define KVI_THREAD_EVENT_ERROR 202
+#define KVI_THREAD_EVENT_DATA 203
+
+// The following is KviThreadDataEvent<KviDataBuffer>
+#define KVI_THREAD_EVENT_BINARYDATA 300
+
+// The user events
+#define KVI_THREAD_USER_EVENT_BASE 1000
+
+// #warning "Get rid of the m_szMessage member of KviThreadEvent : eventual data should be passed with a KviThreadDataEvent"
+
+// Base class for all thread events
+class KVILIB_API KviThreadEvent : public QEvent, public KviHeapObject
+{
+protected:
+ int m_eventId;
+ KviThread * m_pSender;
+public:
+ KviThreadEvent(int evId,KviThread * sender = 0)
+ : QEvent((QEvent::Type)KVI_THREAD_EVENT) , m_eventId(evId) , m_pSender(sender) {};
+ virtual ~KviThreadEvent(){};
+public:
+ // This is the sender of the event
+ // WARNING : this MAY be null , threads CAN send anonymous events
+ KviThread * sender(){ return m_pSender; };
+ int id(){ return m_eventId; };
+};
+
+template<class TData> class KviThreadDataEvent : public KviThreadEvent
+{
+protected:
+ TData * m_pData;
+public:
+ KviThreadDataEvent(int evId,TData * pData = 0,KviThread * sender = 0)
+ : KviThreadEvent(evId,sender){ m_pData = pData; };
+ virtual ~KviThreadDataEvent(){ if(m_pData)delete m_pData; };
+public:
+ void setData(TData * d){ if(m_pData)delete m_pData; m_pData = d; };
+ TData * getData(){ TData * aux = m_pData; m_pData = 0; return aux; };
+ TData * data(){ return m_pData; };
+};
+
+// A thread that has also an internal event queue
+// so events can be posted from the master side to the slave one
+// Reimplementations of this class should periodically check
+// dequeueEvent() and eventually process the incoming events (and then DELETE it)
+
+// KVI_THREAD_EVENT_TERMINATE should be always handled by the reimplementation
+// and it should always exit (cleanly) when this event is received
+
+
+class KVILIB_API KviSensitiveThread : public KviThread
+{
+public:
+ KviSensitiveThread();
+ virtual ~KviSensitiveThread();
+protected:
+ KviMutex * m_pLocalEventQueueMutex;
+ KviPointerList<KviThreadEvent> * m_pLocalEventQueue;
+public:
+ // enqueues an event directed to THIS thread
+ // the event must be allocated with NEW and
+ // will be destroyed on the slave side
+ void enqueueEvent(KviThreadEvent *e);
+ // enqueues a terminate event and waits() for the slave thread
+ // the slave thread MUST handle KVI_THREAD_EVENT_TERMINATE
+ void terminate();
+protected:
+ // slave side:
+ // returns the first event in the local queue
+ // the event MUST BE DELETED after processing
+ KviThreadEvent * dequeueEvent();
+};
+
+// =============================================================================================//
+// This is private stuff...only KviThread and KviApp may use it
+// and may call only specific functions...don't touch.
+
+typedef struct _KviThreadPendingEvent
+{
+ QObject *o;
+ QEvent *e;
+} KviThreadPendingEvent;
+
+class KVILIB_API KviThreadManager : public QObject
+{
+ friend class KviApp;
+ friend class KviThread;
+ Q_OBJECT
+protected:
+ // These should be private...but we don't want anyone to complain
+ // Treat as private plz.
+ KviThreadManager();
+ ~KviThreadManager();
+public:
+ static void killPendingEvents(QObject * receiver);
+private:
+#ifndef COMPILE_ON_WINDOWS
+ QSocketNotifier * m_pSn;
+#endif
+ KviMutex * m_pMutex; // This class performs only atomic operations
+ KviPointerList<KviThread> * m_pThreadList;
+ int m_iWaitingThreads;
+#ifndef COMPILE_ON_WINDOWS
+ KviPointerList<KviThreadPendingEvent> * m_pEventQueue;
+ int m_fd[2];
+ int m_iTriggerCount;
+#endif
+protected:
+ // Public to KviThread only
+ void registerSlaveThread(KviThread *t);
+ void unregisterSlaveThread(KviThread *t);
+
+ void threadEnteredWaitState();
+ void threadLeftWaitState();
+
+ void postSlaveEvent(QObject *o,QEvent *e);
+ void killPendingEventsByReceiver(QObject * receiver);
+ // Public to KviApp only
+ static void globalInit();
+ static void globalDestroy();
+private slots:
+ void eventsPending(int fd);
+};
+
+
+#endif //!_KVI_THREAD_H_
diff --git a/src/kvilib/system/kvi_time.cpp b/src/kvilib/system/kvi_time.cpp
new file mode 100644
index 00000000..f500b7d4
--- /dev/null
+++ b/src/kvilib/system/kvi_time.cpp
@@ -0,0 +1,135 @@
+//=============================================================================
+//
+// File : kvi_time.cpp
+// Creation date : Tue Sep 25 17:35:13 2001 GMT by Szymon Stefanek
+//
+// This file is part of the KVirc irc client distribution
+// Copyright (C) 2001-2004 Szymon Stefanek (pragma at kvirc dot net)
+//
+// This program is FREE software. You can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your opinion) any later version.
+//
+// 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 General Public License
+// along with this program. If not, write to the Free Software Foundation,
+// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+//=============================================================================
+
+#define __KVILIB__
+
+
+#include "kvi_time.h"
+#include "kvi_qstring.h"
+#include "kvi_locale.h"
+
+#ifdef COMPILE_ON_WINDOWS
+ #include <windows.h> // GetSystemTime
+
+ // Call SystemTimeToFileTime to copy the system time to a FILETIME structure.
+ // Call GetSystemTime to get the current system time to pass to SystemTimeToFileTime.
+ // Copy the contents of the FILETIME structure to a ULARGE_INTEGER structure.
+ // Initialize a SYSTEMTIME structure with the date and time of the first second of January 1, 1970.
+ // Call SystemTimeToFileTime, passing the SYSTEMTIME structure initialized in Step 3 to the call.
+ // Copy the contents of the FILETIME structure returned by SystemTimeToFileTime in Step 4 to
+ // a second ULARGE_INTEGER. The copied value should be greater than or equal to the value copied
+ // in Step 2. Subtract the 64-bit value in the ULARGE_INTEGER structure initialized in Step 2
+ // from the 64-bit value of the ULARGE_INTEGER structure initialized in Step 5.
+ // This produces a value in 100-nanosecond intervals since January 1, 1970.
+ // To convert this value to seconds, divide by 10,000,000.
+
+ // buah buah buahhhh lol ghgh :DDDDDDDDD
+
+ void kvi_gettimeofday(struct timeval * tmv,struct timezone *)
+ {
+ SYSTEMTIME st;
+ GetSystemTime(&st);
+
+ // this is simply fucked up..
+ // to minimize the possibility of wrapping we use also the day field.
+ // we actually give something that is near the number of seconds from the beginning
+ // of the current month...
+ // We cannot use the wMonth field since the months have variable length :/
+ tmv->tv_sec = (st.wDay * 86400) + (st.wHour * 3600) + (st.wMinute * 60) + (st.wSecond);
+ tmv->tv_usec = st.wMilliseconds * 1000;
+ }
+#endif
+
+KviMSecTimeInterval::KviMSecTimeInterval()
+{
+ m_uReferenceSecs = 0;
+ m_uReferenceUSecs = 0;
+}
+
+
+unsigned long KviMSecTimeInterval::mark()
+{
+ struct timeval tmv;
+ kvi_gettimeofday(&tmv,0);
+ unsigned long uDiff = ((((unsigned long)(tmv.tv_sec)) - m_uReferenceSecs) * 1000);
+ if(((unsigned long)(tmv.tv_usec)) > m_uReferenceUSecs)uDiff += (((unsigned long)(tmv.tv_usec) - m_uReferenceUSecs) / 1000);
+ else uDiff -= ((m_uReferenceUSecs - (unsigned long)(tmv.tv_usec)) / 1000);
+ m_uReferenceSecs = (unsigned long)tmv.tv_sec;
+ m_uReferenceUSecs = (unsigned long)tmv.tv_usec;
+ return uDiff;
+}
+
+namespace KviTimeUtils
+{
+ void secondsToDaysHoursMinsSecs(unsigned int uSecs,
+ unsigned int * uD,unsigned int * uH,unsigned int * uM,unsigned int * uS)
+ {
+ *uD = uSecs / 86400;
+ uSecs = uSecs % 86400;
+ *uH = uSecs / 3600;
+ uSecs = uSecs % 3600;
+ *uM = uSecs / 60;
+ *uS = uSecs % 60;
+ }
+
+ QString formatTimeInterval(unsigned int uSeconds,int iFlags)
+ {
+ unsigned int d,h,m,s;
+ secondsToDaysHoursMinsSecs(uSeconds,&d,&h,&m,&s);
+ QString ret;
+ // the following tricks maybe will help translators a bit...
+ if(iFlags & FillWithHypens)
+ {
+ ret = __tr2qs("- d -- h -- m -- s");
+ } else {
+ if((iFlags & NoLeadingEmptyIntervals) && (d == 0))
+ {
+ if(h > 0)
+ {
+ if(iFlags & NoLeadingZeroes)
+ KviQString::sprintf(ret,__tr2qs("%u h %u m %u s"),h,m,s);
+ else
+ KviQString::sprintf(ret,__tr2qs("%u h %u%u m %u%u s"),h,m / 10,m % 10,s / 10,s % 10);
+ } else {
+ if(m > 0)
+ {
+ if(iFlags & NoLeadingZeroes)
+ KviQString::sprintf(ret,__tr2qs("%u m %u s"),m,s);
+ else
+ KviQString::sprintf(ret,__tr2qs("%u m %u%u s"),m,s / 10,s % 10);
+ } else {
+ KviQString::sprintf(ret,__tr2qs("%u s"),s);
+ }
+ }
+ } else {
+ if(iFlags & NoLeadingZeroes)
+ KviQString::sprintf(ret,__tr2qs("%u d %u h %u m %u s"),d,h,m,s);
+ else
+ KviQString::sprintf(ret,__tr2qs("%u d %u%u h %u%u m %u%u s"),d,h / 10,h % 10,m / 10,m % 10,s / 10,s % 10);
+ }
+ }
+ return ret;
+ }
+
+}
diff --git a/src/kvilib/system/kvi_time.h b/src/kvilib/system/kvi_time.h
new file mode 100644
index 00000000..309eec10
--- /dev/null
+++ b/src/kvilib/system/kvi_time.h
@@ -0,0 +1,92 @@
+#ifndef _KVI_TIME_H_
+#define _KVI_TIME_H_
+
+//=============================================================================
+//
+// File : kvi_time.h
+// Creation date : Tue Sep 25 17:28:46 2001 GMT by Szymon Stefanek
+//
+// This file is part of the KVirc irc client distribution
+// Copyright (C) 2001 Szymon Stefanek (pragma at kvirc dot net)
+//
+// This program is FREE software. You can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your opinion) any later version.
+//
+// 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 General Public License
+// along with this program. If not, write to the Free Software Foundation,
+// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+//=============================================================================
+
+#include "kvi_settings.h"
+#include <qstring.h>
+
+
+#include <time.h> // for time()
+
+#define kvi_unixTime() time(0)
+#define kvi_timeSpan(_time_now,_time_before) ((_time_now) - (_time_before))
+#define kvi_secondsSince(_that_time_t) kvi_timeSpan(kvi_unixTime(),_that_time_t)
+
+#define kvi_time_t time_t
+
+#ifdef COMPILE_ON_WINDOWS
+
+ #include <winsock2.h> // struct timeval
+
+ extern KVILIB_API void kvi_gettimeofday(struct timeval * tmv,struct timezone * tmz);
+
+#else //!COMPILE_ON_WINDOWS
+
+ #include <sys/time.h> // gettimeofday() , struct timeval
+
+ inline void kvi_gettimeofday(struct timeval * tmv,struct timezone * tmz)
+ {
+ gettimeofday(tmv,tmz);
+ };
+
+#endif //!COMPILE_ON_WINDOWS
+
+// this works for time intervals a bit longer than 24 days
+class KVILIB_API KviMSecTimeInterval
+{
+public:
+ KviMSecTimeInterval();
+protected:
+ unsigned long m_uReferenceSecs;
+ unsigned long m_uReferenceUSecs;
+public:
+ // returns the number of milliseconds since
+ // mark() was last called (and thus marks
+ // the beginning of a new interval).
+ unsigned long mark();
+ // this wors ONLY in the same second that mark was called in
+ // and returns the tv_sec field of the gettimeofday()
+ // (remember that gettimeofday() is broken on windows)
+ unsigned long secondsCounter(){ return m_uReferenceSecs; };
+};
+
+namespace KviTimeUtils
+{
+
+
+ // splits the time span uSecs in days, hours, minutes and seconds
+ KVILIB_API void secondsToDaysHoursMinsSecs(unsigned int uSecs,
+ unsigned int * uD,unsigned int * uH,unsigned int * uM,unsigned int * uS);
+ // returns a string formatted like x d x h xx m xx s
+ enum FormatTimeSpanFlags {
+ NoLeadingEmptyIntervals = 1, // causes the leading empty intervals to be omitted
+ NoLeadingZeroes = 2, // no leading zeroes are printed in hours and seconds
+ FillWithHypens = 4 // uses only -- %d -- %h -- etc.. discards all other flags
+ };
+ KVILIB_API QString formatTimeInterval(unsigned int uSeconds,int iFlags = 0);
+};
+
+#endif //_KVI_TIME_H_
diff --git a/src/kvilib/system/moc_kvi_locale.cpp b/src/kvilib/system/moc_kvi_locale.cpp
new file mode 100644
index 00000000..52e2ae22
--- /dev/null
+++ b/src/kvilib/system/moc_kvi_locale.cpp
@@ -0,0 +1,92 @@
+/****************************************************************************
+** KviTranslator meta object code from reading C++ file 'kvi_locale.h'
+**
+** Created: Sun Mar 23 20:56:24 2008
+** by: The Qt MOC ($Id: qt/moc_yacc.cpp 3.3.8 edited Feb 2 14:59 $)
+**
+** WARNING! All changes made in this file will be lost!
+*****************************************************************************/
+
+#undef QT_NO_COMPAT
+#include "kvi_locale.h"
+#include <qmetaobject.h>
+#include <qapplication.h>
+
+#include <private/qucomextra_p.h>
+#if !defined(Q_MOC_OUTPUT_REVISION) || (Q_MOC_OUTPUT_REVISION != 26)
+#error "This file was generated using the moc from 3.3.8. It"
+#error "cannot be used with the include files from this version of Qt."
+#error "(The moc has changed too much.)"
+#endif
+
+const char *KviTranslator::className() const
+{
+ return "KviTranslator";
+}
+
+QMetaObject *KviTranslator::metaObj = 0;
+static QMetaObjectCleanUp cleanUp_KviTranslator( "KviTranslator", &KviTranslator::staticMetaObject );
+
+#ifndef QT_NO_TRANSLATION
+QString KviTranslator::tr( const char *s, const char *c )
+{
+ if ( qApp )
+ return qApp->translate( "KviTranslator", s, c, QApplication::DefaultCodec );
+ else
+ return QString::fromLatin1( s );
+}
+#ifndef QT_NO_TRANSLATION_UTF8
+QString KviTranslator::trUtf8( const char *s, const char *c )
+{
+ if ( qApp )
+ return qApp->translate( "KviTranslator", s, c, QApplication::UnicodeUTF8 );
+ else
+ return QString::fromUtf8( s );
+}
+#endif // QT_NO_TRANSLATION_UTF8
+
+#endif // QT_NO_TRANSLATION
+
+QMetaObject* KviTranslator::staticMetaObject()
+{
+ if ( metaObj )
+ return metaObj;
+ QMetaObject* parentObject = QTranslator::staticMetaObject();
+ metaObj = QMetaObject::new_metaobject(
+ "KviTranslator", parentObject,
+ 0, 0,
+ 0, 0,
+#ifndef QT_NO_PROPERTIES
+ 0, 0,
+ 0, 0,
+#endif // QT_NO_PROPERTIES
+ 0, 0 );
+ cleanUp_KviTranslator.setMetaObject( metaObj );
+ return metaObj;
+}
+
+void* KviTranslator::qt_cast( const char* clname )
+{
+ if ( !qstrcmp( clname, "KviTranslator" ) )
+ return this;
+ return QTranslator::qt_cast( clname );
+}
+
+bool KviTranslator::qt_invoke( int _id, QUObject* _o )
+{
+ return QTranslator::qt_invoke(_id,_o);
+}
+
+bool KviTranslator::qt_emit( int _id, QUObject* _o )
+{
+ return QTranslator::qt_emit(_id,_o);
+}
+#ifndef QT_NO_PROPERTIES
+
+bool KviTranslator::qt_property( int id, int f, QVariant* v)
+{
+ return QTranslator::qt_property( id, f, v);
+}
+
+bool KviTranslator::qt_static_property( QObject* , int , int , QVariant* ){ return FALSE; }
+#endif // QT_NO_PROPERTIES
diff --git a/src/kvilib/system/moc_kvi_thread.cpp b/src/kvilib/system/moc_kvi_thread.cpp
new file mode 100644
index 00000000..556849a9
--- /dev/null
+++ b/src/kvilib/system/moc_kvi_thread.cpp
@@ -0,0 +1,104 @@
+/****************************************************************************
+** KviThreadManager meta object code from reading C++ file 'kvi_thread.h'
+**
+** Created: Sun Mar 23 20:56:25 2008
+** by: The Qt MOC ($Id: qt/moc_yacc.cpp 3.3.8 edited Feb 2 14:59 $)
+**
+** WARNING! All changes made in this file will be lost!
+*****************************************************************************/
+
+#undef QT_NO_COMPAT
+#include "kvi_thread.h"
+#include <qmetaobject.h>
+#include <qapplication.h>
+
+#include <private/qucomextra_p.h>
+#if !defined(Q_MOC_OUTPUT_REVISION) || (Q_MOC_OUTPUT_REVISION != 26)
+#error "This file was generated using the moc from 3.3.8. It"
+#error "cannot be used with the include files from this version of Qt."
+#error "(The moc has changed too much.)"
+#endif
+
+const char *KviThreadManager::className() const
+{
+ return "KviThreadManager";
+}
+
+QMetaObject *KviThreadManager::metaObj = 0;
+static QMetaObjectCleanUp cleanUp_KviThreadManager( "KviThreadManager", &KviThreadManager::staticMetaObject );
+
+#ifndef QT_NO_TRANSLATION
+QString KviThreadManager::tr( const char *s, const char *c )
+{
+ if ( qApp )
+ return qApp->translate( "KviThreadManager", s, c, QApplication::DefaultCodec );
+ else
+ return QString::fromLatin1( s );
+}
+#ifndef QT_NO_TRANSLATION_UTF8
+QString KviThreadManager::trUtf8( const char *s, const char *c )
+{
+ if ( qApp )
+ return qApp->translate( "KviThreadManager", s, c, QApplication::UnicodeUTF8 );
+ else
+ return QString::fromUtf8( s );
+}
+#endif // QT_NO_TRANSLATION_UTF8
+
+#endif // QT_NO_TRANSLATION
+
+QMetaObject* KviThreadManager::staticMetaObject()
+{
+ if ( metaObj )
+ return metaObj;
+ QMetaObject* parentObject = QObject::staticMetaObject();
+ static const QUParameter param_slot_0[] = {
+ { "fd", &static_QUType_int, 0, QUParameter::In }
+ };
+ static const QUMethod slot_0 = {"eventsPending", 1, param_slot_0 };
+ static const QMetaData slot_tbl[] = {
+ { "eventsPending(int)", &slot_0, QMetaData::Private }
+ };
+ metaObj = QMetaObject::new_metaobject(
+ "KviThreadManager", parentObject,
+ slot_tbl, 1,
+ 0, 0,
+#ifndef QT_NO_PROPERTIES
+ 0, 0,
+ 0, 0,
+#endif // QT_NO_PROPERTIES
+ 0, 0 );
+ cleanUp_KviThreadManager.setMetaObject( metaObj );
+ return metaObj;
+}
+
+void* KviThreadManager::qt_cast( const char* clname )
+{
+ if ( !qstrcmp( clname, "KviThreadManager" ) )
+ return this;
+ return QObject::qt_cast( clname );
+}
+
+bool KviThreadManager::qt_invoke( int _id, QUObject* _o )
+{
+ switch ( _id - staticMetaObject()->slotOffset() ) {
+ case 0: eventsPending((int)static_QUType_int.get(_o+1)); break;
+ default:
+ return QObject::qt_invoke( _id, _o );
+ }
+ return TRUE;
+}
+
+bool KviThreadManager::qt_emit( int _id, QUObject* _o )
+{
+ return QObject::qt_emit(_id,_o);
+}
+#ifndef QT_NO_PROPERTIES
+
+bool KviThreadManager::qt_property( int id, int f, QVariant* v)
+{
+ return QObject::qt_property( id, f, v);
+}
+
+bool KviThreadManager::qt_static_property( QObject* , int , int , QVariant* ){ return FALSE; }
+#endif // QT_NO_PROPERTIES