summaryrefslogtreecommitdiffstats
path: root/src/kvilib/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/kvilib/core')
-rw-r--r--src/kvilib/core/Makefile.am5
-rw-r--r--src/kvilib/core/kvi_bswap.h63
-rw-r--r--src/kvilib/core/kvi_error.cpp237
-rw-r--r--src/kvilib/core/kvi_error.h188
-rw-r--r--src/kvilib/core/kvi_heapobject.cpp96
-rw-r--r--src/kvilib/core/kvi_heapobject.h50
-rw-r--r--src/kvilib/core/kvi_inttypes.h95
-rw-r--r--src/kvilib/core/kvi_malloc.cpp198
-rw-r--r--src/kvilib/core/kvi_malloc.h88
-rw-r--r--src/kvilib/core/kvi_memmove.cpp253
-rw-r--r--src/kvilib/core/kvi_memmove.h105
-rw-r--r--src/kvilib/core/kvi_pointerhashtable.h999
-rw-r--r--src/kvilib/core/kvi_pointerlist.h1069
-rw-r--r--src/kvilib/core/kvi_qcstring.h39
-rw-r--r--src/kvilib/core/kvi_qstring.cpp1125
-rw-r--r--src/kvilib/core/kvi_qstring.h293
-rw-r--r--src/kvilib/core/kvi_strasm.h194
-rw-r--r--src/kvilib/core/kvi_string.cpp3063
-rw-r--r--src/kvilib/core/kvi_string.h552
-rw-r--r--src/kvilib/core/kvi_stringarray.cpp119
-rw-r--r--src/kvilib/core/kvi_stringarray.h55
-rw-r--r--src/kvilib/core/kvi_valuelist.h37
22 files changed, 8923 insertions, 0 deletions
diff --git a/src/kvilib/core/Makefile.am b/src/kvilib/core/Makefile.am
new file mode 100644
index 00000000..c84487eb
--- /dev/null
+++ b/src/kvilib/core/Makefile.am
@@ -0,0 +1,5 @@
+###############################################################################
+# KVirc IRC client Makefile - 16.12.98 Szymon Stefanek <stefanek@tin.it>
+###############################################################################
+
+EXTRA_DIST = *.cpp *.h
diff --git a/src/kvilib/core/kvi_bswap.h b/src/kvilib/core/kvi_bswap.h
new file mode 100644
index 00000000..5d5ef5bb
--- /dev/null
+++ b/src/kvilib/core/kvi_bswap.h
@@ -0,0 +1,63 @@
+#ifndef _KVI_BSWAP_H_
+#define _KVI_BSWAP_H_
+
+//=============================================================================
+//
+// File : kvi_bswap.h
+// Creation date : Fri Mar 19 1999 03:15:21 CEST by Szymon Stefanek
+//
+// This file is part of the KVirc irc client distribution
+// Copyright (C) 1999-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_inttypes.h"
+
+
+// KVILIB_API has been removed from therse two functions
+// these should always go inlined
+
+inline kvi_u64_t kvi_swap64(kvi_u64_t i)
+{
+ // abcdefgh to hgfedcba
+ return ((i << 56) | /* h to a */
+ ((i & 0xff00) << 40) | /* g to b */
+ ((i & 0xff0000) << 24) | /* f to c */
+ ((i & 0xff000000) << 8) | /* e to d */
+ ((i >> 8) & 0xff000000) | /* d to e */
+ ((i >> 24) & 0xff0000) | /* c to f */
+ ((i >> 40) & 0xff00) | /* b to g */
+ (i >> 56)); /* a to h */
+}
+
+inline kvi_u32_t kvi_swap32(kvi_u32_t i)
+{
+ // abcd to dcba
+ return ((i << 24) | ((i & 0xff00) << 8) | ((i >> 8) & 0xff00) | (i >> 24));
+}
+
+inline kvi_u16_t kvi_swap16(kvi_u16_t i)
+{
+ // ab to ba
+ return ((i << 8) | (i >> 8));
+}
+
+
+
+
+#endif // !_KVI_BSWAP_H_
diff --git a/src/kvilib/core/kvi_error.cpp b/src/kvilib/core/kvi_error.cpp
new file mode 100644
index 00000000..6497c757
--- /dev/null
+++ b/src/kvilib/core/kvi_error.cpp
@@ -0,0 +1,237 @@
+//=============================================================================
+//
+// File : kvi_error.cpp
+// Creation date : Sun Jul 02 2000 18:37:02 by Szymon Stefanek
+//
+// This file is part of the KVirc irc client distribution
+// Copyright (C) 1999-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.
+//
+//=============================================================================
+
+#define __KVILIB__
+
+#define _KVI_ERROR_CPP_
+
+#include "kvi_locale.h"
+#include "kvi_error.h"
+#include "kvi_settings.h"
+
+
+#ifdef COMPILE_ON_WINDOWS
+#include <winsock2.h> // for the WSAE* error codes
+#endif
+
+#include <errno.h>
+
+#ifdef HAVE_STRERROR
+#include <string.h> // for strerror()
+#endif
+
+// FIXME: This stuff should basically die and be eventually replaced with some
+// helper functions for handling ONLY system errors.
+//
+// WARNING: getDescription() is not even thread safe... it will die in the near future
+
+const char * g_errorTable[KVI_NUM_ERRORS]=
+{
+ __tr_no_lookup("Success"), // 000: success
+ __tr_no_lookup("Unknown error"), // 001: unkonwnError
+ __tr_no_lookup("Internal error"), // 002: internalError
+ __tr_no_lookup("Unknown command"), // 003: unknownCommand
+ __tr_no_lookup("Missing closing brace"), // 004: missingClosingBrace
+ __tr_no_lookup("Unexpected end of command in string"), // 005: unexpectedEndInString
+ __tr_no_lookup("Unexpected end of command in dictionary key"), // 006: unexpectedEndInDictionaryKey
+ __tr_no_lookup("Switch dash without switch letter"), // 007: switchDashWithoutSwitchLetter
+ __tr_no_lookup("Unknown function"), // 008: unknownFunction
+ __tr_no_lookup("Unexpected end of command in parenthesis"), // 009: unexpectedEndInParenthesis
+ __tr_no_lookup("Unexpected end of command in function parameters"), // 010: unexpectedEndInFunctionParams
+ __tr_no_lookup("Missing variable name"), // 011: missingVariableName
+ __tr_no_lookup("Variable or identifier expected"), // 012: variableOrIdentifierExpected
+ __tr_no_lookup("Left operand is not a number"), // 013: leftOperandIsNotANumber
+ __tr_no_lookup("Multiple operations not supported for numeric operators"), // 014: multipleOpsNotSupportedForOperator
+ __tr_no_lookup("Division by zero"), // 015: divisionByZero
+ __tr_no_lookup("Modulo by zero"), // 016: moduloByZero
+ __tr_no_lookup("Right operand is not a number"), // 017: rightOperandIsNotANumber
+ __tr_no_lookup("Unterminated expression (missing ')' ?)"), // 018: unterminatedExpression
+ __tr_no_lookup("Unterminated subexpression (Parenthesis mismatch)"), // 019: unterminatedSubexpression
+ __tr_no_lookup("Unexpected character"), // 020: unexpectedCharacter
+ __tr_no_lookup("Unknown operator"), // 021: unknownOperator
+ __tr_no_lookup("No host to resolve"), // 022
+ __tr_no_lookup("(DNS Internal) Unsupported address family"), // 023
+ __tr_no_lookup("Valid name but the host has no IP address"), // 024
+ __tr_no_lookup("Unrecoverable nameserver error (crashed ?)"), // 025
+ __tr_no_lookup("Dns temporaneous fault (try again)"), // 026
+ __tr_no_lookup("(DNS Internal) Bad flags"), // 027
+ __tr_no_lookup("(DNS Internal) Out of memory"), // 028
+ __tr_no_lookup("(DNS Internal) Service not supported"), // 029
+ __tr_no_lookup("Unknown node (host not found)"), // 030
+ __tr_no_lookup("(DNS Internal) Unsupported socket type"), // 031
+ __tr_no_lookup("Dns query failed"), // 032
+ __tr_no_lookup("This KVIrc executable has no IPV6 support"), // 033
+ __tr_no_lookup("Host not found"), // 034
+ __tr_no_lookup("(DNS Internal) IPC failure (slave data corrupted)"), // 035
+ __tr_no_lookup("Another connection in progress"), // 036
+ __tr_no_lookup("Invalid IP address"), // 037
+ __tr_no_lookup("Socket creation failed"), // 038
+ __tr_no_lookup("Failed to put the socket in non blocking mode"), // 039
+ __tr_no_lookup("Bad file descriptor"), // 040
+ __tr_no_lookup("Out of address space"), // 041
+ __tr_no_lookup("Connection refused"), // 042
+ __tr_no_lookup("Kernel networking panic"), // 043
+ __tr_no_lookup("Connection timed out"), // 044
+ __tr_no_lookup("Network is unreachable"), // 045
+ __tr_no_lookup("Broken pipe"), // 046
+ __tr_no_lookup("Invalid proxy address"), // 047
+ __tr_no_lookup("Remote end has closed the connection"), // 048
+ __tr_no_lookup("Invalid irc context id"), // 049
+ __tr_no_lookup("Error in loading module"), // 050
+ __tr_no_lookup("No such module command"), // 051
+ __tr_no_lookup("No such module function"), // 052
+ __tr_no_lookup("Left operand is not a dictionary reference"), // 053
+ __tr_no_lookup("Right operand is not a dictionary reference"), // 054
+ __tr_no_lookup("Missing object class name"), // 055
+ __tr_no_lookup("No such object class"), // 056
+ __tr_no_lookup("No such object"), // 057
+ __tr_no_lookup("No such object function"), // 058
+ __tr_no_lookup("Invalid left operand"), // 059
+ __tr_no_lookup("Not enough parameters"), // 060
+ __tr_no_lookup("Integer parameter expected"), // 061
+ __tr_no_lookup("Invalid parameter"), // 062
+ __tr_no_lookup("No such file"), // 063
+ __tr_no_lookup("Open parenthesis expected"), // 064
+ __tr_no_lookup("Open brace expected"), // 065
+ __tr_no_lookup("Can't kill a builtin class"), // 066
+ __tr_no_lookup("The SOCKSV4 protocol lacks IpV6 support"), // 067
+ __tr_no_lookup("Unrecognized proxy reply"), // 068
+ __tr_no_lookup("Proxy response: auth failed: access denied"),
+ __tr_no_lookup("Proxy response: No acceptable auth method: request rejected"),
+ __tr_no_lookup("Proxy response: request failed"),
+ __tr_no_lookup("Proxy response: ident failed"),
+ __tr_no_lookup("Proxy response: ident not matching"),
+ __tr_no_lookup("Proxy response: general SOCKS failure"),
+ __tr_no_lookup("Proxy response: connection not allowed"),
+ __tr_no_lookup("Proxy response: network unreachable"),
+ __tr_no_lookup("Proxy response: host unreachable"),
+ __tr_no_lookup("Proxy response: connection refused"),
+ __tr_no_lookup("Proxy response: TTL expired"),
+ __tr_no_lookup("Proxy response: command not supported"),
+ __tr_no_lookup("Proxy response: address type not supported"),
+ __tr_no_lookup("Proxy response: invalid address"),
+ __tr_no_lookup("Invalid port number"),
+ __tr_no_lookup("Socket not connected"),
+ __tr_no_lookup("Insufficient resources to complete the operation"),
+ __tr_no_lookup("Can't setup a listening socket : bind failed"),
+ __tr_no_lookup("Can't resolve the localhost name"),
+ __tr_no_lookup("Unsupported image format"),
+ __tr_no_lookup("Can't open file for appending"),
+ __tr_no_lookup("Can't open file for writing"),
+ __tr_no_lookup("File I/O error"),
+ __tr_no_lookup("Acknowledge error"),
+ __tr_no_lookup("Can't open file for reading"),
+ __tr_no_lookup("Can't send a zero-size file"),
+ __tr_no_lookup("Missing popup name"),
+ __tr_no_lookup("'item', 'popup', 'label' or 'separator' keyword expected"),
+ __tr_no_lookup("Self modification not allowed"),
+ __tr_no_lookup("UNUSED"),
+ __tr_no_lookup("Feature not available"),
+ __tr_no_lookup("Unexpected characters in array index"),
+ __tr_no_lookup("Unexpected end in expression"),
+ __tr_no_lookup("Unexpected end in array index"),
+ __tr_no_lookup("Connection thru HTTP proxy failed"),
+ __tr_no_lookup("Case , match , regexp , default or break keyword expected"),
+ __tr_no_lookup("Access denied"),
+ __tr_no_lookup("Address already in use"),
+ __tr_no_lookup("Can't assign the requested address"),
+ __tr_no_lookup("Connection reset by peer"),
+ __tr_no_lookup("Host unreachable (no route to host)"),
+ __tr_no_lookup("Variable expected"),
+ __tr_no_lookup("Invalid array index: positive integer expected"),
+ __tr_no_lookup("listen() call failed"),
+ __tr_no_lookup("This executable has been compiled without SSL support"),
+ __tr_no_lookup("Secure Socket Layer error"),
+ __tr_no_lookup("Slash (/) character expected"),
+ __tr_no_lookup("Unknown string manipulation operation"),
+ __tr_no_lookup("Operation aborted"),
+ __tr_no_lookup("Unexpected token"),
+ __tr_no_lookup("Scope object already defined (unexpected @)"),
+ __tr_no_lookup("There is no $this pointer in this scope (unexpected @)")
+};
+
+namespace KviError
+{
+ const char * getUntranslatedDescription(int iErrorCode)
+ {
+ if((iErrorCode < KVI_NUM_ERRORS) && (iErrorCode >= 0))
+ return g_errorTable[iErrorCode];
+#ifdef HAVE_STRERROR
+ if(iErrorCode < 0)return strerror(-iErrorCode);
+#endif
+ return g_errorTable[KviError_unknownError];
+ }
+
+ QString getDescription(int iErrorCode)
+ {
+ return __tr2qs_no_xgettext(getUntranslatedDescription(iErrorCode));
+ }
+
+ int translateSystemError(int iErrNo)
+ {
+#ifdef COMPILE_ON_WINDOWS
+ switch(iErrNo)
+ {
+ case EBADF: return KviError_badFileDescriptor; break;
+ case WSAEINVAL:
+ case WSAEFAULT:
+ case EFAULT: return KviError_outOfAddressSpace; break;
+ case WSAECONNREFUSED: return KviError_connectionRefused; break;
+ case WSAENOTSOCK: return KviError_kernelNetworkingPanic; break;
+ case WSAETIMEDOUT: return KviError_connectionTimedOut; break;
+ case WSAENETUNREACH: return KviError_networkUnreachable; break;
+ case EPIPE: return KviError_brokenPipe; break;
+ case WSAENOTCONN: return KviError_socketNotConnected; break;
+
+ case WSAEACCES: return KviError_accessDenied; break;
+ case WSAEADDRINUSE: return KviError_addressAlreadyInUse; break;
+ case WSAEADDRNOTAVAIL: return KviError_cantAssignRequestedAddress; break;
+ case WSAEAFNOSUPPORT: return KviError_unsupportedAddressFamily; break;
+ case WSAECONNRESET: return KviError_connectionResetByPeer; break;
+ case WSAEHOSTUNREACH: return KviError_hostUnreachable; break;
+
+ //case ENOBUFS: return KviError_insufficientResources; break;
+ // Unhandled error...pass errno to the strerror function
+ default: return -iErrNo; break;
+ }
+#else
+ switch(iErrNo)
+ {
+ case EBADF: return KviError_badFileDescriptor; break;
+ case EFAULT: return KviError_outOfAddressSpace; break;
+ case ECONNREFUSED: return KviError_connectionRefused; break;
+ case ENOTSOCK: return KviError_kernelNetworkingPanic; break;
+ case ETIMEDOUT: return KviError_connectionTimedOut; break;
+ case ENETUNREACH: return KviError_networkUnreachable; break;
+ case EPIPE: return KviError_brokenPipe; break;
+ case ENOTCONN: return KviError_socketNotConnected; break;
+ case ENOBUFS: return KviError_insufficientResources; break;
+ case EHOSTUNREACH: return KviError_hostUnreachable; break;
+ // Unhandled error...pass errno to the strerror function
+ default: return -iErrNo; break;
+ }
+#endif
+ }
+};
+
diff --git a/src/kvilib/core/kvi_error.h b/src/kvilib/core/kvi_error.h
new file mode 100644
index 00000000..7ab55e88
--- /dev/null
+++ b/src/kvilib/core/kvi_error.h
@@ -0,0 +1,188 @@
+#ifndef _KVI_ERROR_H_
+#define _KVI_ERROR_H_
+//=============================================================================
+//
+// File : kvi_error.h
+// Creation date : Sun Jul 02 2000 18:35:56 by Szymon Stefanek
+//
+// This file is part of the KVirc irc client distribution
+// Copyright (C) 1999-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_qstring.h"
+
+#define KviError_success 0
+#define KviError_unknownError 1
+#define KviError_internalError 2
+#define KviError_unknownCommand 3
+#define KviError_missingClosingBrace 4
+#define KviError_unexpectedEndInString 5
+#define KviError_unexpectedEndInDictionaryKey 6
+#define KviError_switchDashWithoutSwitchLetter 7
+#define KviError_unknownFunction 8
+#define KviError_unexpectedEndInParenthesis 9
+#define KviError_unexpectedEndInFunctionParams 10
+#define KviError_missingVariableName 11
+#define KviError_variableOrIdentifierExpected 12
+#define KviError_leftOperandIsNotANumber 13
+#define KviError_multipleOpsNotSupportedForOperator 14
+#define KviError_divisionByZero 15
+#define KviError_moduloByZero 16
+#define KviError_rightOperandIsNotANumber 17
+#define KviError_unterminatedExpression 18
+#define KviError_unterminatedSubexpression 19
+#define KviError_unexpectedCharacter 20
+#define KviError_unknownOperator 21
+
+#define KviError_noHostToResolve 22
+#define KviError_unsupportedAddressFamily 23
+#define KviError_validNameButNoIpAddress 24
+#define KviError_unrecoverableNameserverError 25
+#define KviError_dnsTemporaneousFault 26
+#define KviError_dnsInternalErrorBadFlags 27
+#define KviError_dnsInternalErrorOutOfMemory 28
+#define KviError_dnsInternalErrorServiceNotSupported 29
+#define KviError_dnsNoName 30
+#define KviError_dnsInternalErrorUnsupportedSocketType 31
+#define KviError_dnsQueryFailed 32
+#define KviError_noIpV6Support 33
+#define KviError_hostNotFound 34
+#define KviError_dnsInternalIPCFailure 35
+
+#define KviError_anotherConnectionInProgress 36
+#define KviError_invalidIpAddress 37
+#define KviError_socketCreationFailed 38
+#define KviError_asyncSocketFailed 39
+#define KviError_badFileDescriptor 40
+#define KviError_outOfAddressSpace 41
+#define KviError_connectionRefused 42
+#define KviError_kernelNetworkingPanic 43
+#define KviError_connectionTimedOut 44
+#define KviError_networkUnreachable 45
+#define KviError_brokenPipe 46
+#define KviError_invalidProxyAddress 47
+#define KviError_remoteEndClosedConnection 48
+
+#define KviError_invalidIrcContextId 49
+#define KviError_errorInLoadingModule 50
+#define KviError_noSuchModuleCommand 51
+#define KviError_noSuchModuleFunction 52
+
+#define KviError_leftOperandIsNotADictionaryReference 53
+#define KviError_rightOperandIsNotADictionaryReference 54
+
+#define KviError_missingObjectClassName 55
+#define KviError_noSuchObjectClass 56
+#define KviError_noSuchObject 57
+#define KviError_noSuchObjectFunction 58
+
+#define KviError_invalidLeftOperand 59
+
+#define KviError_notEnoughParameters 60
+#define KviError_integerParameterExpected 61
+#define KviError_invalidParameter 62
+
+#define KviError_noSuchFile 63
+
+#define KviError_openParenthesisExpected 64
+#define KviError_openBraceExpected 65
+
+#define KviError_cantKillABuiltinClass 66
+#define KviError_socksV4LacksIpV6Support 67
+#define KviError_unrecognizedProxyReply 68
+#define KviError_proxyAuthFailed 69
+#define KviError_proxyNoAcceptableAuthMethod 70
+
+#define KviError_proxyReply91RequestFailed 71
+#define KviError_proxyReply92IdentFailed 72
+#define KviError_proxyReply93IdentNotMatching 73
+#define KviError_proxyReply01GeneralSOCKSFailure 74
+#define KviError_proxyReply02ConnectionNotAllowed 75
+#define KviError_proxyReply03NetworkUnreachable 76
+#define KviError_proxyReply04HostUnreachable 77
+#define KviError_proxyReply05ConnectionRefused 78
+#define KviError_proxyReply06TTLExpired 79
+#define KviError_proxyReply07CommandNotSupported 80
+#define KviError_proxyReply08AddressTypeNotSupported 81
+#define KviError_proxyReply09InvalidAddress 82
+
+#define KviError_invalidPortNumber 83
+#define KviError_socketNotConnected 84
+#define KviError_insufficientResources 85
+#define KviError_bindFailed 86
+#define KviError_cantResolveLocalhost 87
+
+#define KviError_unsupportedImageFormat 88
+
+#define KviError_cantOpenFileForAppending 89
+#define KviError_cantOpenFileForWriting 90
+#define KviError_fileIOError 91
+#define KviError_acknowledgeError 92
+#define KviError_cantOpenFileForReading 93
+#define KviError_cantSendAZeroSizeFile 94
+
+#define KviError_missingPopupName 95
+#define KviError_itemPopupOrSeparatorExpected 96
+#define KviError_selfModificationNotAllowed 97
+
+//#define KviError_recursionTooDeep 98
+#define KviError_featureNotAvailable 99
+
+#define KviError_unexpectedCharactersInArrayIndex 100
+#define KviError_unexpectedEndInExpression 101
+#define KviError_unexpectedEndInArrayIndex 102
+
+#define KviError_proxyHttpFailure 103
+#define KviError_caseMatchRegexpDefaultOrBreakExpected 104
+
+
+#define KviError_accessDenied 105
+#define KviError_addressAlreadyInUse 106
+#define KviError_cantAssignRequestedAddress 107
+#define KviError_connectionResetByPeer 108
+#define KviError_hostUnreachable 109
+
+#define KviError_variableExpected 110
+#define KviError_invalidArrayIndex 111
+
+#define KviError_listenFailed 112
+
+#define KviError_noSSLSupport 113
+#define KviError_SSLError 114
+
+#define KviError_slashCharacterExpected 115
+#define KviError_unknownStringManipulationOperator 116
+
+#define KviError_operationAborted 117
+
+#define KviError_unexpectedToken 118
+
+#define KviError_scopeObjectAlreadyDefined 119
+#define KviError_noThisObject 120
+
+#define KVI_NUM_ERRORS 121
+
+namespace KviError
+{
+ KVILIB_API QString getDescription(int iErrorCode);
+ KVILIB_API const char * getUntranslatedDescription(int iErrorCode);
+ KVILIB_API int translateSystemError(int iErrNo);
+};
+
+#endif //_KVI_ERROR_H_
diff --git a/src/kvilib/core/kvi_heapobject.cpp b/src/kvilib/core/kvi_heapobject.cpp
new file mode 100644
index 00000000..7568086d
--- /dev/null
+++ b/src/kvilib/core/kvi_heapobject.cpp
@@ -0,0 +1,96 @@
+//=============================================================================
+//
+// File : kvi_heapobject.cpp
+// Created on Wed 24 Mar 2004 04:45:17 by Szymon Stefanek
+//
+// This file is part of the KVIrc IRC client distribution
+// Copyright (C) 2004-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.
+//
+//=============================================================================
+
+#define __KVILIB__
+
+
+#include "kvi_heapobject.h"
+#include "kvi_malloc.h"
+
+// On windows we need to override new and delete operators
+// to ensure that always the right new/delete pair is called for an object instance
+// This bug jumps out because windows uses a local heap for each
+// executable module (exe or dll).
+// (this is a well known bug described in Q122675 of MSDN)
+
+// on Linux it is not needed: there is a single global heap
+
+
+
+// 05.02.2005 : scalar/vector deleting destructors in modules
+//
+// There are also other issues involving the MSVC compiler.
+// When the operator new is called on an object with a virtual
+// destructor the compiler generates a helper function
+// called "vector deleting destructor" that is used to both
+// free the object's memory and call the object's destructor.
+// (In fact there is also a "scalar deleting destructor" but
+// MSVC seems to call the vector version also for scalar deletes ?!?)
+// The problem arises when operator new is called in a module:
+// the helper function gets stuffed in one of the module's sections
+// and when the module is unloaded any attempt to delete
+// the object will simply jump into no man's land.
+
+// An "unhandled exception" in a "call [%eax]" corresponding
+// to a delete <pointer> may be a symptom of this problem.
+
+// I haven't been able to find a solution nicer than having
+// a static allocation function in each class that can be
+// created from inside a module and destroyed anywhere else
+// and has a virtual destructor.
+
+#ifdef COMPILE_ON_WINDOWS
+ void * KviHeapObject::operator new(size_t uSize)
+ {
+ return kvi_malloc(uSize);
+ }
+
+ void KviHeapObject::operator delete(void * pData)
+ {
+ kvi_free(pData);
+ }
+
+ void * KviHeapObject::operator new[](size_t uSize)
+ {
+ return kvi_malloc(uSize);
+ }
+
+ void KviHeapObject::operator delete[](void * pData)
+ {
+ kvi_free(pData);
+ }
+
+ // these are the debug versions...
+ void * KviHeapObject::operator new(size_t uSize,const char *,int)
+ {
+ return kvi_malloc(uSize);
+ }
+
+ void KviHeapObject::operator delete(void * pData,const char *,int)
+ {
+ kvi_free(pData);
+ }
+#endif
+
+
diff --git a/src/kvilib/core/kvi_heapobject.h b/src/kvilib/core/kvi_heapobject.h
new file mode 100644
index 00000000..3d1638cf
--- /dev/null
+++ b/src/kvilib/core/kvi_heapobject.h
@@ -0,0 +1,50 @@
+#ifndef _KVI_HEAPOBJECT_H_
+#define _KVI_HEAPOBJECT_H_
+//=============================================================================
+//
+// File : kvi_heapobject.h
+// Created on Wed 24 Mar 2004 04:45:17 by Szymon Stefanek
+//
+// This file is part of the KVIrc IRC client distribution
+// Copyright (C) 2004-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"
+
+// See kvi_heapobject.cpp for comments on this class
+
+#ifdef COMPILE_ON_WINDOWS
+
+ class KVILIB_API KviHeapObject
+ {
+ public:
+ void * operator new(size_t uSize);
+ void operator delete(void * pData);
+ void * operator new[](size_t uSize);
+ void operator delete[](void * pData);
+ void * operator new(size_t uSize,const char *,int);
+ void operator delete(void * pData,const char *,int);
+ };
+#else //!COMPILE_ON_WINDOWS
+ class KVILIB_API KviHeapObject
+ {
+ // on other platforms this crap is not necessary
+ };
+#endif //!COMPILE_ON_WINDOWS
+
+#endif //!_KVI_HEAPOBJECT_H_
diff --git a/src/kvilib/core/kvi_inttypes.h b/src/kvilib/core/kvi_inttypes.h
new file mode 100644
index 00000000..6405ee79
--- /dev/null
+++ b/src/kvilib/core/kvi_inttypes.h
@@ -0,0 +1,95 @@
+#ifndef _KVI_INTTYPES_H_
+#define _KVI_INTTYPES_H_
+//=============================================================================
+//
+// File : kvi_inttypes.h
+// Creation date : Wed Sep 4 22:28:00 2002 GMT by Szymon Stefanek
+//
+// This file is part of the KVirc irc client distribution
+// Copyright (C) 2002-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"
+
+#ifdef COMPILE_ON_WINDOWS
+ // we don't have a configure script here
+ // so we can't check the size of types
+ // We rely on the ms specific definitions then
+ typedef __int64 kvi_i64_t;
+ typedef unsigned __int64 kvi_u64_t;
+ typedef int kvi_i32_t;
+ typedef unsigned int kvi_u32_t;
+ typedef short int kvi_i16_t;
+ typedef short unsigned int kvi_u16_t;
+ typedef char kvi_i8_t;
+ typedef unsigned char kvi_u8_t;
+#else
+ #if SIZEOF_LONG_INT == 8
+ // the most common case on 64 bit machines
+ typedef long int kvi_i64_t;
+ typedef unsigned long int kvi_u64_t;
+ #elif SIZEOF_INT == 8
+ // 64 bit ints ?.. a Cray ? :D
+ typedef int kvi_i64_t;
+ typedef unsigned int kvi_u64_t;
+ #elif SIZEOF_LONG_LONG_INT == 8
+ // the most common case on 32 bit machines
+ typedef long long int kvi_i64_t;
+ typedef unsigned long long int kvi_u64_t;
+ #else
+ // attempt to live without a 64bit integer type anyway...
+ // dunno if it will work tough...
+ typedef long long int kvi_i64_t;
+ typedef unsigned long long int kvi_u64_t;
+ #endif
+
+ #if SIZEOF_INT == 4
+ // the most common case
+ typedef int kvi_i32_t;
+ typedef unsigned int kvi_u32_t;
+ #elif SIZEOF_SHORT_INT == 4
+ // 32 bit shorts ?.. a Cray ? :D
+ typedef short int kvi_i32_t;
+ typedef short unsigned int kvi_u32_t;
+ #elif SIZEOF_LONG_INT == 4
+ typedef long int kvi_i32_t;
+ typedef unsigned long int kvi_u32_t;
+ #else
+ #error "Can't find a 32 bit integral type on this system"
+ #error "Please report to pragma at kvirc dot net"
+ #endif
+
+ #if SIZEOF_SHORT_INT == 2
+ // the most common case
+ typedef short int kvi_i16_t;
+ typedef short unsigned int kvi_u16_t;
+ #elif SIZEOF_INT == 2
+ // this isn't going to work anyway, I think..
+ typedef int kvi_i16_t;
+ typedef long int kvi_u16_t;
+ #else
+ #error "Can't find a 16 bit integral type on this system"
+ #error "Please report to pragma at kvirc dot net"
+ #endif
+
+ // assume that char is always 8 bit
+ typedef char kvi_i8_t;
+ typedef unsigned char kvi_u8_t;
+#endif
+
+#endif //_KVI_INTTYPES_H_
diff --git a/src/kvilib/core/kvi_malloc.cpp b/src/kvilib/core/kvi_malloc.cpp
new file mode 100644
index 00000000..9c418ec5
--- /dev/null
+++ b/src/kvilib/core/kvi_malloc.cpp
@@ -0,0 +1,198 @@
+//=============================================================================
+//
+// File : kvi_malloc.cpp
+// Creation date : Sun Jun 18 2000 18:26:27 CEST by Szymon Stefanek
+//
+// This file is part of the KVirc irc client distribution
+// Copyright (C) 1999-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.
+//
+//=============================================================================
+
+//=============================================================================
+// C memory allocation routines
+// This stuff is rather unused, because in normal compilations
+// kvi_malloc , kvi_free and kvi_realloc are macros (see kvi_malloc.h)
+//=============================================================================
+
+#define __KVILIB__
+
+#define _KVI_MALLOC_CPP_
+#include "kvi_malloc.h"
+
+#include <stdio.h>
+
+
+
+#ifdef COMPILE_MEMORY_PROFILE
+
+ //
+ // Memory profile stuff
+ // Used to find memory leaks etc...
+ //
+
+ #include "kvi_pointerlist.h"
+
+ typedef struct _KviMallocEntry {
+ struct _KviMallocEntry * prev;
+ void * pointer;
+ int size;
+ void * return_addr1;
+ void * return_addr2;
+ struct _KviMallocEntry * next;
+ } KviMallocEntry;
+
+ int g_iMaxRequestSize = 0;
+ void * g_pMaxRequestReturnAddress1 = 0;
+ void * g_pMaxRequestReturnAddress2 = 0;
+ unsigned int g_iMallocCalls = 0;
+ unsigned int g_iReallocCalls = 0;
+ unsigned int g_iFreeCalls = 0;
+ unsigned int g_iTotalMemAllocated = 0;
+ unsigned int g_uAllocationPeak = 0;
+ KviMallocEntry * g_pEntries = 0;
+
+ void * kvi_malloc(int size)
+ {
+ g_iMallocCalls ++;
+ g_iTotalMemAllocated += size;
+ if(g_iTotalMemAllocated > g_uAllocationPeak)g_uAllocationPeak = g_iTotalMemAllocated;
+ if(g_iMaxRequestSize < size){
+ g_iMaxRequestSize = size;
+ g_pMaxRequestReturnAddress1 = __builtin_return_address(1);
+ g_pMaxRequestReturnAddress2 = __builtin_return_address(2);
+ }
+ KviMallocEntry * e = (KviMallocEntry *)malloc(sizeof(KviMallocEntry));
+ e->pointer = malloc(size);
+ e->size = size;
+ e->return_addr1 = __builtin_return_address(1);
+ e->return_addr2 = __builtin_return_address(2);
+ e->next = g_pEntries;
+ e->prev = 0;
+ if(g_pEntries)g_pEntries->prev = e;
+ g_pEntries = e;
+ return e->pointer;
+ }
+
+ void * kvi_realloc(void * ptr,int size)
+ {
+ g_iReallocCalls ++;
+ if(ptr == 0)return kvi_malloc(size);
+ if(g_iMaxRequestSize < size){
+ g_iMaxRequestSize = size;
+ g_pMaxRequestReturnAddress1 = __builtin_return_address(1);
+ g_pMaxRequestReturnAddress2 = __builtin_return_address(2);
+ }
+ KviMallocEntry *e = g_pEntries;
+ while(e){
+ if(e->pointer == ptr){
+ g_iTotalMemAllocated -= e->size;
+ g_iTotalMemAllocated += size;
+ if(g_iTotalMemAllocated > g_uAllocationPeak)g_uAllocationPeak = g_iTotalMemAllocated;
+ e->pointer = realloc(ptr,size);
+ e->size = size;
+ e->return_addr1 = __builtin_return_address(1);
+ e->return_addr2 = __builtin_return_address(2);
+ return e->pointer;
+ }
+ e = e->next;
+ }
+ fprintf(stderr,"Attempt to realloc an inexisting pointer (%p) (called from %p (%p))\n",ptr,__builtin_return_address(1),__builtin_return_address(2));
+ return realloc(ptr,size);
+ }
+
+ void kvi_free(void * ptr)
+ {
+ g_iFreeCalls++;
+ if(ptr == 0){
+ fprintf(stderr,"Attempt to free a null pointer (called from %p (%p))\n",__builtin_return_address(1),__builtin_return_address(2));
+ exit(-1);
+ }
+ KviMallocEntry * e= g_pEntries;
+ while(e){
+ if(e->pointer == ptr){
+ g_iTotalMemAllocated -= e->size;
+ if(e->prev){
+ if(e == g_pEntries)fprintf(stderr,"Mem profiling internal error!\n");
+ e->prev->next = e->next;
+ if(e->next)e->next->prev = e->prev;
+ } else {
+ if(e != g_pEntries)fprintf(stderr,"Mem profiling internal error!\n");
+ if(e->next)e->next->prev = 0;
+ g_pEntries = e->next;
+ }
+ free(e);
+ return;
+ }
+ e = e->next;
+ }
+ fprintf(stderr,"Attempt to free an inexisting pointer (%p) (called from %p (%p))\n",ptr,__builtin_return_address(1),__builtin_return_address(2));
+ }
+
+ void kvi_memory_profile() __attribute__((destructor));
+ void kvi_memory_profile()
+ {
+ unsigned int countUnfreed = 0;
+ KviMallocEntry * e = g_pEntries;
+ while(e){
+ countUnfreed++;
+ e = e->next;
+ }
+ fprintf(stderr,"|====|====|====|====|====|====|====|====\n");
+ fprintf(stderr,"| Memory profile for KVIrc\n");
+ fprintf(stderr,"| Unfreed chunks : %d\n",countUnfreed);
+ fprintf(stderr,"| Total unfreed memory : %u bytes\n",g_iTotalMemAllocated);
+ fprintf(stderr,"|====|====|====|====|====|====|====|====\n");
+ fprintf(stderr,"| Possible unfreed chunks dump:\n");
+ e = g_pEntries;
+ while(e){
+ fprintf(stderr,"|====|====|\n");
+ fprintf(stderr,"| Currently unfreed chunk: %p\n",e->pointer);
+ fprintf(stderr,"| Size: %d\n",e->size);
+ fprintf(stderr,"| Caller address 1: %p\n",e->return_addr1);
+ fprintf(stderr,"| Caller address 2: %p\n",e->return_addr2);
+ if(e->size > 10)fprintf(stderr,"| Data: %.10s\n",e->pointer);
+ else if(e->size > 5)fprintf(stderr,"| Data: %.5s\n",e->pointer);
+ KviMallocEntry *toFree = e;
+ e = e->next;
+ free(toFree);
+ }
+ fprintf(stderr,"|====|====|====|====|====|====|====|====\n");
+ fprintf(stderr,"| Allocation peak : %u bytes\n",g_uAllocationPeak);
+ fprintf(stderr,"|====|====|====|====|====|====|====|====\n");
+ fprintf(stderr,"| Max request size : %d bytes\n",g_iMaxRequestSize);
+ fprintf(stderr,"| Called from %p (%p)\n",g_pMaxRequestReturnAddress1,g_pMaxRequestReturnAddress2);
+ fprintf(stderr,"|====|====|====|====|====|====|====|====\n");
+ fprintf(stderr,"| Malloc calls: %u\n",g_iMallocCalls);
+ fprintf(stderr,"| Realloc calls: %u\n",g_iReallocCalls);
+ fprintf(stderr,"| Free calls: %u\n",g_iFreeCalls);
+ fprintf(stderr,"|====|====|====|====|====|====|====|====\n");
+ }
+
+#else
+
+ #ifdef COMPILE_MEMORY_CHECKS
+
+ void outOfMemory()
+ {
+ //What a cool message :)
+ fprintf(stderr,"Virtual memory exhausted in malloc call....bye!\n");
+ exit(-1);
+ }
+
+ #endif
+
+#endif
diff --git a/src/kvilib/core/kvi_malloc.h b/src/kvilib/core/kvi_malloc.h
new file mode 100644
index 00000000..8a7204a5
--- /dev/null
+++ b/src/kvilib/core/kvi_malloc.h
@@ -0,0 +1,88 @@
+#ifndef _KVI_MALLOC_H_
+#define _KVI_MALLOC_H_
+
+//=============================================================================
+//
+// File : kvi_malloc.h
+// Creation date : Sun Jun 18 2000 18:18:36 CEST by Szymon Stefanek
+//
+// This file is part of the KVirc irc client distribution
+// Copyright (C) 1999-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.
+//
+//=============================================================================
+
+//=============================================================================
+// C memory allocation routines: macros in common compilations
+//=============================================================================
+
+#include "kvi_settings.h"
+
+#include <stdlib.h>
+
+#ifdef COMPILE_MEMORY_PROFILE
+
+ #ifdef COMPILE_ON_WINDOWS
+ #error "This stuff should be never compiled on Windows"
+ #endif
+
+ extern void * kvi_malloc(int size);
+ extern void * kvi_realloc(void * ptr,int size);
+ extern void kvi_free(void * ptr);
+
+#else
+
+ #ifndef COMPILE_MEMORY_CHECKS
+
+ // These two are the "common" ones
+ #define kvi_malloc(__size_) malloc(__size_)
+ #define kvi_realloc(__ptr_,__size_) realloc((void *)__ptr_,__size_)
+
+ #else
+
+ #ifdef COMPILE_ON_WINDOWS
+ #error "This stuff should be never compiled on Windows"
+ #endif
+
+ // Want to check all the pointers
+ #define kvi_malloc(__size_) kvi_safe_malloc(__size_)
+ #define kvi_realloc(__ptr_,__size_) kvi_safe_realloc((void *)__ptr_,__size_)
+
+ #ifndef _KVI_MALLOC_CPP_
+ extern void outOfMemory();
+ #endif
+
+ inline void * kvi_safe_malloc(int size)
+ {
+ void * ptr = malloc(size);
+ if(!ptr)outOfMemory();
+ return ptr;
+ }
+
+ inline void * kvi_safe_realloc(void * ptr,int size)
+ {
+ ptr = realloc(ptr,size);
+ if(!ptr)outOfMemory();
+ return ptr;
+ }
+
+ #endif //COMPILE_MEMORY_CHECKS
+
+ #define kvi_free(__ptr_) free((void *)__ptr_)
+
+#endif
+
+#endif //_KVI_MALLOC_H_
diff --git a/src/kvilib/core/kvi_memmove.cpp b/src/kvilib/core/kvi_memmove.cpp
new file mode 100644
index 00000000..1beb920a
--- /dev/null
+++ b/src/kvilib/core/kvi_memmove.cpp
@@ -0,0 +1,253 @@
+//=============================================================================
+//
+// File : kvi_memmove.cpp
+// Creation date : Sun Jun 18 2000 18:27:50 CEST by Szymon Stefanek
+//
+// This file is part of the KVirc irc client distribution
+// Copyright (C) 1999-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.
+//
+//=============================================================================
+
+#define __KVILIB__
+
+#define _KVI_DEBUG_CHECK_RANGE_
+#include "kvi_debug.h"
+
+#define _KVI_MEMMOVE_CPP_
+#include "kvi_memmove.h"
+
+// FIXME: #warning "With system memmove could be guessed by configure"
+
+#ifndef COMPILE_WITH_SYSTEM_MEMMOVE
+
+ #ifdef COMPILE_ix86_ASM
+
+
+ void *kvi_memmove(void * dst_ptr,const void *src_ptr,int len)
+ {
+ __range_valid(dst_ptr);
+ __range_valid(src_ptr);
+ __range_valid(len >= 0);
+ // Save pointer registers
+ asm(" pushl %esi"); // save %esi
+ asm(" pushl %edi"); // save %edi
+ // Load arguments
+ asm(" movl 16(%ebp),%ecx"); // %ecx = len
+ asm(" movl 12(%ebp),%esi"); // %esi = src
+ asm(" movl 8(%ebp),%edi"); // %edi = dst
+ // Compare src and dest
+ asm(" cmpl %esi,%edi"); // %edi - %esi
+ asm(" jbe move_from_bottom_to_top"); // if(%edi < %esi) jump to move_from_bottom_to_top
+ // dst_ptr > src_ptr
+ asm(" addl %ecx,%esi"); // %esi += %ecx (src_ptr += len);
+ asm(" addl %ecx,%edi"); // %edi += %ecx (dst_ptr += len);
+ asm(" decl %esi"); // %esi--; (src_ptr--);
+ asm(" decl %edi"); // %edi--; (dst_ptr--);
+ asm(" std"); // set direction flag (decrement esi and edi in movsb)
+ // Optimization : check for non-odd len (1,3,5,7...)
+ asm(" shr $1,%ecx"); // %ecx >> 1 , shifted bit -> CF
+ asm(" jnc move_two_bytes_top_to_bottom_directly"); // if !carry (CF == 0) skip this move
+ // Move the first byte (non-odd)
+ asm(" movsb %ds:(%esi),%es:(%edi)"); // *dst-- = *src-- if DF else *dst++ = *src++
+ asm("move_two_bytes_top_to_bottom_directly:");
+ asm(" decl %esi"); // %esi--; (src_ptr--);
+ asm(" decl %edi"); // %edi--; (dst_ptr--);
+ asm("move_two_bytes_top_to_bottom:");
+ asm(" shr $1,%ecx"); // %ecx >> 1 , shifted bit -> CF
+ asm(" jnc move_the_rest_top_to_bottom_directly"); // if !carry (CF == 0) skip this move
+ // Move the next two bytes
+ asm(" movsw %ds:(%esi),%es:(%edi)"); // *((word *)dst)-- = *((word)src)-- if DF else *((word *)dst)++ = *((word)src)++
+ asm("move_the_rest_top_to_bottom_directly:");
+ asm(" subl $2,%esi"); // %esi-=2; (src-=2);
+ asm(" subl $2,%edi"); // %edi-=2; (dst-=2);
+ asm(" jmp move_the_rest"); // call last repnz movsl
+ // dst_ptr <= src_ptr
+ asm("move_from_bottom_to_top:");
+ asm(" cld"); // clear direction flag (increment esi and edi in movsb)
+ // Optimization : check for non-odd len (1,3,5,7...)
+ asm(" shr $1,%ecx"); // %ecx >> 1 , shifted bit -> CF
+ asm(" jnc move_two_bytes"); // if !carry (CF == 0) skip this move
+ // Move the first byte (non-odd)
+ asm(" movsb %ds:(%esi),%es:(%edi)"); // *dst-- = *src-- if DF else *dst++ = *src++
+ // Optimization : pass 2 , check for %2 and %3
+ asm("move_two_bytes:");
+ asm(" shr $1,%ecx"); // %ecx >> 1 , shifted bit -> CF
+ asm(" jnc move_the_rest"); // if !carry (CF == 0) skip this move
+ // Move the next two bytes
+ asm(" movsw %ds:(%esi),%es:(%edi)"); // *((word *)dst)-- = *((word)src)-- if DF else *((word *)dst)++ = *((word)src)++
+ // Main move remaining part
+ asm("move_the_rest:");
+ asm(" repnz; movsl %ds:(%esi),%es:(%edi)"); // loop moving 4 bytes at once (increment or decrement as above)
+ // Restore pointer registers
+ asm(" popl %edi"); // restore %edi
+ asm(" popl %esi"); // restore %esi
+ return dst_ptr; //asm(" movl 8(%ebp),%eax"); <-- gcc will put that (AFTER THE OPTIMISATION PASS!)
+ }
+
+ void *kvi_memmoveodd(void * dst_ptr,const void *src_ptr,int len)
+ {
+ __range_valid(dst_ptr);
+ __range_valid(src_ptr);
+ __range_valid(len >= 0);
+ // Save pointer registers
+ asm(" pushl %esi"); // save %esi
+ asm(" pushl %edi"); // save %edi
+ // Load arguments
+ asm(" movl 16(%ebp),%ecx"); // %ecx = len
+ asm(" movl 12(%ebp),%esi"); // %esi = src
+ asm(" movl 8(%ebp),%edi"); // %edi = dst
+ // Compare src and dest
+ asm(" cmpl %esi,%edi"); // %edi - %esi
+ asm(" jbe xmove_from_bottom_to_top"); // if(%edi < %esi) jump to move_from_bottom_to_top
+ // dst_ptr > src_ptr
+ asm(" addl %ecx,%esi"); // %esi += %ecx (src_ptr += len);
+ asm(" addl %ecx,%edi"); // %edi += %ecx (dst_ptr += len);
+ asm(" std"); // set direction flag (decrement esi and edi in movsb)
+ // start moving
+ asm(" shr $2,%ecx"); // %ecx >> 2 , last shifted bit -> CF
+ asm(" jnc xmove_the_rest_top_to_bottom_directly"); // if !carry (CF == 0) skip this move
+ // Move the next two bytes
+ asm(" subl $2,%esi"); // %esi-=2; (src_ptr-=2);
+ asm(" subl $2,%edi"); // %edi-=2; (dst_ptr-=2);
+ asm(" movsw %ds:(%esi),%es:(%edi)"); // *((word *)dst)-- = *((word)src)-- if DF else *((word *)dst)++ = *((word)src)++
+ asm(" subl $2,%esi"); // %esi-=2; (src_ptr-=2);
+ asm(" subl $2,%edi"); // %edi-=2; (dst_ptr-=2);
+ asm(" jmp xmove_the_rest");
+ asm("xmove_the_rest_top_to_bottom_directly:");
+ asm(" subl $4,%esi"); // %esi-=4; (src-=4);
+ asm(" subl $4,%edi"); // %edi-=4; (dst-=4);
+ asm(" jmp xmove_the_rest"); // call last repnz movsl
+ // dst_ptr <= src_ptr
+ asm("xmove_from_bottom_to_top:");
+ asm(" cld"); // clear direction flag (increment esi and edi in movsb)
+ // move it
+ asm(" shr $2,%ecx"); // %ecx >> 2 , last shifted bit -> CF
+ asm(" jnc xmove_the_rest"); // if !carry (CF == 0) skip this move
+ // Move the next two bytes
+ asm(" movsw %ds:(%esi),%es:(%edi)"); // *((word *)dst)-- = *((word)src)-- if DF else *((word *)dst)++ = *((word)src)++
+ // Main move remaining part
+ asm("xmove_the_rest:");
+ asm(" repnz; movsl %ds:(%esi),%es:(%edi)"); // loop moving 4 bytes at once (increment or decrement as above)
+ // Restore pointer registers
+ asm(" popl %edi"); // restore %edi
+ asm(" popl %esi"); // restore %esi
+ return dst_ptr; //asm(" movl 8(%ebp),%eax"); <-- gcc will put that (AFTER THE OPTIMISATION PASS!)
+ }
+
+ #else // ndef COMPILE_ix86_ASM
+
+
+
+ // The next 4 functions could be optimized with the & and shift technique
+ // used in the assembly implementations but the compilers usually
+ // will not translate the carry bit trick producing code
+ // that works slower on short block of memory (really near the average case)
+
+ // The trick would be:
+ //
+ // if(len & 1) // the length is even
+ // *dst-- = *src--; // move one byte
+ // len >> 1; // drop the last bit (thus divide by 2)
+ // if(len & 1) // the length is still even
+ // *((short *)dst)-- = *((short *)src)--; // move two bytes
+ // len >> 1; // again drop the last bit (thus divide by 2)
+ // while(len--)*((int *)dst)-- = *((int *)src)--; // move four bytes at a time
+ //
+ //
+
+ void *kvi_memmove(void *dst_ptr,const void *src_ptr,int len)
+ {
+ __range_valid(dst_ptr);
+ __range_valid(src_ptr);
+ __range_valid(len >= 0);
+ register char *dst;
+ register const char *src;
+ if(dst_ptr > src_ptr){
+ dst = (char *)dst_ptr + len - 1;
+ src = (const char *)src_ptr + len - 1;
+ while(len--)*dst-- = *src--;
+ } else { //it is valid even if dst_ptr == src_ptr
+ dst = (char *)dst_ptr;
+ src = (const char *)src_ptr;
+ while(len--)*dst++ = *src++;
+ }
+ return dst_ptr;
+ }
+
+ void *kvi_memmoveodd(void *dst_ptr,const void *src_ptr,int len)
+ {
+ __range_valid(dst_ptr);
+ __range_valid(src_ptr);
+ __range_valid(len >= 0);
+ __range_valid((len & 1) == 0);
+ register short *dst;
+ register const short *src;
+ if(dst_ptr > src_ptr){
+ dst = (short *) (((char *)dst_ptr) + len - 2);
+ src = (const short *) (((const char *)src_ptr) + len - 2);
+ while(len > 0)
+ {
+ *dst-- = *src--;
+ len -= 2;
+ }
+ } else { //it is valid even if dst_ptr == src_ptr
+ dst = (short *)dst_ptr;
+ src = (const short *)src_ptr;
+ while(len > 0)
+ {
+ *dst++ = *src++;
+ len -= 2;
+ }
+ }
+ return dst_ptr;
+ }
+
+ void kvi_fastmove(void *dst_ptr,const void *src_ptr,int len)
+ {
+ __range_valid(dst_ptr);
+ __range_valid(src_ptr);
+ __range_valid(len >= 0);
+ register const char *src = (const char *)src_ptr;
+ register char *dst = (char *)dst_ptr;
+ while(len--)*dst++ = *src++;
+ }
+
+ void kvi_fastmoveodd(void *dst_ptr,const void *src_ptr,int len)
+ {
+ __range_valid(dst_ptr);
+ __range_valid(src_ptr);
+ __range_valid(len >= 0);
+ __range_valid((len & 1) == 0);
+ register const short *src = (const short *)src_ptr;
+ register short *dst = (short *)dst_ptr;
+ while(len > 0){
+ *dst++ = *src++;
+ len -= 2;
+ }
+ }
+
+ #endif // !COMPILE_ix86_ASM
+
+ void kvi_memset(void *dst_ptr,char c,int len)
+ {
+ __range_valid(dst_ptr);
+ __range_valid(len >= 0);
+ register char *dst = (char *)dst_ptr;
+ while(len--)*dst++ = c;
+ }
+
+#endif // !COMPILE_WITH_SYSTEM_MEMMOVE
diff --git a/src/kvilib/core/kvi_memmove.h b/src/kvilib/core/kvi_memmove.h
new file mode 100644
index 00000000..d1319a41
--- /dev/null
+++ b/src/kvilib/core/kvi_memmove.h
@@ -0,0 +1,105 @@
+#ifndef _KVI_MEMMOVE_H_
+#define _KVI_MEMMOVE_H_
+
+//=============================================================================
+//
+// File : kvi_memmove.h
+// Creation date : Fri Mar 19 1999 03:15:21 CEST by Szymon Stefanek
+//
+// This file is part of the KVirc irc client distribution
+// Copyright (C) 1999-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.
+//
+//=============================================================================
+
+#define __KVILIB__
+
+#include "kvi_settings.h"
+
+//#undef COMPILE_WITH_SYSTEM_MEMMOVE
+//#define COMPILE_MMX_ASM
+
+#ifndef _KVI_MEMMOVE_CPP_
+
+ #ifdef COMPILE_WITH_SYSTEM_MEMMOVE
+
+ #include <string.h>
+
+ #define kvi_memmove memmove
+ #define kvi_memmoveodd memmove
+ #define kvi_memset memset
+ #define kvi_fastmove memcpy
+ #define kvi_fastmoveodd memcpy
+
+ #else
+
+ #ifdef COMPILE_ON_WINDOWS
+ #error "This stuff should be never compiled on Windows"
+ #endif
+
+ extern void *kvi_memmove(void *dst_ptr,const void *src_ptr,int len);
+ extern void *kvi_memmoveodd(void *dst_ptr,const void *src_ptr,int len);
+ extern void *kvi_memset(void *dst_ptr,char c,int len);
+ // In fastmove the src and dst may not overlap
+
+ #ifdef COMPILE_ix86_ASM
+
+ // WE WANT repnz; movsq\n"!!!
+
+ inline void kvi_fastmove(void * dst_ptr,const void *src_ptr,int len)
+ {
+ __asm__ __volatile__(
+ " cld\n"
+ " shr $1,%0\n"
+ " jnc 1f\n"
+ " movsb\n"
+ "1:\n"
+ " shr $1,%0\n"
+ " jnc 2f\n"
+ " movsw\n"
+ "2:\n"
+ " repnz; movsl\n"
+ : "=c" (len), "=&S" (src_ptr), "=&D" (dst_ptr)
+ : "0" (len), "1" (src_ptr), "2" (dst_ptr)
+ );
+ }
+
+ inline void kvi_fastmoveodd(void * dst_ptr,const void *src_ptr,int len)
+ {
+ __asm__ __volatile__(
+ " cld\n"
+ " shr $2,%0\n"
+ " jnc 1f\n"
+ " movsw\n"
+ "1:\n"
+ " repnz; movsl\n"
+ : "=c" (len), "=&S" (src_ptr), "=&D" (dst_ptr)
+ : "0" (len), "1" (src_ptr), "2" (dst_ptr)
+ );
+ }
+
+ #else // ! COMPILE_ix86_ASM
+
+ extern void kvi_fastmove(void *dst_ptr,const void *src_ptr,int len);
+ extern void kvi_fastmoveodd(void *dst_ptr,const void *src_ptr,int len);
+
+ #endif // !COMPILE_ix86_ASM
+
+ #endif // COMPILE_WITH_SYSTEM_MEMMOVE
+
+#endif // _KVI_MEMMOVE_CPP_
+
+#endif // !_KVI_MEMMOVE_H_
diff --git a/src/kvilib/core/kvi_pointerhashtable.h b/src/kvilib/core/kvi_pointerhashtable.h
new file mode 100644
index 00000000..9066c091
--- /dev/null
+++ b/src/kvilib/core/kvi_pointerhashtable.h
@@ -0,0 +1,999 @@
+#ifndef _KVI_POINTERHASHTABLE_H_
+#define _KVI_POINTERHASHTABLE_H_
+//=================================================================================================
+//
+// File : kvi_pointerhashtable.h
+// Creation date : Sat Jan 12 2008 04:53 by Szymon Stefanek
+//
+// This file is part of the KVirc irc client distribution
+// Copyright (C) 2008 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_pointerlist.h"
+#include "kvi_string.h"
+#include "kvi_qstring.h"
+#include "kvi_malloc.h"
+#include "kvi_memmove.h"
+
+#include <ctype.h>
+
+///
+/// Hash functions for various data types
+///
+
+inline unsigned int kvi_hash_hash(const char * szKey,bool bCaseSensitive)
+{
+ unsigned int uResult = 0;
+ if(bCaseSensitive)
+ {
+ while(*szKey)
+ {
+ uResult += (unsigned char)(*(szKey));
+ szKey++;
+ }
+ } else {
+ while(*szKey)
+ {
+ uResult += (unsigned char)tolower(*(szKey));
+ szKey++;
+ }
+ }
+ return uResult;
+}
+
+inline bool kvi_hash_key_equal(const char * szKey1,const char * szKey2,bool bCaseSensitive)
+{
+ if(bCaseSensitive)
+ {
+ while(*szKey1 && *szKey2)
+ {
+ if(*szKey1 != *szKey2)
+ return false;
+ szKey1++;
+ szKey2++;
+ }
+ } else {
+ while(*szKey1 && *szKey2)
+ {
+ if(tolower(*szKey1) != tolower(*szKey2))
+ return false;
+ szKey1++;
+ szKey2++;
+ }
+ }
+ return true;
+}
+
+inline void kvi_hash_key_copy(const char * const &szFrom,const char * &szTo,bool bDeepCopy)
+{
+ if(bDeepCopy)
+ {
+ int len = kvi_strLen(szFrom);
+ char * dst = (char *)kvi_malloc(len+1);
+ kvi_fastmove(dst,szFrom,len+1);
+ szTo = dst;
+ } else {
+ szTo = szFrom; // we never modify it anyway
+ }
+}
+
+inline void kvi_hash_key_destroy(const char * &szKey,bool bDeepCopy)
+{
+ if(bDeepCopy)
+ kvi_free(szKey);
+}
+
+inline const char * & kvi_hash_key_default(const char **)
+{
+ static const char * static_null = NULL;
+ return static_null;
+}
+
+inline unsigned int kvi_hash_hash(const KviStr &szKey,bool bCaseSensitive)
+{
+ unsigned int uResult = 0;
+ const char * p = szKey.ptr();
+ if(bCaseSensitive)
+ {
+ while(*p)
+ {
+ uResult += *((const unsigned char *)p);
+ p++;
+ }
+ } else {
+ while(*p)
+ {
+ uResult += tolower(*((const unsigned char *)p));
+ p++;
+ }
+ }
+ return uResult;
+}
+
+inline bool kvi_hash_key_equal(const KviStr &szKey1,const KviStr &szKey2)
+{
+ return kvi_hash_key_equal(szKey1.ptr(),szKey2.ptr());
+}
+
+inline void kvi_hash_key_copy(const KviStr &szFrom,KviStr &szTo,bool)
+{
+ szTo = szFrom;
+}
+
+inline void kvi_hash_key_destroy(KviStr &szKey,bool)
+{
+}
+
+inline const KviStr & kvi_hash_key_default(KviStr *)
+{
+ return KviStr::emptyString();
+}
+
+inline unsigned int kvi_hash_hash(const int &iKey,bool)
+{
+ return (unsigned int)iKey;
+}
+
+inline bool kvi_hash_key_equal(const int &iKey1,const int &iKey2,bool)
+{
+ return iKey1 == iKey2;
+}
+
+inline void kvi_hash_key_copy(const int &iKeyFrom,int &iKeyTo,bool)
+{
+ iKeyTo = iKeyFrom;
+}
+
+inline void kvi_hash_key_destroy(int &iKey,bool)
+{
+}
+
+inline const int & kvi_hash_key_default(int *)
+{
+ static int static_default = 0;
+ return static_default;
+}
+
+inline unsigned int kvi_hash_hash(const unsigned short &iKey,bool)
+{
+ return (unsigned int)iKey;
+}
+
+inline bool kvi_hash_key_equal(const unsigned short &iKey1,const unsigned short &iKey2,bool)
+{
+ return iKey1 == iKey2;
+}
+
+inline void kvi_hash_key_copy(const unsigned short &iKeyFrom,unsigned short &iKeyTo,bool)
+{
+ iKeyTo = iKeyFrom;
+}
+
+inline void kvi_hash_key_destroy(unsigned short &iKey,bool)
+{
+}
+
+inline const unsigned short & kvi_hash_key_default(unsigned short *)
+{
+ static unsigned short static_default = 0;
+ return static_default;
+}
+
+
+inline unsigned int kvi_hash_hash(void * pKey,bool)
+{
+ unsigned char * pBytes = (unsigned char *)&(pKey);
+ unsigned char * pEnd = pBytes + sizeof(void *);
+ unsigned int uSum = 0;
+ while(pBytes < pEnd)
+ {
+ uSum += *pBytes;
+ pBytes++;
+ }
+ return uSum;
+}
+
+inline bool kvi_hash_key_equal(void *pKey1,void *pKey2,bool)
+{
+ return pKey1 == pKey2;
+}
+
+inline void kvi_hash_key_copy(void * const &pKeyFrom,void *&pKeyTo,bool)
+{
+ pKeyTo = pKeyFrom;
+}
+
+inline void kvi_hash_key_destroy(void *iKey,bool)
+{
+}
+
+inline void * & kvi_hash_key_default(void *)
+{
+ static void * static_default = NULL;
+ return static_default;
+}
+
+inline unsigned int kvi_hash_hash(const QString &szKey,bool bCaseSensitive)
+{
+ unsigned int uResult = 0;
+ const QChar * p = KviQString::nullTerminatedArray(szKey);
+ if(!p)return 0;
+ if(bCaseSensitive)
+ {
+ while(p->unicode())
+ {
+ uResult += p->unicode();
+ p++;
+ }
+ } else {
+ while(p->unicode())
+ {
+#ifdef COMPILE_USE_QT4
+ uResult += p->toLower().unicode();
+#else
+ uResult += p->lower().unicode();
+#endif
+ p++;
+ }
+ }
+ return uResult;
+}
+
+inline bool kvi_hash_key_equal(const QString &szKey1,const QString &szKey2,bool bCaseSensitive)
+{
+ if(bCaseSensitive)
+ return KviQString::equalCS(szKey1,szKey2);
+ return KviQString::equalCI(szKey1,szKey2);
+}
+
+inline void kvi_hash_key_copy(const QString &szFrom,QString &szTo,bool)
+{
+ szTo = szFrom;
+}
+
+inline void kvi_hash_key_destroy(QString &szKey,bool)
+{
+}
+
+inline const QString & kvi_hash_key_default(QString *)
+{
+ return KviQString::empty;
+}
+
+template<typename Key,typename T> class KviPointerHashTable;
+template<typename Key,typename T> class KviPointerHashTableIterator;
+
+template<typename Key,typename T> class KviPointerHashTableEntry
+{
+ friend class KviPointerHashTable<Key,T>;
+protected:
+ T * pData;
+ Key hKey;
+public:
+ Key & key(){ return hKey; };
+ T * data(){ return pData; };
+};
+
+///
+///
+/// \class KviPointerHashTable
+/// \brief A fast pointer hash table implementation
+///
+/// A very cool, very fast hash table implementation :P
+///
+/// To use this hash table you need to provide implementations
+/// for the following functions:
+///
+/// \verbatim
+///
+/// unsigned int kvi_hash_hash(const Key &hKey,bool bCaseSensitive);
+/// bool kvi_hash_key_equal(const Key &hKey1,const Key &hKey2,bool bCaseSensitive);
+/// void kvi_hash_key_copy(const Key &hKeyFrom,Key &hKeyTo,bool bDeepCopy);
+/// void kvi_hash_key_destroy(Key &hKey,bool bIsDeepCopy);
+/// const Key & kvi_hash_key_default(Key *);
+///
+/// \endverbatim
+///
+/// Implementations for the most likey Key data types are provided below.
+/// KviPointerHashTable will automagically work with const char *,QString,KviStr
+/// and integer types as keys.
+///
+/// For string Key types, the hash table may or may not be case sensitive.
+/// For other Key types the case sensitive flag has no meaning and will
+/// (hopefully) be optimized out by the compiler.
+///
+/// For pointer based keys the hash table may or may not mantain deep copies
+/// of Key data. For example, with char * keys, if deep copying is enabled
+/// then a private copy of the string data will be mantained. With deep
+/// copying disabled only char * pointers will be kept. For types
+/// that do not have meaning of deep copy the deep copying code will
+/// (hopefully) be optimized out by the compiler.
+///
+/// The hashtable mantains an array of KviPointerList based buckets.
+/// The number of buckets may be specified by the application user
+/// and does NOT need to be a prime number. Yet better to have it a power
+/// of two so the memory allocation routines will feel better and are
+/// less likely to waste space.
+///
+template<class Key,class T> class KviPointerHashTable
+{
+ friend class KviPointerHashTableIterator<Key,T>;
+protected:
+ KviPointerList<KviPointerHashTableEntry<Key,T> > ** m_pDataArray;
+ bool m_bAutoDelete;
+ unsigned int m_uSize;
+ unsigned int m_uCount;
+ bool m_bCaseSensitive;
+ bool m_bDeepCopyKeys;
+ unsigned int m_uIteratorIdx;
+public:
+ ///
+ /// Returns the item associated to the key hKey
+ /// or NULL if no such item exists in the hash table.
+ /// Places the hash table iterator at the position
+ /// of the item found.
+ ///
+ T * find(const Key & hKey)
+ {
+ m_uIteratorIdx = kvi_hash_hash(hKey,m_bCaseSensitive) % m_uSize;
+ if(!m_pDataArray[m_uIteratorIdx])return 0;
+ for(KviPointerHashTableEntry<Key,T> * e = m_pDataArray[m_uIteratorIdx]->first();e;e = m_pDataArray[m_uIteratorIdx]->next())
+ {
+ if(kvi_hash_key_equal(e->hKey,hKey,m_bCaseSensitive))return (T *)e->pData;
+ }
+ return 0;
+ }
+
+ ///
+ /// Returns the item associated to the key hKey
+ /// or NULL if no such item exists in the hash table.
+ /// Places the hash table iterator at the position
+ /// of the item found. This is an alias to find().
+ ///
+ T * operator[](const Key & hKey)
+ {
+ return find(hKey);
+ }
+
+ ///
+ /// Returns the number of items in this hash table
+ ///
+ unsigned int count() const
+ {
+ return m_uCount;
+ }
+
+ ///
+ /// Returns true if the hash table is empty
+ ///
+ bool isEmpty() const
+ {
+ return m_uCount == 0;
+ }
+
+ ///
+ /// Inserts the item pData at the position specified by the key hKey.
+ /// Replaces any previous item with the same key
+ /// The replaced item is deleted if autodelete is enabled.
+ /// The hash table iterator is placed at the newly inserted item.
+ ///
+ void insert(const Key & hKey,T * pData)
+ {
+ if(!pData)return;
+ unsigned int uEntry = kvi_hash_hash(hKey,m_bCaseSensitive) % m_uSize;
+ if(!m_pDataArray[uEntry])m_pDataArray[uEntry] = new KviPointerList<KviPointerHashTableEntry<Key,T> >(true);
+ for(KviPointerHashTableEntry<Key,T> * e = m_pDataArray[uEntry]->first();e;e = m_pDataArray[uEntry]->next())
+ {
+ if(kvi_hash_key_equal(e->hKey,hKey,m_bCaseSensitive))
+ {
+ if(!m_bCaseSensitive)
+ {
+ // must change the key too
+ kvi_hash_key_destroy(e->hKey,m_bDeepCopyKeys);
+ kvi_hash_key_copy(hKey,e->hKey,m_bDeepCopyKeys);
+ }
+ if(m_bAutoDelete)delete e->pData;
+ e->pData = pData;
+ return;
+ }
+ }
+ KviPointerHashTableEntry<Key,T> * n = new KviPointerHashTableEntry<Key,T>;
+ kvi_hash_key_copy(hKey,n->hKey,m_bDeepCopyKeys);
+ n->pData = pData;
+ m_pDataArray[uEntry]->append(n);
+ m_uCount++;
+ }
+
+ ///
+ /// Inserts the item pData at the position specified by the key hKey.
+ /// Replaces any previous item with the same key
+ /// The replaced item is deleted if autodelete is enabled.
+ /// The hash table iterator is placed at the newly inserted item.
+ /// This is just an alias to insert() with a different name.
+ ///
+ void replace(const Key & hKey,T * pData)
+ {
+ insert(hKey,pData);
+ }
+
+ ///
+ /// Removes the item pointer associated to the key hKey, if such an item
+ /// exists in the hash table. The item is deleted if autodeletion
+ /// is enabled. Returns true if the item was found and removed and false if it wasn't found.
+ /// Invalidates the hash table iterator.
+ ///
+ bool remove(const Key & hKey)
+ {
+ unsigned int uEntry = kvi_hash_hash(hKey,m_bCaseSensitive) % m_uSize;
+ if(!m_pDataArray[uEntry])return false;
+ for(KviPointerHashTableEntry<Key,T> * e = m_pDataArray[uEntry]->first();e;e = m_pDataArray[uEntry]->next())
+ {
+ if(kvi_hash_key_equal(e->hKey,hKey,m_bCaseSensitive))
+ {
+ kvi_hash_key_destroy(e->hKey,m_bDeepCopyKeys);
+ if(m_bAutoDelete)delete ((T *)(e->pData));
+ m_pDataArray[uEntry]->removeRef(e);
+ if(m_pDataArray[uEntry]->isEmpty())
+ {
+ delete m_pDataArray[uEntry];
+ m_pDataArray[uEntry] = 0;
+ }
+ m_uCount--;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ ///
+ /// Removes the first occurence of the item pointer pRef. The item is deleted if autodeletion
+ /// is enabled. Returns true if the pointer was found and false otherwise
+ /// Invalidates the hash table iterator.
+ ///
+ bool removeRef(const T * pRef)
+ {
+ for(unsigned int i=0;i<m_uSize;i++)
+ {
+ if(m_pDataArray[i])
+ {
+ for(KviPointerHashTableEntry<Key,T> * e = m_pDataArray[i]->first();e;e = m_pDataArray[i]->next())
+ {
+ if(e->pData == pRef)
+ {
+ kvi_hash_key_destroy(e->hKey,m_bDeepCopyKeys);
+ if(m_bAutoDelete)delete ((T *)(e->pData));
+ m_pDataArray[i]->removeRef(e);
+ if(m_pDataArray[i]->isEmpty())
+ {
+ delete m_pDataArray[i];
+ m_pDataArray[i] = 0;
+ }
+ m_uCount--;
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ ///
+ /// Removes all the items from the hash table.
+ /// The items are deleted if autodeletion is enabled.
+ /// Invalidates the hash table iterator.
+ ///
+ void clear()
+ {
+ for(unsigned int i=0;i<m_uSize;i++)
+ {
+ if(m_pDataArray[i])
+ {
+ for(KviPointerHashTableEntry<Key,T> * e = m_pDataArray[i]->first();e;e = m_pDataArray[i]->next())
+ {
+ kvi_hash_key_destroy(e->hKey,m_bDeepCopyKeys);
+ if(m_bAutoDelete)
+ delete ((T *)(e->pData));
+ }
+ delete m_pDataArray[i];
+ m_pDataArray[i] = 0;
+ }
+ }
+ m_uCount = 0;
+ }
+
+ ///
+ /// Searches for the item pointer pRef and returns
+ /// it's hash table entry, if found, and NULL otherwise.
+ /// The hash table iterator is placed at the item found.
+ ///
+ KviPointerHashTableEntry<Key,T> * findRef(const T * pRef)
+ {
+ for(m_uIteratorIdx = 0;m_uIteratorIdx<m_uSize;m_uIteratorIdx++)
+ {
+ if(m_pDataArray[m_uIteratorIdx])
+ {
+ for(KviPointerHashTableEntry<Key,T> * e = m_pDataArray[m_uIteratorIdx]->first();e;e = m_pDataArray[m_uIteratorIdx]->next())
+ {
+ if(e->pData == pRef)return e;
+ }
+ }
+ }
+ return 0;
+ }
+
+ ///
+ /// Returns the entry pointed by the hash table iterator.
+ /// This function must be preceeded by a call to firstEntry(), first()
+ /// or findRef().
+ ///
+ KviPointerHashTableEntry<Key,T> * currentEntry()
+ {
+ if(m_uIteratorIdx >= m_uSize)return 0;
+ if(m_pDataArray[m_uIteratorIdx])return m_pDataArray[m_uIteratorIdx]->current();
+ return 0;
+ }
+
+ ///
+ /// Places the hash table iterator at the first entry
+ /// and returns it.
+ ///
+ KviPointerHashTableEntry<Key,T> * firstEntry()
+ {
+ m_uIteratorIdx = 0;
+ while(m_uIteratorIdx < m_uSize && (!m_pDataArray[m_uIteratorIdx]))
+ {
+ m_uIteratorIdx++;
+ }
+ if(m_uIteratorIdx == m_uSize)return 0;
+ return m_pDataArray[m_uIteratorIdx]->first();
+ }
+
+ ///
+ /// Places the hash table iterator at the next entry
+ /// and returns it.
+ /// This function must be preceeded by a call to firstEntry(), first()
+ /// or findRef().
+ ///
+ KviPointerHashTableEntry<Key,T> * nextEntry()
+ {
+ if(m_uIteratorIdx >= m_uSize)return 0;
+
+ if(m_uIteratorIdx < m_uSize)
+ {
+ KviPointerHashTableEntry<Key,T> * t = m_pDataArray[m_uIteratorIdx]->next();
+ if(t)return t;
+ }
+
+ m_uIteratorIdx++;
+
+ while(m_uIteratorIdx < m_uSize && (!m_pDataArray[m_uIteratorIdx]))
+ {
+ m_uIteratorIdx++;
+ }
+
+ if(m_uIteratorIdx == m_uSize)return 0;
+
+ return m_pDataArray[m_uIteratorIdx]->first();
+
+ }
+
+ ///
+ /// Returns the data value pointer pointed by the hash table iterator.
+ /// This function must be preceeded by a call to firstEntry(), first()
+ /// or findRef().
+ ///
+ T * current()
+ {
+ if(m_uIteratorIdx >= m_uSize)return 0;
+ if(m_pDataArray[m_uIteratorIdx])
+ {
+ KviPointerHashTableEntry<Key,T> * e = m_pDataArray[m_uIteratorIdx]->current();
+ if(!e)return 0;
+ return e->data();
+ }
+ return 0;
+ }
+
+ ///
+ /// Returns the key pointed by the hash table iterator.
+ /// This function must be preceeded by a call to firstEntry(), first()
+ /// or findRef().
+ ///
+ const Key & currentKey()
+ {
+ if(m_uIteratorIdx >= m_uSize)return kvi_hash_key_default(((Key *)NULL));
+ if(m_pDataArray[m_uIteratorIdx])
+ {
+ KviPointerHashTableEntry<Key,T> * e = m_pDataArray[m_uIteratorIdx]->current();
+ if(!e)return kvi_hash_key_default(((Key *)NULL));
+ return e->key();
+ }
+ return kvi_hash_key_default(((Key *)NULL));
+ }
+
+ ///
+ /// Places the hash table iterator at the first entry
+ /// and returns the associated data value pointer.
+ ///
+ T * first()
+ {
+ m_uIteratorIdx = 0;
+ while(m_uIteratorIdx < m_uSize && (!m_pDataArray[m_uIteratorIdx]))
+ {
+ m_uIteratorIdx++;
+ }
+ if(m_uIteratorIdx == m_uSize)return 0;
+ KviPointerHashTableEntry<Key,T> * e = m_pDataArray[m_uIteratorIdx]->first();
+ if(!e)return 0;
+ return e->data();
+ }
+
+ ///
+ /// Places the hash table iterator at the next entry
+ /// and returns the associated data value pointer.
+ /// This function must be preceeded by a call to firstEntry(), first()
+ /// or findRef().
+ ///
+ T * next()
+ {
+ if(m_uIteratorIdx >= m_uSize)return 0;
+
+ if(m_uIteratorIdx < m_uSize)
+ {
+ KviPointerHashTableEntry<Key,T> * t = m_pDataArray[m_uIteratorIdx]->next();
+ if(t)
+ {
+ return t->data();
+ }
+ }
+
+ m_uIteratorIdx++;
+
+ while(m_uIteratorIdx < m_uSize && (!m_pDataArray[m_uIteratorIdx]))
+ {
+ m_uIteratorIdx++;
+ }
+
+ if(m_uIteratorIdx == m_uSize)return 0;
+
+ KviPointerHashTableEntry<Key,T> * e = m_pDataArray[m_uIteratorIdx]->first();
+ if(!e)return 0;
+ return e->data();
+ }
+
+ ///
+ /// Removes all items in the hash table and then
+ /// makes a complete shallow copy of the data contained in t.
+ /// The removed items are deleted if autodeletion is enabled.
+ /// The hash table iterator is invalidated.
+ /// Does not change autodelete flag: make sure you not delete the items twice :)
+ ///
+ void copyFrom(KviPointerHashTable<Key,T> &t)
+ {
+ clear();
+ for(KviPointerHashTableEntry<Key,T> * e = t.firstEntry();e;e = t.nextEntry())
+ insert(e->key(),e->data());
+ }
+
+ ///
+ /// Inserts a complete shallow copy of the data contained in t.
+ /// The hash table iterator is invalidated.
+ ///
+ void insert(KviPointerHashTable<Key,T> &t)
+ {
+ for(KviPointerHashTableEntry<Key,T> * e = t.firstEntry();e;e = t.nextEntry())
+ insert(e->key(),e->data());
+ }
+
+ ///
+ /// Enables or disabled the autodeletion feature.
+ /// Items are deleted upon removal when the feature is enabled.
+ ///
+ void setAutoDelete(bool bAutoDelete)
+ {
+ m_bAutoDelete = bAutoDelete;
+ }
+
+ ///
+ /// Creates an empty hash table.
+ /// Automatic deletion is enabled.
+ ///
+ /// \param uSize The number of hash buckets: does NOT necesairly need to be prime
+ /// \param bCaseSensitive Are the key comparisons case sensitive ?
+ /// \param Do we need to mantain deep copies of keys ?
+ ///
+ KviPointerHashTable(unsigned int uSize = 32,bool bCaseSensitive = true,bool bDeepCopyKeys = true)
+ {
+ m_uCount = 0;
+ m_bCaseSensitive = bCaseSensitive;
+ m_bAutoDelete = true;
+ m_bDeepCopyKeys = bDeepCopyKeys;
+ m_uSize = uSize > 0 ? uSize : 32;
+ m_pDataArray = new KviPointerList<KviPointerHashTableEntry<Key,T> > *[m_uSize];
+ for(unsigned int i=0;i<m_uSize;i++)m_pDataArray[i] = NULL;
+ }
+
+ ///
+ /// First creates an empty hash table
+ /// and then inserts a copy of all the item pointers present in t.
+ /// The autodelete feature is automatically disabled (take care!).
+ ///
+ KviPointerHashTable(KviPointerHashTable<Key,T> &t)
+ {
+ m_uCount = 0;
+ m_bAutoDelete = false;
+ m_bCaseSensitive = t.m_bCaseSensitive;
+ m_bDeepCopyKeys = t.m_bDeepCopyKeys;
+ m_uSize = t.m_uSize;
+ m_pDataArray = new KviPointerList<KviPointerHashTableEntry<Key,T> > *[m_uSize];
+ for(unsigned int i=0;i<m_uSize;i++)m_pDataArray[i] = NULL;
+ copyFrom(t);
+ }
+
+ ///
+ /// Destroys the hash table and all the items contained within.
+ /// Items are deleted if autodeletion is enabled.
+ ///
+ ~KviPointerHashTable()
+ {
+ clear();
+ delete [] m_pDataArray;
+ }
+};
+
+template<typename Key,typename T> class KviPointerHashTableIterator
+{
+protected:
+ const KviPointerHashTable<Key,T> * m_pHashTable;
+ unsigned int m_uEntryIndex;
+ KviPointerListIterator<KviPointerHashTableEntry<Key,T> > * m_pIterator;
+public:
+ ///
+ /// Creates an iterator copy.
+ /// The new iterator points exactly to the item pointed by src.
+ ///
+ void operator = (const KviPointerHashTableIterator<Key,T> &src)
+ {
+ m_pHashTable = src.m_pHashTable;
+ m_uEntryIndex = src.m_uEntryIndex;
+ if(src.m_pIterator)
+ m_pIterator = new KviPointerListIterator<KviPointerHashTableEntry<Key,T> >(*(src.m_pIterator));
+ else
+ m_pIterator = NULL;
+ }
+
+ ///
+ /// Moves the iterator to the first element of the hash table.
+ /// Returns true in case of success or false if the hash table is empty.
+ ///
+ bool moveFirst()
+ {
+ if(m_pIterator)
+ {
+ delete m_pIterator;
+ m_pIterator = NULL;
+ }
+
+ m_uEntryIndex = 0;
+ while((m_uEntryIndex < m_pHashTable->m_uSize) && (!(m_pHashTable->m_pDataArray[m_uEntryIndex])))
+ {
+ m_uEntryIndex++;
+ }
+
+ if(m_uEntryIndex == m_pHashTable->m_uSize)
+ return false;
+
+ m_pIterator = new KviPointerListIterator<KviPointerHashTableEntry<Key,T> >(*(m_pHashTable->m_pDataArray[m_uEntryIndex]));
+ bool bRet = m_pIterator->moveFirst();
+ if(!bRet)
+ {
+ delete m_pIterator;
+ m_pIterator = NULL;
+ }
+ return bRet;
+ }
+
+ ///
+ /// Moves the iterator to the last element of the hash table.
+ /// Returns true in case of success or false if the hash table is empty.
+ ///
+ bool moveLast()
+ {
+ if(m_pIterator)
+ {
+ delete m_pIterator;
+ m_pIterator = NULL;
+ }
+
+ m_uEntryIndex = m_pHashTable->m_uSize;
+ while(m_uEntryIndex > 0)
+ {
+ m_uEntryIndex--;
+ if(m_pHashTable->m_pDataArray[m_uEntryIndex])
+ {
+ m_pIterator = new KviPointerListIterator<KviPointerHashTableEntry<Key,T> >(*(m_pHashTable->m_pDataArray[m_uEntryIndex]));
+ bool bRet = m_pIterator->moveLast();
+ if(!bRet)
+ {
+ delete m_pIterator;
+ m_pIterator = NULL;
+ }
+ return bRet;
+ }
+ }
+ return false;
+ }
+
+ ///
+ /// Moves the iterator to the next element of the hash table.
+ /// The iterator must be actually valid for this function to work.
+ /// Returns true in case of success or false if there is no next item.
+ ///
+ bool moveNext()
+ {
+ if(!m_pIterator)
+ return false;
+ if(m_pIterator->moveNext())
+ return true;
+ if(m_pIterator)
+ {
+ delete m_pIterator;
+ m_pIterator = NULL;
+ }
+ m_uEntryIndex++;
+ while((m_uEntryIndex < m_pHashTable->m_uSize) && (!(m_pHashTable->m_pDataArray[m_uEntryIndex])))
+ {
+ m_uEntryIndex++;
+ }
+ if(m_uEntryIndex == m_pHashTable->m_uSize)
+ return false;
+ m_pIterator = new KviPointerListIterator<KviPointerHashTableEntry<Key,T> >(*(m_pHashTable->m_pDataArray[m_uEntryIndex]));
+ bool bRet = m_pIterator->moveFirst();
+ if(!bRet)
+ {
+ delete m_pIterator;
+ m_pIterator = NULL;
+ }
+ return bRet;
+ }
+
+ ///
+ /// Moves the iterator to the next element of the hash table.
+ /// The iterator must be actually valid for this function to work.
+ /// Returns true in case of success or false if there is no next item.
+ /// This is just an alias to moveNext().
+ ///
+ bool operator ++()
+ {
+ return moveNext();
+ }
+
+ ///
+ /// Moves the iterator to the previous element of the hash table.
+ /// The iterator must be actually valid for this function to work.
+ /// Returns true in case of success or false if there is no previous item.
+ ///
+ bool movePrev()
+ {
+ if(!m_pIterator)
+ return false;
+ if(m_pIterator->movePrev())
+ return true;
+ if(m_pIterator)
+ {
+ delete m_pIterator;
+ m_pIterator = NULL;
+ }
+ if(m_uEntryIndex >= m_pHashTable->m_uSize)
+ return false;
+ while(m_uEntryIndex > 0)
+ {
+ m_uEntryIndex--;
+ if(m_pHashTable->m_pDataArray[m_uEntryIndex])
+ {
+ m_pIterator = new KviPointerListIterator<KviPointerHashTableEntry<Key,T> >(*(m_pHashTable->m_pDataArray[m_uEntryIndex]));
+ bool bRet = m_pIterator->moveLast();
+ if(!bRet)
+ {
+ delete m_pIterator;
+ m_pIterator = NULL;
+ }
+ return bRet;
+ }
+ }
+ return false;
+ }
+
+
+ ///
+ /// Moves the iterator to the previous element of the hash table.
+ /// The iterator must be actually valid for this function to work.
+ /// Returns true in case of success or false if there is no previous item.
+ /// This is just an alias to movePrev() with a different name.
+ ///
+ bool operator --()
+ {
+ return movePrev();
+ }
+
+ ///
+ /// Returs the value pointed by the iterator
+ /// or a default constructed value if the iterator is not valid.
+ /// This is an alias to operator *() with just a different name.
+ ///
+ T * current() const
+ {
+ return m_pIterator ? m_pIterator->current()->data() : NULL;
+ }
+
+ ///
+ /// Returs the value pointed by the iterator
+ /// or a default constructed value if the iterator is not valid.
+ /// This is an alias to current() with just a different name.
+ ///
+ T * operator *() const
+ {
+ return m_pIterator ? m_pIterator->current()->data() : NULL;
+ }
+
+ ///
+ /// Returs the key pointed by the iterator
+ /// or a default constructed key if the iterator is not valid.
+ ///
+ const Key & currentKey() const
+ {
+ return m_pIterator ? m_pIterator->current()->key() : kvi_hash_key_default(((Key *)NULL));
+ }
+
+ ///
+ /// Moves the iterator to the first element of the hash table.
+ /// Returns the first item found or NULL if the hash table is empty.
+ ///
+ T * toFirst()
+ {
+ if(!moveFirst())
+ return NULL;
+ return current();
+ }
+public:
+ ///
+ /// Creates an iterator pointing to the first item in the hash table, if any.
+ ///
+ KviPointerHashTableIterator(const KviPointerHashTable<Key,T> &hTable)
+ {
+ m_pHashTable = &hTable;
+ m_uEntryIndex = 0;
+ m_pIterator = NULL;
+ moveFirst();
+ }
+
+ ///
+ /// Destroys the iterator
+ ///
+ ~KviPointerHashTableIterator()
+ {
+ if(m_pIterator)
+ delete m_pIterator;
+ }
+};
+
+
+
+
+#endif //_KVI_POINTERHASHTABLE_H_
diff --git a/src/kvilib/core/kvi_pointerlist.h b/src/kvilib/core/kvi_pointerlist.h
new file mode 100644
index 00000000..381780c8
--- /dev/null
+++ b/src/kvilib/core/kvi_pointerlist.h
@@ -0,0 +1,1069 @@
+#ifndef _KVI_POINTERLIST_H_
+#define _KVI_POINTERLIST_H_
+//=================================================================================================
+//
+// File : kvi_pointerlist.h
+// Creation date : Tue Jul 6 1999 14:52:20 by Szymon Stefanek
+//
+// This file is part of the KVirc irc client distribution
+// Copyright (C) 1999-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.
+//
+//=================================================================================================
+//=============================================================================
+//
+// C++ Template based double linked pointer list class
+// Original ss_list.h Created on 10 Dec 2001
+// Copyright (C) 2001-2007 Szymon Stefanek (pragma at kvirc dot net)
+// Added to KVIrc on 02 Jan 2008.
+//
+//=============================================================================
+
+// Qt changes the collection classes too much and too frequently.
+// I think we need to be independent of that to the maximum degree possible.
+// That's why we have our own fast pointer list class.
+// This does not depend on Qt AT ALL and has an interface similar
+// to the Qt<=3.x series. The pointer lists with the autodelete
+// feature was great and I don't completly understand why they have
+// been removed from Qt4 in favor of the value based non-autodeleting
+// lists... anyway: here we go :)
+
+#include "kvi_settings.h"
+
+template<typename T> class KviPointerList;
+template<typename T> class KviPointerListIterator;
+
+#ifndef NULL
+ #define NULL 0
+#endif
+
+///
+/// \internal
+///
+class KviPointerListNode
+{
+public:
+ KviPointerListNode * m_pPrev;
+ void * m_pData;
+ KviPointerListNode * m_pNext;
+};
+
+///
+/// \class KviPointerListIterator
+/// \brief A fast KviPointerList iterator.
+///
+/// This class allows traversing the list sequentially.
+/// Multilpe iterators can traverse the list at the same time.
+///
+/// Iteration example 1:
+///
+/// \verbatim
+/// KviPointerListIterator<T> it(list);
+/// for(bool b = it.moveFirst();b;b = it.moveNext())
+/// {
+/// T * pData = it.data();
+/// doSomethingWithData(pData);
+/// }
+/// \endverbatim
+///
+/// Iteration example 2:
+///
+/// \verbatim
+/// KviPointerListIterator<T> it(list);
+/// if(it.moveFirst())
+/// {
+/// do {
+/// T * pData = it.data();
+/// doSomethingWithData(pData);
+/// } while(it.moveNext());
+/// }
+/// \endverbatim
+///
+/// Iteration example 3:
+///
+/// \verbatim
+/// KviPointerListIterator<T> it(list.iteratorAt(10));
+/// if(it.isValid())
+/// {
+/// do {
+/// T * pData = it.data();
+/// doSomethingWithData(pData);
+/// while(it.movePrev());
+/// }
+/// \endverbatim
+///
+/// Please note that you must NOT remove any item from
+/// the list when using the iterators. An iterator pointing
+/// to a removed item will crash your application if you use it.
+/// The following code will NOT work (and crash):
+///
+/// \verbatim
+/// KviPointerList<T> l;
+/// l.append(new KviStr("x"));
+/// l.append(new KviStr("y"));
+/// KviPointerListIterator<T> it(l);
+/// it.moveFirst();
+/// l.removeFirst();
+/// KviStr * tmp = it.data(); <-- this will crash
+/// \endverbatim
+///
+/// In the rare cases in that you need to remove items
+/// while traversing the list you should put them
+/// in a temporary list and remove them after the iteration.
+///
+/// I've choosen this way because usually you don't modify
+/// the list while traversing it and a fix for this
+/// would add a constant overhead to several list operation.
+/// You just must take care of it yourself.
+///
+/// \warning This class is not thread safe by itself.
+///
+template<typename T> class KviPointerListIterator
+{
+protected:
+ KviPointerList<T> * m_pList;
+ KviPointerListNode * m_pNode;
+public:
+ ///
+ /// Creates an iterator copy.
+ /// The new iterator points exactly to the item pointed by src.
+ ///
+ KviPointerListIterator(const KviPointerListIterator<T> &src)
+ {
+ m_pList = src.m_pList;
+ m_pNode = src.m_pNode;
+ }
+
+ ///
+ /// Creates an iterator for the list l.
+ /// The iterator points to the first list item, if any.
+ ///
+ KviPointerListIterator(KviPointerList<T> &l)
+ {
+ m_pList = (KviPointerList<T> *)&l;
+ m_pNode = m_pList->m_pHead;
+ }
+
+ ///
+ /// Creates an iterator for the list l.
+ /// The iterator points to the specified list node.
+ ///
+ KviPointerListIterator(KviPointerList<T> &l,KviPointerListNode * pNode)
+ {
+ m_pList = (KviPointerList<T> *)&l;
+ m_pNode = pNode;
+ }
+
+ ///
+ /// Creates an iterator copy.
+ /// The new iterator points exactly to the item pointed by src.
+ ///
+ void operator = (const KviPointerListIterator<T> &src)
+ {
+ m_pList = src.m_pList;
+ m_pNode = src.m_pNode;
+ }
+public:
+ ///
+ /// Moves the iterator to the first element of the list.
+ /// Returns true in case of success or false if the list is empty.
+ ///
+ bool moveFirst()
+ {
+ m_pNode = m_pList->m_pHead;
+ return m_pNode != NULL;
+ }
+
+ ///
+ /// Moves the iterator to the last element of the list.
+ /// Returns true in case of success or false if the list is empty.
+ ///
+ bool moveLast()
+ {
+ m_pNode = m_pList->m_pTail;
+ return m_pNode != NULL;
+ }
+
+ ///
+ /// Moves the iterator to the next element of the list.
+ /// The iterator must be actually valid for this function to work.
+ /// Returns true in case of success or false if there is no next item.
+ ///
+ bool moveNext()
+ {
+ if(!m_pNode)return false;
+ m_pNode = m_pNode->m_pNext;
+ return m_pNode != NULL;
+ }
+
+ ///
+ /// Moves the iterator to the next element of the list.
+ /// The iterator must be actually valid for this operator to work.
+ /// Returns true in case of success or false if there is no next item.
+ /// This is just a convenient alias to moveNext().
+ ///
+ bool operator ++()
+ {
+ if(!m_pNode)return false;
+ m_pNode = m_pNode->m_pNext;
+ return m_pNode != NULL;
+ }
+
+ ///
+ /// Moves the iterator to the previous element of the list.
+ /// The iterator must be actually valid for this function to work.
+ /// Returns true in case of success or false if there is no previous item.
+ ///
+ bool movePrev()
+ {
+ if(!m_pNode)return false;
+ m_pNode = m_pNode->m_pPrev;
+ return m_pNode != NULL;
+ }
+
+ ///
+ /// Moves the iterator to the previous element of the list.
+ /// The iterator must be actually valid for this operator to work.
+ /// Returns true in case of success or false if there is no previous item.
+ /// This is just a convenient alias to movePrev().
+ ///
+ bool operator --()
+ {
+ if(!m_pNode)return false;
+ m_pNode = m_pNode->m_pPrev;
+ return m_pNode != NULL;
+ }
+
+ ///
+ /// Returs the value pointed by the iterator
+ /// or NULL if the iterator is not valid.
+ ///
+ T * current()
+ {
+ return m_pNode ? (T *)(m_pNode->m_pData) : NULL;
+ }
+
+ ///
+ /// Returs the value pointed by the iterator
+ /// or NULL if the iterator is not valid.
+ /// This is just an alias to current().
+ ///
+ T * operator *()
+ {
+ return m_pNode ? (T *)(m_pNode->m_pData) : NULL;
+ }
+
+ ///
+ /// Returns true if this iterator points to a valid
+ /// element of the list and false otherwise.
+ ///
+ bool isValid()
+ {
+ return m_pNode != NULL;
+ }
+};
+
+///
+/// \class KviPointerList
+/// \brief A template double linked list of pointers.
+///
+/// The main advantage of this type of list is speed.
+/// Insertion of pointers is very fast when compared
+/// to the typical "copy constructor" call used
+/// in the "plain type" template list implementations.
+///
+/// Iterating over pointers is also very fast and this
+/// class contains an internal iterator that allows to
+/// write loops in a compact and clean way.
+/// See the first(), next(), current() and findRef()
+/// functions for the description of this feature.
+///
+/// There is also a non-const external iterator
+/// that you can use to traverse the list concurrently.
+/// There is no const iterator (and no const access methods)
+/// since the list provides the autoDelete() method
+/// which vould implicitly violate constness.
+/// If you have to deal with const objects then
+/// you need to use a QList instead.
+///
+/// Your objects also do not need to support copy constructors
+/// or >= operators. This class will work fine without them
+/// as opposed to a plain QList.
+///
+/// This class also supports automatic deletion of the inseted items.
+/// See the setAutoDelete() and autoDelete() members for the
+/// description of the feature.
+///
+/// Typcal usage:
+///
+/// \verbatim
+/// KviPointerList<MyClass> list();
+/// list.append(new MyClass());
+/// list.append(new MyClass());
+/// ...
+/// for(MyClass * c = list.first();c;c = list.next())doSomethingWith(c);
+/// delete list; // autodelete is set to true in the constructor
+/// \endverbatim
+///
+/// \warning This class is absolutely NOT thread safe. You must
+/// protect concurrent access from multiple threads by
+/// using an external synchronization tool (such as KviMutex).
+///
+template<typename T> class KviPointerList
+{
+ friend class KviPointerListIterator<T>;
+protected:
+ bool m_bAutoDelete; //< do we automatically delete items when they are removed ?
+
+ KviPointerListNode * m_pHead; //< our list head pointer (NULL if there are no items in the list)
+ KviPointerListNode * m_pTail; //< our list tail
+ KviPointerListNode * m_pAux; //< our iteration pointer
+
+ unsigned int m_uCount; //< the count of items in the list
+protected:
+ ///
+ /// \internal
+ ///
+ /// inserts the item d before the item ref or at the beginning
+ /// if ref is not found in the list
+ /// also sets the current iteration pointer to the newly inserted item
+ ///
+ void insertBeforeSafe(KviPointerListNode * ref,const T * d)
+ {
+ m_pAux = ref;
+ KviPointerListNode * n = new KviPointerListNode;
+ n->m_pPrev = m_pAux->m_pPrev;
+ n->m_pNext = m_pAux;
+ if(m_pAux->m_pPrev)
+ {
+ m_pAux->m_pPrev->m_pNext = n;
+ } else {
+ m_pHead = n;
+ }
+ m_pAux->m_pPrev = n;
+ n->m_pData = (void *)d;
+ m_uCount++;
+ }
+
+ ///
+ /// \internal
+ ///
+ /// Grabs the first element from the list src
+ /// and puts it as the first element of this list.
+ ///
+ void grabFirstAndPrepend(KviPointerList<T> * src)
+ {
+ KviPointerListNode * pNewHead = src->m_pHead;
+ if(!pNewHead)
+ return;
+
+ if(pNewHead->m_pNext)
+ {
+ src->m_pHead = pNewHead->m_pNext;
+ src->m_pHead->m_pPrev = NULL;
+ } else {
+ src->m_pHead = NULL;
+ src->m_pTail = NULL;
+ }
+
+ if(m_pHead)
+ {
+ m_pHead->m_pPrev = pNewHead;
+ pNewHead->m_pNext = m_pHead;
+ m_pHead = pNewHead;
+ } else {
+ m_pHead = pNewHead;
+ m_pTail = pNewHead;
+ m_pHead->m_pNext = NULL;
+ }
+ m_uCount++;
+ src->m_uCount--;
+ }
+
+ ///
+ /// \internal
+ ///
+ /// Removes the current iteration item assuming that it is valid.
+ ///
+ void removeCurrentSafe()
+ {
+ if(m_pAux->m_pPrev)
+ m_pAux->m_pPrev->m_pNext = m_pAux->m_pNext;
+ else
+ m_pHead = m_pAux->m_pNext;
+ if(m_pAux->m_pNext)
+ m_pAux->m_pNext->m_pPrev = m_pAux->m_pPrev;
+ else
+ m_pTail = m_pAux->m_pPrev;
+ const T * pAuxData = (const T *)(m_pAux->m_pData);
+ delete m_pAux;
+ m_pAux = NULL;
+ m_uCount--;
+ if(m_bAutoDelete)
+ delete pAuxData; // this can cause recursion, so do it at the end
+ }
+
+public:
+ ///
+ /// Inserts the list src inside this list
+ /// by respecting the sort order.
+ /// The src list elements are removed.
+ ///
+ void merge(KviPointerList<T> * src)
+ {
+ m_pAux = m_pHead;
+ KviPointerListNode * n = src->m_pHead;
+ m_uCount += src->m_uCount;
+ while(m_pAux && n)
+ {
+ if(kvi_compare((const T *)(m_pAux->m_pData),(const T *)(n->m_pData)) > 0)
+ {
+ // our element is greater, n->m_pData goes first
+ KviPointerListNode * pNext = n->m_pNext;
+ n->m_pPrev = m_pAux->m_pPrev; // his prev becomes
+ n->m_pNext = m_pAux;
+ if(m_pAux->m_pPrev)
+ m_pAux->m_pPrev->m_pNext = n;
+ else
+ m_pHead = n;
+ m_pAux->m_pPrev = n;
+ n = pNext;
+ } else {
+ // that element is greater
+ m_pAux = m_pAux->m_pNext;
+ }
+ }
+ if(n)
+ {
+ // last items to append
+ if(m_pTail)
+ {
+ m_pTail->m_pNext = n;
+ n->m_pPrev = m_pTail;
+ } else {
+ m_pHead = n;
+ m_pTail = n;
+ n->m_pPrev = NULL;
+ }
+ m_pTail = src->m_pTail;
+ }
+
+ src->m_pHead = NULL;
+ src->m_pTail = NULL;
+ src->m_uCount = 0;
+ }
+
+ void swap(KviPointerList<T> * src)
+ {
+ KviPointerListNode * n = m_pHead;
+ m_pHead = src->m_pHead;
+ src->m_pHead = n;
+ n = m_pTail;
+ m_pTail = src->m_pTail;
+ src->m_pTail = n;
+ unsigned int uCount = m_uCount;
+ m_uCount = src->m_uCount;
+ src->m_uCount = uCount;
+ }
+
+
+ ///
+ /// Sorts this list in ascending order.
+ /// There must be an int kvi_compare(const T *p1,const T *p2) function
+ /// which returns a value less than, equal to
+ /// or greater than zero when the item p1 is considered lower than,
+ /// equal to or greater than p2.
+ ///
+ void sort()
+ {
+ if(m_uCount < 2)return;
+
+ KviPointerList<T> carry;
+ KviPointerList<T> tmp[64];
+ KviPointerList * fill = &tmp[0];
+ KviPointerList * counter;
+
+ do {
+ carry.grabFirstAndPrepend(this);
+
+ for(counter = &tmp[0];counter != fill && !counter->isEmpty();++counter)
+ {
+ counter->merge(&carry);
+ carry.swap(counter);
+ }
+ carry.swap(counter);
+ if(counter == fill)
+ ++fill;
+ } while(m_uCount > 0);
+
+ for(counter = &tmp[1];counter != fill;++counter)
+ counter->merge(counter-1);
+ swap(fill-1);
+ }
+
+ ///
+ /// Inserts the item respecting the sorting order inside the list.
+ /// The list itself must be already sorted for this to work correctly.
+ /// There must be a int kvi_compare(const T *p1,const T * p2)
+ /// that returns a value less than, equal to
+ /// or greater than zero when the item p1 is considered lower than,
+ /// equal to or greater than p2.
+ ///
+ void inSort(T * t)
+ {
+ KviPointerListNode * x = m_pHead;
+ while(x && (kvi_compare(((T *)x->m_pData),t) > 0))x = x->m_pNext;
+ if(!x)append(t);
+ else insertBeforeSafe(x,t);
+ }
+
+ ///
+ /// Returns true if the list is empty
+ ///
+ bool isEmpty() const
+ {
+ return (m_pHead == NULL);
+ }
+
+ ///
+ /// Returns the count of the items in the list
+ ///
+ unsigned int count() const
+ {
+ return m_uCount;
+ }
+
+ ///
+ /// Sets the iteration pointer to the first item in the list
+ /// and returns that item (or 0 if the list is empty)
+ ///
+ T * first()
+ {
+ if(!m_pHead)
+ {
+ m_pAux = NULL;
+ return NULL;
+ }
+ m_pAux = m_pHead;
+ return (T *)(m_pAux->m_pData);
+ }
+
+ ///
+ /// Removes the first element from the list
+ /// and returns it to the caller. This function
+ /// obviously never deletes the item (regadless of autoDeletion()).
+ ///
+ T * takeFirst()
+ {
+ if(!m_pHead)return NULL;
+ T * pData = (T *)m_pHead->m_pData;
+ if(m_pHead->m_pNext)
+ {
+ m_pHead = m_pHead->m_pNext;
+ delete m_pHead->m_pPrev;
+ m_pHead->m_pPrev = NULL;
+ } else {
+ delete m_pHead;
+ m_pHead = NULL;
+ m_pTail = NULL;
+ }
+ m_uCount--;
+ return pData;
+ }
+
+ ///
+ /// Returns an iterator pointing to the first item of the list.
+ ///
+ KviPointerListIterator<T> iteratorAtFirst()
+ {
+ return KviPointerListIterator<T>(*this,m_pHead);
+ }
+
+ ///
+ /// Sets the iteration pointer to the last item in the list
+ /// and returns that item (or 0 if the list is empty)
+ ///
+ T * last()
+ {
+ if(!m_pTail)
+ {
+ m_pAux = NULL;
+ return NULL;
+ }
+ m_pAux = m_pTail;
+ return (T *)(m_pAux->m_pData);
+ }
+
+ ///
+ /// Returns an iterator pointing to the first item of the list.
+ ///
+ KviPointerListIterator<T> iteratorAtLast()
+ {
+ return KviPointerListIterator<T>(*this,m_pTail);
+ }
+
+ ///
+ /// Returns the current iteration item
+ /// A call to this function MUST be preceded by a call to
+ /// first(),last(),at() or findRef()
+ ///
+ T * current()
+ {
+ return (T *)(m_pAux->m_pData);
+ }
+
+ ///
+ /// Returns the current iteration item
+ /// A call to this function should be preceded by a call to
+ /// first(),last(),at() or findRef().
+ /// This function will return a NULL pointer if the current
+ /// item has been invalidated due to a remove operation.
+ ///
+ T * safeCurrent()
+ {
+ return m_pAux ? (T *)(m_pAux->m_pData) : NULL;
+ }
+
+
+ ///
+ /// Returns an iterator pointing to the current item in the list.
+ /// A call to this function MUST be preceded by a call to
+ /// first(),last(),at() or findRef()
+ ///
+ KviPointerListIterator<T> iteratorAtCurrent()
+ {
+ return KviPointerListIterator<T>(*this,m_pAux);
+ }
+
+ ///
+ /// Sets the iteration pointer to the next item in the list
+ /// and returns that item (or 0 if the end of the list has been reached)
+ /// A call to this function MUST be preceded by a _succesfull_ call to
+ /// first(),last(),at() or findRef().
+ ///
+ T * next()
+ {
+ if(!m_pAux)return NULL;
+ m_pAux = m_pAux->m_pNext;
+ if(m_pAux)return (T *)(m_pAux->m_pData);
+ return NULL;
+ }
+
+ ///
+ /// Sets the iteration pointer to the previous item in the list
+ /// and returns that item (or 0 if the beginning of the list has been reached)
+ /// A call to this function MUST be preceded by a _succesfull_ call to
+ /// first(),last(),at() or findRef()
+ ///
+ T * prev()
+ {
+ if(!m_pAux)return NULL;
+ m_pAux = m_pAux->m_pPrev;
+ if(m_pAux)return (T *)(m_pAux->m_pData);
+ return NULL;
+ }
+
+ ///
+ /// Sets the iteration pointer to the nTh item in the list
+ /// and returns that item (or 0 if the index is out of range)
+ ///
+ T * at(int idx)
+ {
+ T * t = first();
+ int cnt = 0;
+ while(t)
+ {
+ if(idx == cnt)return t;
+ t = next();
+ cnt++;
+ }
+ return 0;
+ }
+
+ ///
+ /// Returns an iterator pointing to the item at the specified index.
+ ///
+ KviPointerListIterator<T> iteratorAt(int idx)
+ {
+ KviPointerListNode * n = m_pHead;
+ int cnt = 0;
+ while(n)
+ {
+ if(idx == cnt)
+ return KviPointerListIterator<T>(*this,n);
+ n = n->m_pNext;
+ cnt++;
+ }
+ return KviPointerListIterator<T>(*this,NULL);
+ }
+
+ ///
+ /// Sets the iteration pointer to the item with pointer d
+ /// and returns its position (zero based index) in the list or -1 if the
+ /// item cannot be found
+ ///
+ int findRef(const T * d)
+ {
+ int ret = 0;
+ for(T * t = first();t;t = next())
+ {
+ if(t == d)return ret;
+ ret++;
+ }
+ return -1;
+ }
+
+ ///
+ /// Returns an iterator pointing to the item with pointer d.
+ ///
+ KviPointerListIterator<T> iteratorAtRef(const T * d)
+ {
+ KviPointerListNode * n = m_pHead;
+ while(n)
+ {
+ if(n->m_pData == d)
+ return KviPointerListIterator<T>(*this,n);
+ n = n->m_pNext;
+ }
+ return KviPointerListIterator<T>(*this,NULL);
+ }
+
+ ///
+ /// Appends an item at the end of the list
+ ///
+ void append(const T * d)
+ {
+ if(!m_pHead)
+ {
+ m_pHead = new KviPointerListNode;
+ m_pHead->m_pPrev = NULL;
+ m_pHead->m_pNext = NULL;
+ m_pHead->m_pData = (void *)d;
+ m_pTail = m_pHead;
+ } else {
+ m_pTail->m_pNext = new KviPointerListNode;
+ m_pTail->m_pNext->m_pPrev = m_pTail;
+ m_pTail->m_pNext->m_pNext = NULL;
+ m_pTail->m_pNext->m_pData = (void *)d;
+ m_pTail = m_pTail->m_pNext;
+ }
+ m_uCount++;
+ }
+
+ ///
+ /// Appends all the items from the list l to this list
+ ///
+ void append(KviPointerList<T> * l)
+ {
+ for(T * t = l->first();t;t = l->next())append(t);
+ }
+
+ ///
+ /// Prepends (inserts in head position) all the items from
+ /// the list l to this list
+ ///
+ void prepend(KviPointerList<T> * l)
+ {
+ for(T * t = l->last();t;t = l->prev())prepend(t);
+ }
+
+ ///
+ /// Inserts the item d in the head position
+ ///
+ void prepend(const T * d)
+ {
+ if(!m_pHead)
+ {
+ m_pHead = new KviPointerListNode;
+ m_pHead->m_pPrev = NULL;
+ m_pHead->m_pNext = NULL;
+ m_pHead->m_pData = (void *)d;
+ m_pTail = m_pHead;
+ } else {
+ m_pHead->m_pPrev = new KviPointerListNode;
+ m_pHead->m_pPrev->m_pNext = m_pHead;
+ m_pHead->m_pPrev->m_pPrev = NULL;
+ m_pHead->m_pPrev->m_pData = (void *)d;
+ m_pHead = m_pHead->m_pPrev;
+ m_uCount++;
+ }
+ }
+
+ ///
+ /// Inserts the item d at the zero-based position
+ /// specified by iIndex. If the specified position
+ /// is out of the list then the item is appended.
+ /// Note that this function costs O(n).
+ /// It's really better to use insertAfter() or
+ /// insertBefore(), if possible.
+ ///
+ void insert(int iIndex,const T * d)
+ {
+ m_pAux = m_pHead;
+ while(m_pAux && iIndex > 0)
+ {
+ iIndex--;
+ m_pAux = m_pAux->m_pNext;
+ }
+ if(m_pAux)
+ insertBeforeSafe(m_pAux,d);
+ else
+ append(d);
+ }
+
+ ///
+ /// Removes the firstitem (if any)
+ /// the item is deleted if autoDelete() is set to true
+ ///
+ bool removeFirst()
+ {
+ if(!m_pHead)return false;
+ const T * pAuxData;
+ if(m_pHead->m_pNext)
+ {
+ m_pHead = m_pHead->m_pNext;
+ pAuxData = (const T *)(m_pHead->m_pPrev->m_pData);
+ delete m_pHead->m_pPrev;
+ m_pHead->m_pPrev = NULL;
+ } else {
+ pAuxData = (const T *)(m_pHead->m_pData);
+ delete m_pHead;
+ m_pHead = NULL;
+ m_pTail = NULL;
+ }
+ m_pAux = NULL;
+ m_uCount--;
+ if(m_bAutoDelete)
+ delete pAuxData;
+ return true;
+ }
+
+ ///
+ /// Removes the firstitem (if any)
+ /// the item is deleted if autoDelete() is set to true
+ ///
+ bool removeLast()
+ {
+ if(!m_pTail)return false;
+ const T * pAuxData;
+ if(m_pTail->m_pPrev)
+ {
+ m_pTail = m_pTail->m_pPrev;
+ pAuxData = (const T *)(m_pTail->m_pNext->m_pData);
+ delete m_pTail->m_pNext;
+ m_pTail->m_pNext = NULL;
+ } else {
+ pAuxData = (const T *)(m_pTail->m_pData);
+ delete m_pTail;
+ m_pHead = NULL;
+ m_pTail = NULL;
+ }
+ m_pAux = NULL;
+ m_uCount--;
+ if(m_bAutoDelete)
+ delete pAuxData;
+ return true;
+ }
+
+ ///
+ /// Removes the item at zero-based position iIndex.
+ /// Does nothing and returns false if iIndex is out of the list.
+ /// Please note that this function costs O(n).
+ ///
+ bool remove(int iIndex)
+ {
+ m_pAux = m_pHead;
+ while(m_pAux && iIndex > 0)
+ {
+ iIndex--;
+ m_pAux = m_pAux->m_pNext;
+ }
+ if(!m_pAux)
+ return false;
+ removeCurrentSafe();
+ return true;
+ }
+
+ ///
+ /// Sets the autodelete flag
+ /// When this flag is on (default) , all the items
+ /// are deleted when removed from the list (or when the list is destroyed
+ /// or cleared explicitly)
+ ///
+ void setAutoDelete(bool bAutoDelete)
+ {
+ m_bAutoDelete = bAutoDelete;
+ }
+
+ ///
+ /// Returns the autodelete flag.
+ ///
+ bool autoDelete()
+ {
+ return m_bAutoDelete;
+ };
+
+ ///
+ /// Removes all the items from the list
+ /// (the items are deleted if the autoDelete() flag is set to true)
+ ///
+ void clear()
+ {
+ while(m_pHead)removeFirst();
+ }
+
+ ///
+ /// Removes the current iteration item.
+ /// Returns true if the current iteration item was valid (and was removed)
+ /// and false otherwise.
+ ///
+ bool removeCurrent()
+ {
+ if(!m_pAux)
+ return false;
+ removeCurrentSafe();
+ return true;
+ }
+
+ ///
+ /// Removes the item pointed by d (if found in the list)
+ /// the item is deleted if the autoDelete() flag is set to true)
+ /// Returns true if the item was in the list and false otherwise.
+ ///
+ bool removeRef(const T * d)
+ {
+ if(findRef(d) == -1)return false;
+ removeCurrentSafe();
+ return true;
+ }
+
+ ///
+ /// inserts the item d after the item ref or at the end
+ /// if ref is not found in the list
+ /// also sets the current iteration pointer to the newly inserted item
+ ///
+ void insertAfter(const T * ref,const T * d)
+ {
+ if(findRef(ref) == -1)
+ {
+ append(d);
+ return;
+ }
+ KviPointerListNode * n = new KviPointerListNode;
+ n->m_pPrev = m_pAux;
+ n->m_pNext = m_pAux->m_pNext;
+ if(m_pAux->m_pNext)
+ m_pAux->m_pNext->m_pPrev = n;
+ else
+ m_pTail = n;
+ m_pAux->m_pNext = n;
+ n->m_pData = (void *)d;
+ m_uCount++;
+ }
+
+ ///
+ /// inserts the item d before the item ref or at the beginning
+ /// if ref is not found in the list
+ /// also sets the current iteration pointer to the newly inserted item
+ ///
+ void insertBefore(const T * ref,const T * d)
+ {
+ if(findRef(ref) == -1)
+ {
+ prepend(d);
+ return;
+ }
+ KviPointerListNode * n = new KviPointerListNode;
+ n->m_pPrev = m_pAux->m_pPrev;
+ n->m_pNext = m_pAux;
+ if(m_pAux->m_pPrev)
+ m_pAux->m_pPrev->m_pNext = n;
+ else
+ m_pHead = n;
+ m_pAux->m_pPrev = n;
+ n->m_pData = (void *)d;
+ m_uCount++;
+ }
+
+ ///
+ /// Inverts the elements in the list.
+ ///
+ void invert()
+ {
+ if(!m_pHead)return;
+ KviPointerListNode * oldHead = m_pHead;
+ KviPointerListNode * oldTail = m_pTail;
+ KviPointerListNode * n = m_pHead;
+ while(n)
+ {
+ KviPointerListNode * next = n->m_pNext;
+ n->m_pNext = n->m_pPrev;
+ n->m_pPrev = next;
+ n = next;
+ }
+ m_pTail = oldHead;
+ m_pHead = oldTail;
+ }
+
+ ///
+ /// clears the list and inserts all the items from the list l
+ ///
+ void copyFrom(KviPointerList<T> * l)
+ {
+ clear();
+ for(T * t = l->first();t;t = l->next())append(t);
+ }
+
+ ///
+ /// equivalent to copyFrom(l)
+ ///
+ KviPointerList<T> & operator = (KviPointerList<T> &l)
+ {
+ copyFrom(&l);
+ return *this;
+ }
+
+ ///
+ /// creates a template list
+ ///
+ KviPointerList<T>(bool bAutoDelete = true)
+ {
+ m_bAutoDelete = bAutoDelete;
+ m_pHead = NULL;
+ m_pTail = NULL;
+ m_uCount = 0;
+ m_pAux = NULL;
+ };
+
+ ///
+ /// destroys the list
+ /// if autoDelete() is set to true, all the items are deleted
+ ///
+ virtual ~KviPointerList<T>()
+ {
+ clear();
+ };
+};
+
+#define KviPointerListBase KviPointerList
+
+// BROKEN MSVC LINKER
+#ifdef COMPILE_ON_WINDOWS
+ #include "kvi_string.h"
+ template class KVILIB_API KviPointerList<KviStr>;
+#endif
+
+#endif //_KVI_POINTERLIST_H_
diff --git a/src/kvilib/core/kvi_qcstring.h b/src/kvilib/core/kvi_qcstring.h
new file mode 100644
index 00000000..0693e205
--- /dev/null
+++ b/src/kvilib/core/kvi_qcstring.h
@@ -0,0 +1,39 @@
+#ifndef _KVI_QCSTRING_H_
+#define _KVI_QCSTRING_H_
+
+//=============================================================================
+//
+// File : kvi_qcstring.h
+// Creation date : Thu Jan 18 2007 00:34:33 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 <q3cstring.h> // includes <qbytearray.h>
+ #define KviQCString QByteArray
+#else
+ // this is dead in Qt 4.x
+ #include <qcstring.h>
+ #define KviQCString QCString
+#endif
+
+#endif //!_KVI_QCSTRING_H_
diff --git a/src/kvilib/core/kvi_qstring.cpp b/src/kvilib/core/kvi_qstring.cpp
new file mode 100644
index 00000000..eba255aa
--- /dev/null
+++ b/src/kvilib/core/kvi_qstring.cpp
@@ -0,0 +1,1125 @@
+//=============================================================================
+//
+// File : kvi_qstring.cpp
+// Creation date : Mon Aug 04 2003 13:36:33 CEST by Szymon Stefanek
+//
+// This file is part of the KVirc irc client distribution
+// Copyright (C) 2003-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.
+//
+//=============================================================================
+
+//=============================================================================
+//
+// Helper functions for the QString class
+//
+//=============================================================================
+
+#define __KVILIB__
+
+
+#include "kvi_qstring.h"
+#include "kvi_string.h"
+#include "kvi_malloc.h"
+#include "kvi_locale.h"
+
+#include <ctype.h> // for tolower()
+#include <stdio.h> // for sprintf()
+#include <qregexp.h>
+
+// kvi_string.cpp
+extern unsigned char iso88591_toLower_map[256];
+extern unsigned char iso88591_toUpper_map[256];
+
+#define MY_MIN(a,b) (((a) < (b)) ? (a) : (b))
+
+namespace KviQString
+{
+ // The global empty (and null) string
+ const QString empty;
+
+ bool equalCSN(const QString &sz1,const QString &sz2,unsigned int len)
+ {
+ if(len == 0)return true; // assume equal
+ const QChar * c1 = sz1.unicode();
+ const QChar * c2 = sz2.unicode();
+ unsigned int lmin = MY_MIN(sz1.length(),sz2.length());
+ if(lmin < len)return false;
+ const QChar * c1e = c1 + len;
+
+ if(!c1 || !c2)return (c1 == c2);
+
+ while(c1 < c1e)
+ {
+ if(c1->unicode() != c2->unicode())return false;
+ c1++;
+ c2++;
+ }
+ return (c1 == c1e);
+ }
+
+ bool equalCIN(const QString &sz1,const QString &sz2,unsigned int len)
+ {
+ if(len == 0)return true; // assume equal
+ const QChar * c1 = sz1.unicode();
+ const QChar * c2 = sz2.unicode();
+ unsigned int lmin = MY_MIN(sz1.length(),sz2.length());
+ if(lmin < len)return false;
+ const QChar * c1e = c1 + len;
+
+ if(!c1 || !c2)return (c1 == c2);
+
+ while(c1 < c1e)
+ {
+#ifdef COMPILE_USE_QT4
+ if(c1->toLower().unicode() != c2->toLower().unicode())return false;
+#else
+ if(c1->lower().unicode() != c2->lower().unicode())return false;
+#endif
+ c1++;
+ c2++;
+ }
+ return (c1 == c1e);
+ }
+
+ bool equalCSN(const QString &sz1,const char * sz2,unsigned int len)
+ {
+ if(len == 0)return true; // assume equal
+ const QChar * c1 = sz1.unicode();
+ if(sz1.length() < len)return false;
+ const QChar * c1e = c1 + len;
+
+ if(!sz2)return !c1;
+ if(!c1)return !sz2;
+
+ while((c1 < c1e) && (*sz2))
+ {
+ if(c1->unicode() != *sz2)return false;
+ c1++;
+ sz2++;
+ }
+ return (c1 == c1e);
+ }
+
+ bool equalCIN(const QString &sz1,const char * sz2,unsigned int len)
+ {
+ if(len == 0)return true; // assume equal
+ const QChar * c1 = sz1.unicode();
+ if(sz1.length() < len)return false;
+ const QChar * c1e = c1 + len;
+
+ if(!sz2)return !c1;
+ if(!c1)return !(*sz2);
+
+ while((c1 < c1e) && (*sz2))
+ {
+#ifdef COMPILE_USE_QT4
+ if(c1->toLower().unicode() != tolower(*sz2))return false;
+#else
+ if(c1->lower().unicode() != tolower(*sz2))return false;
+#endif
+ c1++;
+ sz2++;
+ }
+ return (c1 == c1e);
+ }
+
+ // sz2 is assumed to be null terminated, sz1 is not!
+ bool equalCIN(const QString &sz1,const QChar *sz2,unsigned int len)
+ {
+ if(len == 0)return true; // assume equal
+ const QChar * c1 = sz1.unicode();
+ if(sz1.length() < len)return false;
+ const QChar * c1e = c1 + len;
+
+ if(!sz2)return !c1;
+ if(!c1)return !(sz2->unicode());
+
+ while((c1 < c1e) && (sz2->unicode()))
+ {
+#ifdef COMPILE_USE_QT4
+ if(c1->toLower().unicode() != sz2->toLower().unicode())return false;
+#else
+ if(c1->lower().unicode() != sz2->lower().unicode())return false;
+#endif
+ c1++;
+ sz2++;
+ }
+ return (c1 == c1e);
+ }
+
+ QString makeSizeReadable(size_t bytes)
+ {
+ double size = bytes;
+ if(size<900)
+ return QString(__tr2qs("%1 bytes")).arg(size,0,'f',3);
+
+ size/=1024;
+ if(size<900)
+ return QString(__tr2qs("%1 KB")).arg(size,0,'f',3);
+
+ size/=1024;
+ if(size<900)
+ return QString(__tr2qs("%1 MB")).arg(size,0,'f',3);
+
+ //Pirated DVD?;)
+ size/=1024;
+ if(size<900)
+ return QString(__tr2qs("%1 GB")).arg(size,0,'f',3);
+
+ //Uhm.. We are downloading a whole internet:)))
+ size/=1024;
+ return QString(__tr2qs("%1 TB")).arg(size,0,'f',3);
+ }
+
+ bool equalCS(const QString &sz1,const QString &sz2)
+ {
+ if(sz1.length() != sz2.length())return false;
+
+ const QChar * c1 = sz1.unicode();
+ const QChar * c2 = sz2.unicode();
+ const QChar * c1e = c1 + sz1.length();
+
+ if(!c1 || !c2)return (c1 == c2);
+
+ while(c1 < c1e)
+ {
+ if(c1->unicode() != c2->unicode())return false;
+ c1++;
+ c2++;
+ }
+ return (c1 == c1e);
+ }
+
+ bool equalCI(const QString &sz1,const QString &sz2)
+ {
+ if(sz1.length() != sz2.length())return false;
+
+ const QChar * c1 = sz1.unicode();
+ const QChar * c2 = sz2.unicode();
+ const QChar * c1e = c1 + sz1.length();
+
+ if(!c1 || !c2)return (c1 == c2);
+
+ while(c1 < c1e)
+ {
+#ifdef COMPILE_USE_QT4
+ if(c1->toLower().unicode() != c2->toLower().unicode())return false;
+#else
+ if(c1->lower().unicode() != c2->lower().unicode())return false;
+#endif
+ c1++;
+ c2++;
+ }
+ return (c1 == c1e);
+ }
+
+ // sz2 is assumed to be null terminated, sz1 is not!
+ bool equalCI(const QString &sz1,const QChar *sz2)
+ {
+ const QChar * c1 = sz1.unicode();
+ const QChar * c1e = c1 + sz1.length();
+
+ if(!c1 || !sz2)return (c1 == sz2);
+
+ while(c1 < c1e)
+ {
+ if(!sz2->unicode())return false; // sz1 has at least another character
+#ifdef COMPILE_USE_QT4
+ if(c1->toLower().unicode() != sz2->toLower().unicode())return false;
+#else
+ if(c1->lower().unicode() != sz2->lower().unicode())return false;
+#endif
+ c1++;
+ sz2++;
+ }
+ return (c1 == c1e) && (!sz2->unicode());
+ }
+
+ bool equalCS(const QString &sz1,const char * sz2)
+ {
+ const QChar * c1 = sz1.unicode();
+ const QChar * c1e = c1 + sz1.length();
+
+ if(!c1)return !sz2;
+
+ while((c1 < c1e) && (*sz2))
+ {
+ if(c1->unicode() != *sz2)return false;
+ c1++;
+ sz2++;
+ }
+ return ((c1 == c1e) && (*sz2 == '\0'));
+ }
+
+ bool equalCI(const QString &sz1,const char * sz2)
+ {
+ const QChar * c1 = sz1.unicode();
+ const QChar * c1e = c1 + sz1.length();
+
+ if(!c1)return !sz2;
+
+ while((c1 < c1e) && (*sz2))
+ {
+#ifdef COMPILE_USE_QT4
+ if(c1->toLower().unicode() != tolower(*sz2))return false;
+#else
+ if(c1->lower().unicode() != tolower(*sz2))return false;
+#endif
+ c1++;
+ sz2++;
+ }
+ return ((c1 == c1e) && (*sz2 == '\0'));
+ }
+
+ int cmpCS(const QString &sz1,const QString &sz2)
+ {
+ const QChar * c1 = sz1.unicode();
+ const QChar * c2 = sz2.unicode();
+ const QChar * c1e = c1 + sz1.length();
+ const QChar * c2e = c2 + sz2.length();
+
+ if(!c1)
+ {
+ if(!c2)return 0;
+ return -1;
+ }
+ if(!c2)return 1;
+
+
+ for(;;)
+ {
+ if(c1 >= c1e)
+ {
+ if(c2 < c2e)return /* 0 */ - (c2->unicode());
+ return 0;
+ }
+ if(c2 >= c2e)return c1->unicode() /* - 0 */;
+
+ int diff = c1->unicode() - c2->unicode();
+ if(diff)return diff;
+
+ c1++;
+ c2++;
+ }
+
+ return 0; // never here
+ }
+
+ int cmpCI(const QString &sz1,const QString &sz2)
+ {
+ const QChar * c1 = sz1.unicode();
+ const QChar * c2 = sz2.unicode();
+ const QChar * c1e = c1 + sz1.length();
+ const QChar * c2e = c2 + sz2.length();
+
+ if(!c1)
+ {
+ if(!c2)return 0;
+ return -1;
+ }
+ if(!c2)return 1;
+
+ for(;;)
+ {
+ if(c1 >= c1e)
+ {
+#ifdef COMPILE_USE_QT4
+ if(c2 < c2e)return /* 0 */ - (c2->toLower().unicode());
+#else
+ if(c2 < c2e)return /* 0 */ - (c2->lower().unicode());
+#endif
+ return 0;
+ }
+#ifdef COMPILE_USE_QT4
+ if(c2 >= c2e)return c1->toLower().unicode() /* - 0 */;
+#else
+ if(c2 >= c2e)return c1->lower().unicode() /* - 0 */;
+#endif
+
+#ifdef COMPILE_USE_QT4
+ int diff = c1->toLower().unicode() - c2->toLower().unicode();
+#else
+ int diff = c1->lower().unicode() - c2->lower().unicode();
+#endif
+ if(diff)return diff;
+
+ c1++;
+ c2++;
+ }
+
+ return 0; // never here
+ }
+
+ int cmpCIN(const QString &sz1,const QString &sz2,unsigned int len)
+ {
+ if(len == 0)return 0; // assume equal
+ unsigned int l1 = MY_MIN(len,sz1.length());
+ unsigned int l = MY_MIN(l1,sz2.length()); // FIXME: THIS IS NOT OK
+
+ const QChar * c1 = sz1.unicode();
+ const QChar * c2 = sz2.unicode();
+ const QChar * c1e = c1 + l;
+
+ if(!c1)
+ {
+ if(!c2)return 0;
+ return -1;
+ }
+ if(!c2)return 1;
+
+ int diff = 0;
+
+#ifdef COMPILE_USE_QT4
+ while((c1 < c1e) && !(diff = (c1->toLower().unicode() - c2->toLower().unicode())))
+#else
+ while((c1 < c1e) && !(diff = (c1->lower().unicode() - c2->lower().unicode())))
+#endif
+ {
+ c1++;
+ c2++;
+ }
+
+ return diff;
+ }
+
+ void ensureLastCharIs(QString &szString,const QChar &c)
+ {
+ if(!lastCharIs(szString,c))szString.append(c);
+ }
+
+ QString getToken(QString &szString,const QChar &sep)
+ {
+ int i=0;
+ while(i < szString.length())
+ {
+ if(szString[i] == sep)break;
+ i++;
+ }
+ QString ret;
+ if(i == szString.length())
+ {
+ ret = szString;
+ szString = "";
+ } else {
+ ret = szString.left(i);
+ while(i < szString.length())
+ {
+ if(szString[i] != sep)break;
+ i++;
+ }
+ if(i == szString.length())szString = "";
+ else szString.remove(0,i);
+ }
+ return ret;
+ }
+
+ void stripRightWhiteSpace(QString &s)
+ {
+ int iRemove = 0;
+ while(iRemove < s.length())
+ {
+ if(s.at(s.length() - (iRemove + 1)).isSpace())iRemove++;
+ else break;
+ }
+ if(iRemove > 0)s.remove(s.length() - iRemove,iRemove);
+ }
+
+ void stripRight(QString &s,const QChar &c)
+ {
+ int iRemove = 0;
+ while(iRemove < s.length())
+ {
+ if(s.at(s.length() - (iRemove + 1)) == c)iRemove++;
+ else break;
+ }
+ if(iRemove > 0)s.remove(s.length() - iRemove,iRemove);
+ }
+
+ void stripLeft(QString &s,const QChar &c)
+ {
+ int iRemove = 0;
+ while(iRemove < s.length())
+ {
+ if(s[iRemove] == c)
+ iRemove++;
+ else
+ break;
+ }
+ if(iRemove > 0)s.remove(0,iRemove);
+ }
+
+ void detach(QString &sz)
+ {
+#ifdef COMPILE_USE_QT4
+ sz.resize(sz.length());
+#else
+ sz.setLength(sz.length());
+#endif
+ }
+
+ const QChar * nullTerminatedArray(const QString &sz)
+ {
+ //sz.setLength(sz.length()); // detach!
+#ifdef COMPILE_USE_QT4
+ return sz.constData();
+#else
+ return (const QChar *)sz.ucs2(); // MAY BE NULL!
+#endif
+ }
+
+ void appendNumber(QString &s,double dReal)
+ {
+ char buffer[512];
+ ::sprintf(buffer,"%f",dReal);
+ s.append(buffer);
+ }
+
+ void appendNumber(QString &s,int iInteger)
+ {
+ char buffer[64];
+ ::sprintf(buffer,"%d",iInteger);
+ s.append(buffer);
+ }
+
+ void appendNumber(QString &s,kvi_i64_t iInteger)
+ {
+ char buffer[64];
+ ::sprintf(buffer,"%ld",iInteger);
+ s.append(buffer);
+ }
+
+ void appendNumber(QString &s,kvi_u64_t uInteger)
+ {
+ char buffer[64];
+ ::sprintf(buffer,"%lu",uInteger);
+ s.append(buffer);
+ }
+
+ void appendNumber(QString &s,unsigned int uInteger)
+ {
+ char buffer[64];
+ ::sprintf(buffer,"%u",uInteger);
+ s.append(buffer);
+ }
+
+ void vsprintf(QString &s,const QString &szFmt,kvi_va_list list)
+ {
+#define MEMINCREMENT 32
+
+ int reallen = 0;
+ int allocsize = MEMINCREMENT;
+
+ //s.setLength(allocsize);
+
+ const QChar * fmt = nullTerminatedArray(szFmt);
+ if(!fmt)
+ {
+ s = QString::null;
+ return;
+ }
+
+ QChar * buffer = (QChar *)kvi_malloc(sizeof(QChar) * allocsize);
+ //QChar * p = (QChar *)s.unicode();
+
+ char *argString;
+ long argValue;
+ unsigned long argUValue;
+
+ //9999999999999999999999999999999\0
+ char numberBuffer[32]; //enough ? 10 is enough for 32bit unsigned int...
+ char *pNumBuf;
+ unsigned int tmp;
+
+ QChar * p = buffer;
+
+#define INCREMENT_MEM \
+ { \
+ allocsize += MEMINCREMENT; \
+ buffer = (QChar *)kvi_realloc(buffer,sizeof(QChar) * allocsize); \
+ p = buffer + reallen; \
+ }
+
+#define INCREMENT_MEM_BY(numchars) \
+ { \
+ allocsize += numchars + MEMINCREMENT; \
+ buffer = (QChar *)kvi_realloc(buffer,sizeof(QChar) * allocsize); \
+ p = buffer + reallen; \
+ }
+
+
+ for(; fmt->unicode() ; ++fmt)
+ {
+ if(reallen == allocsize)INCREMENT_MEM
+
+ //copy up to a '%'
+ if(fmt->unicode() != '%')
+ {
+ *p++ = *fmt;
+ reallen++;
+ continue;
+ }
+
+ ++fmt; //skip this '%'
+ switch(fmt->unicode())
+ {
+ case 's': // char * string
+ {
+ argString = kvi_va_arg(list,char *);
+ if(!argString)argString = "[!NULL!]";
+ QString str(argString);
+ if(str.isEmpty())continue;
+ int len = str.length();
+ const QChar * ch = str.unicode();
+ if(!ch)continue;
+ if((allocsize - reallen) < len)INCREMENT_MEM_BY(len)
+ while(len--)*p++ = *ch++;
+ reallen += str.length();
+ continue;
+ }
+ case 'S': // KviStr * string
+ {
+ KviStr * str = kvi_va_arg(list,KviStr *);
+ if(!str)continue;
+ if((allocsize - reallen) < str->len())INCREMENT_MEM_BY(str->len())
+ argString = str->ptr();
+ while(*argString)*p++ = QChar(*argString++);
+ reallen += str->len();
+ continue;
+ }
+ case 'Q': // QString * string
+ {
+ QString * str = kvi_va_arg(list,QString *);
+ if(!str)continue;
+ if(str->isEmpty())continue;
+ int len = str->length();
+ const QChar * ch = str->unicode();
+ if(!ch)continue;
+ if((allocsize - reallen) < len)INCREMENT_MEM_BY(len)
+ while(len--)*p++ = *ch++;
+ reallen += str->length();
+ continue;
+ }
+ case 'c': //char
+ {
+ //
+ // I'm not sure about this...
+ // In the linux kernel source the
+ // unsigned char is extracted from an integer type.
+ // We assume that gcc stacks a char argument
+ // as sizeof(int) bytes value.
+ // Is this always true ?
+ //
+ *p++ = (char)kvi_va_arg(list,int);
+ reallen++;
+ continue;
+ }
+ case 'q': // QChar *
+ {
+ //
+ // I'm not sure about this...
+ // In the linux kernel source the
+ // unsigned char is extracted from an integer type.
+ // We assume that gcc stacks a char argument
+ // as sizeof(int) bytes value.
+ // Is this always true ?
+ //
+ *p++ = *((QChar *)kvi_va_arg(list,QChar *));
+ reallen++;
+ continue;
+ }
+ case 'd': //signed integer
+ {
+ argValue = kvi_va_arg(list,int);
+ if(argValue < 0)
+ { //negative integer
+ *p++ = '-';
+ reallen++;
+ argValue = -argValue; //need to have it positive
+ // most negative integer exception (avoid completely senseless (non digit) responses)
+ if(argValue < 0)argValue = 0; //we get -0 here
+ }
+ //write the number in a temporary buffer
+ pNumBuf = numberBuffer;
+ do {
+ tmp = argValue / 10;
+ *pNumBuf++ = argValue - (tmp * 10) + '0';
+ } while((argValue = tmp));
+ //copy now....
+ argUValue = pNumBuf - numberBuffer; //length of the number string
+ if((allocsize - reallen) < (int)argUValue)INCREMENT_MEM_BY(argUValue)
+ do { *p++ = QChar(*--pNumBuf); } while(pNumBuf != numberBuffer);
+ reallen += argUValue;
+ continue;
+ }
+ case 'u': //unsigned integer
+ {
+ argUValue = kvi_va_arg(list,unsigned int); //many implementations place int here
+ //write the number in a temporary buffer
+ pNumBuf = numberBuffer;
+ do {
+ tmp = argUValue / 10;
+ *pNumBuf++ = argUValue - (tmp * 10) + '0';
+ } while((argUValue = tmp));
+ //copy now....
+ argValue = pNumBuf - numberBuffer; //length of the number string
+ if((allocsize - reallen) < argValue)INCREMENT_MEM_BY(argValue)
+ do { *p++ = *--pNumBuf; } while(pNumBuf != numberBuffer);
+ reallen += argValue;
+ continue;
+ }
+ case 'h':
+ case 'x': // hexadecimal unsigned integer
+ {
+ static char hexsmalldigits[]="0123456789abcdef";
+ argUValue = kvi_va_arg(list,unsigned int); //many implementations place int here
+ //write the number in a temporary buffer
+ pNumBuf = numberBuffer;
+ do {
+ tmp = argUValue / 16;
+ *pNumBuf++ = hexsmalldigits[argUValue - (tmp * 16)];
+ } while((argUValue = tmp));
+ //copy now....
+ argValue = pNumBuf - numberBuffer; //length of the number string
+ if((allocsize - reallen) < argValue)INCREMENT_MEM_BY(argValue)
+ do { *p++ = *--pNumBuf; } while(pNumBuf != numberBuffer);
+ reallen += argValue;
+ continue;
+ }
+ case 'H':
+ case 'X': // hexadecimal unsigned integer
+ {
+ static char hexbigdigits[]="0123456789ABCDEF";
+ argUValue = kvi_va_arg(list,unsigned int); //many implementations place int here
+ //write the number in a temporary buffer
+ pNumBuf = numberBuffer;
+ do {
+ tmp = argUValue / 16;
+ *pNumBuf++ = hexbigdigits[argUValue - (tmp * 16)];
+ } while((argUValue = tmp));
+ //copy now....
+ argValue = pNumBuf - numberBuffer; //length of the number string
+ if((allocsize - reallen) < argValue)INCREMENT_MEM_BY(argValue)
+ do { *p++ = *--pNumBuf; } while(pNumBuf != numberBuffer);
+ reallen += argValue;
+ continue;
+ }
+ default: //a normal percent followed by some char
+ {
+ *p++ = '%'; //write it
+ reallen++;
+ if(fmt->unicode())
+ {
+ if(reallen == allocsize)INCREMENT_MEM
+ *p++ = *fmt;
+ reallen++;
+ }
+ continue;
+ }
+ }
+ }
+
+ s.setUnicode(buffer,reallen);
+ kvi_free(buffer);
+ //s.squeeze();
+ }
+
+
+ QString & sprintf(QString &s,const QString &szFmt,...)
+ {
+ kvi_va_list list;
+ kvi_va_start_by_reference(list,szFmt);
+ //print...with max 256 chars
+ KviQString::vsprintf(s,szFmt,list);
+ kvi_va_end(list);
+ return s;
+ }
+
+ void appendFormatted(QString &s,const QString &szFmt,...)
+ {
+ QString tmp;
+ kvi_va_list list;
+ kvi_va_start_by_reference(list,szFmt);
+ //print...with max 256 chars
+ KviQString::vsprintf(tmp,szFmt,list);
+ kvi_va_end(list);
+ s.append(tmp);
+ }
+
+ bool matchWildExpressionsCI(const QString &szM1,const QString &szM2)
+ {
+ //Matches two regular expressions containging wildcards (* and ?)
+
+ // s1
+ // m1
+ // mask1 : *xor
+ // mask2 : xorand*xor
+ // m2
+ // s2
+
+ // s2
+ // m2
+ // |
+ // XorT!xor@111.111.111.11
+ //
+ // *!*@*.net
+ // |
+ // m1
+ // s1
+ //
+
+#ifdef COMPILE_USE_QT4
+ const QChar * m1 = (const QChar *)szM1.constData();
+ const QChar * m2 = (const QChar *)szM2.constData();
+#else
+ const QChar * m1 = (const QChar *)szM1.ucs2();
+ const QChar * m2 = (const QChar *)szM2.ucs2();
+#endif
+
+ if(!(m1 && m2 && (m1->unicode())))return false;
+ const QChar * savePos1 = 0;
+ const QChar * savePos2 = m2;
+ while(m1->unicode())
+ {
+ //loop managed by m1 (initially first mask)
+ if(m1->unicode()=='*')
+ {
+ //Found a wildcard in m1
+ savePos1 = ++m1; //move to the next char and save the position...this is our jolly
+ if(!savePos1->unicode())return true; //last was a wildcard , matches everything ahead...
+ savePos2 = m2+1; //next return state for the second string
+ continue; //and return
+ }
+ if(!m2->unicode())return false; //m2 finished and we had something to match here!
+#ifdef COMPILE_USE_QT4
+ if(m1->toLower()==m2->toLower())
+#else
+ if(m1->lower()==m2->lower())
+#endif
+ {
+ //chars matched
+ m1++; //Go ahead in the two strings
+ m2++; //
+ if((!(m1->unicode())) && m2->unicode() && savePos1)
+ {
+ //m1 finished , but m2 not yet and we have a savePosition for m1 (there was a wildcard)...
+ //retry matching the string following the * from the savePos2 (one char ahead last time)
+ m1 = savePos1; //back to char after wildcard
+ m2 = savePos2; //back to last savePos2
+ savePos2++; //next savePos2 will be next char
+ }
+ } else {
+ if(m2->unicode() == '*')
+ {
+ //A wlidcard in the second string
+ //Invert the game : mask1 <-> mask2
+ //mask2 now leads the game...
+ savePos1 = m1; //aux
+ m1 = m2; //...swap
+ m2 = savePos1; //...swap
+ savePos1 = m1; //sync save pos1
+ savePos2 = m2 + 1; //sync save pos2
+ continue; //...and again
+ }
+ // m1 != m2 , m1 != * , m2 != *
+ if((m1->unicode() == '?') || (m2->unicode() == '?'))
+ {
+ m1++;
+ m2++;
+ if((!(m1->unicode())) && m2->unicode() && savePos1)
+ {
+ //m1 finished , but m2 not yet and we have a savePosition for m1 (there was a wildcard)...
+ //retry matching the string following the * from the savePos2 (one char ahead last time)
+ m1 = savePos1; //back to char after wildcard
+ m2 = savePos2; //back to last savePos2
+ savePos2++; //next savePos2 will be next char
+ }
+ } else {
+ if(savePos1)
+ {
+ //Have a jolly man...allow not matching...
+ m1 = savePos1; //go back to char after wildcard...need to rematch...
+ m2 = savePos2; //back to last savePos2
+ savePos2++; //and set next savePos2
+ } else return false; //No previous wildcards...not matched!
+ }
+ }
+ }
+ return (!(m2->unicode())); //m1 surely finished , so for the match , m2 must be finished too
+ }
+
+ bool matchStringCI(const QString &szExp,const QString &szStr,bool bIsRegExp,bool bExact)
+ {
+ QString szWildcard;
+#ifdef COMPILE_USE_QT4
+ QChar* ptr=(QChar*)szExp.constData();
+#else
+ QChar* ptr=(QChar*)szExp.ucs2();
+#endif
+ if(!ptr) return 0;
+ while(ptr->unicode())
+ {
+ if((ptr->unicode()=='[') || (ptr->unicode()==']'))
+ {
+ szWildcard.append("[");
+ szWildcard.append(*ptr);
+ szWildcard.append("]");
+ } else {
+ szWildcard.append(*ptr);
+ }
+ ptr++;
+ }
+#ifdef COMPILE_USE_QT4
+ QRegExp re(szWildcard,Qt::CaseInsensitive,bIsRegExp ? QRegExp::RegExp : QRegExp::Wildcard);
+#else
+ QRegExp re(szWildcard,false,!bIsRegExp);
+#endif
+ if(bExact) return re.exactMatch(szStr);
+#ifdef COMPILE_USE_QT4
+ return re.indexIn(szStr) != -1;
+#else
+ return re.search(szStr) != -1;
+#endif
+ }
+
+ bool matchStringCS(const QString &szExp,const QString &szStr,bool bIsRegExp,bool bExact)
+ {
+ QString szWildcard;
+#ifdef COMPILE_USE_QT4
+ QChar* ptr=(QChar*)szExp.constData();
+#else
+ QChar* ptr=(QChar*)szExp.ucs2();
+#endif
+ if(!ptr) return 0;
+ while(ptr->unicode())
+ {
+ if((ptr->unicode()=='[')) // <-- hum ?
+ {
+ szWildcard.append("[");
+ szWildcard.append(*ptr);
+ szWildcard.append("]");
+ } else {
+ szWildcard.append(*ptr);
+ }
+ ptr++;
+ }
+#ifdef COMPILE_USE_QT4
+ QRegExp re(szWildcard,Qt::CaseSensitive,bIsRegExp ? QRegExp::RegExp : QRegExp::Wildcard);
+#else
+ QRegExp re(szWildcard,true,!bIsRegExp);
+#endif
+ if(bExact) return re.exactMatch(szStr);
+#ifdef COMPILE_USE_QT4
+ return re.indexIn(szStr) != -1;
+#else
+ return re.search(szStr) != -1;
+#endif
+ }
+
+ void cutFromFirst(QString &s,const QChar &c,bool bIncluded)
+ {
+#ifdef COMPILE_USE_QT4
+ int idx = s.indexOf(c);
+#else
+ int idx = s.find(c);
+#endif
+ if(idx == -1)return;
+ s.truncate(bIncluded ? idx : idx + 1);
+ }
+
+ void cutFromLast(QString &s,const QChar &c,bool bIncluded)
+ {
+#ifdef COMPILE_USE_QT4
+ int idx = s.lastIndexOf(c);
+#else
+ int idx = s.findRev(c);
+#endif
+ if(idx == -1)return;
+ s.truncate(bIncluded ? idx : idx + 1);
+ }
+
+ void cutToFirst(QString &s,const QChar &c,bool bIncluded,bool bClearIfNotFound)
+ {
+#ifdef COMPILE_USE_QT4
+ int idx = s.indexOf(c);
+#else
+ int idx = s.find(c);
+#endif
+ if(idx == -1)
+ {
+ if(bClearIfNotFound)s = "";
+ return;
+ }
+ s.remove(0,bIncluded ? idx + 1 : idx);
+ }
+
+ void cutToLast(QString &s,const QChar &c,bool bIncluded,bool bClearIfNotFound)
+ {
+#ifdef COMPILE_USE_QT4
+ int idx = s.lastIndexOf(c);
+#else
+ int idx = s.findRev(c);
+#endif
+ if(idx == -1)
+ {
+ if(bClearIfNotFound)s = "";
+ return;
+ }
+ s.remove(0,bIncluded ? idx + 1 : idx);
+ }
+
+ void cutFromFirst(QString &s,const QString &c,bool bIncluded)
+ {
+#ifdef COMPILE_USE_QT4
+ int idx = s.indexOf(c);
+#else
+ int idx = s.find(c);
+#endif
+ if(idx == -1)return;
+ s.truncate(bIncluded ? idx : idx + c.length());
+ }
+
+ void cutFromLast(QString &s,const QString &c,bool bIncluded)
+ {
+#ifdef COMPILE_USE_QT4
+ int idx = s.lastIndexOf(c);
+#else
+ int idx = s.findRev(c);
+#endif
+ if(idx == -1)return;
+ s.truncate(bIncluded ? idx : idx + c.length());
+ }
+
+ void cutToFirst(QString &s,const QString &c,bool bIncluded,bool bClearIfNotFound)
+ {
+#ifdef COMPILE_USE_QT4
+ int idx = s.indexOf(c);
+#else
+ int idx = s.find(c);
+#endif
+ if(idx == -1)
+ {
+ if(bClearIfNotFound)s = "";
+ return;
+ }
+ s.remove(0,bIncluded ? idx + c.length() : idx);
+ }
+
+ void cutToLast(QString &s,const QString &c,bool bIncluded,bool bClearIfNotFound)
+ {
+#ifdef COMPILE_USE_QT4
+ int idx = s.lastIndexOf(c);
+#else
+ int idx = s.findRev(c);
+#endif
+ if(idx == -1)
+ {
+ if(bClearIfNotFound)s = "";
+ return;
+ }
+ s.remove(0,bIncluded ? idx + c.length() : idx);
+ }
+
+ QString upperISO88591(const QString &szSrc)
+ {
+ const QChar * c = nullTerminatedArray(szSrc);
+ if(!c)
+ {
+ QString ret;
+ return ret;
+ }
+ QChar * buffer = (QChar *)kvi_malloc(sizeof(QChar) * szSrc.length());
+ QChar * b = buffer;
+ unsigned short us = c->unicode();
+ while(us)
+ {
+ if(us < 256)
+ *b=QChar((unsigned short)iso88591_toUpper_map[us]);
+ else
+ *b = *c;
+ c++;
+ b++;
+ us = c->unicode();
+ }
+ QString ret(buffer,szSrc.length());
+ kvi_free(buffer);
+ return ret;
+ }
+
+ QString lowerISO88591(const QString &szSrc)
+ {
+ const QChar * c = nullTerminatedArray(szSrc);
+ if(!c)
+ {
+ QString ret;
+ return ret;
+ }
+ QChar * buffer = (QChar *)kvi_malloc(sizeof(QChar) * szSrc.length());
+ QChar * b = buffer;
+ unsigned short us = c->unicode();
+ while(us)
+ {
+ if(us < 256)
+ {
+ *b=QChar((unsigned short)iso88591_toLower_map[us]);
+ } else
+ *b = *c;
+ c++;
+ b++;
+ us = c->unicode();
+ }
+ QString ret(buffer,szSrc.length());
+ kvi_free(buffer);
+ return ret;
+ }
+
+ void transliterate(QString &s,const QString &szToFind,const QString &szReplacement)
+ {
+ int i=0;
+ int il = MY_MIN(szToFind.length(),szReplacement.length());
+ while(i < il)
+ {
+ int k=0;
+ int kl = s.length();
+ while(k < kl)
+ {
+ if(s[k] == szToFind[i])s[k] = szReplacement[i];
+ k++;
+ }
+ i++;
+ }
+ }
+
+ static char hexdigits[16] = { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' };
+
+ void bufferToHex(QString &szRetBuffer,const unsigned char * buffer,unsigned int len)
+ {
+#ifdef COMPILE_USE_QT4
+ szRetBuffer.resize(len * 2);
+#else
+ szRetBuffer.setLength(len * 2);
+#endif
+ unsigned int i=0;
+ while(i < (len*2))
+ {
+ szRetBuffer[int(i)] = QChar( (unsigned int) hexdigits[(*buffer) / 16] );
+ i++;
+ szRetBuffer[int(i)] = QChar( (unsigned int)hexdigits[(*buffer) % 16] );
+ i++;
+ buffer++;
+ }
+ }
+};
diff --git a/src/kvilib/core/kvi_qstring.h b/src/kvilib/core/kvi_qstring.h
new file mode 100644
index 00000000..c82063e9
--- /dev/null
+++ b/src/kvilib/core/kvi_qstring.h
@@ -0,0 +1,293 @@
+#ifndef _KVI_QSTRING_H_
+#define _KVI_QSTRING_H_
+
+//=============================================================================
+//
+// File : kvi_qstring.h
+// Creation date : Mon Aug 04 2003 13:36:33 CEST by Szymon Stefanek
+//
+// This file is part of the KVirc irc client distribution
+// Copyright (C) 2003-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.
+//
+//=============================================================================
+
+//=============================================================================
+//
+// Helper functions for the QString class
+//
+//=============================================================================
+
+#include "kvi_settings.h"
+#include "kvi_inttypes.h"
+#include "kvi_stdarg.h"
+#include "kvi_qcstring.h"
+
+#include <qstring.h>
+
+///
+/// \namespace KviQString
+///
+/// \brief A namespace for QString helper functions
+///
+/// This namespace contains several helper functions
+/// that are used when dealing with QString.
+///
+namespace KviQString
+{
+ extern KVILIB_API QString makeSizeReadable(size_t size);
+ extern KVILIB_API bool equalCS(const QString &sz1,const QString &sz2);
+ extern KVILIB_API bool equalCI(const QString &sz1,const QString &sz2);
+ extern KVILIB_API bool equalCS(const QString &sz1,const char * sz2);
+ extern KVILIB_API bool equalCI(const QString &sz1,const char * sz2);
+ // sz2 is assumed to be null terminated here!
+ extern KVILIB_API bool equalCI(const QString &sz1,const QChar * sz2);
+ inline bool equalCS(const char * sz1,const QString &sz2)
+ { return equalCS(sz2,sz1); };
+ inline bool equalCI(const char * sz1,const QString &sz2)
+ { return equalCI(sz2,sz1); };
+ // sz1 is assumed to be null terminated here!
+ inline bool equalCI(const QChar * sz1,const QString &sz2)
+ { return equalCI(sz2,sz1); };
+
+ extern KVILIB_API bool equalCSN(const QString &sz1,const QString &sz2,unsigned int len);
+ extern KVILIB_API bool equalCIN(const QString &sz1,const QString &sz2,unsigned int len);
+ extern KVILIB_API bool equalCSN(const QString &sz1,const char * sz2,unsigned int len);
+ extern KVILIB_API bool equalCIN(const QString &sz1,const char * sz2,unsigned int len);
+ // sz2 is assumed to be null terminated here!
+ extern KVILIB_API bool equalCIN(const QString &sz1,const QChar * sz2,unsigned int len);
+ inline bool equalCSN(const char * sz1,const QString &sz2,unsigned int len)
+ { return equalCSN(sz2,sz1,len); };
+ inline bool equalCIN(const char * sz1,const QString &sz2,unsigned int len)
+ { return equalCIN(sz2,sz1,len); };
+ // sz1 is assumed to be null terminated here!
+ inline bool equalCIN(const QChar * sz1,const QString &sz2,unsigned int len)
+ { return equalCIN(sz2,sz1,len); };
+
+ //note that greater here means that come AFTER in the alphabetic order
+ // return < 0 ---> str1 < str2
+ // return = 0 ---> str1 = str2
+ // return > 0 ---> str1 > str2
+ extern KVILIB_API int cmpCI(const QString &sz1,const QString &sz2);
+ extern KVILIB_API int cmpCIN(const QString &sz1,const QString &sz2,unsigned int len);
+ extern KVILIB_API int cmpCS(const QString &sz1,const QString &sz2);
+
+ extern KVILIB_API void detach(QString &sz);
+
+ // this makes the QString sz appear as a null terminated array
+ // it MAY RETURN 0 when the QString is null!
+ extern KVILIB_API const QChar * nullTerminatedArray(const QString &sz);
+
+ inline bool lastCharIs(QString &szString,const QChar &c)
+ { return szString.endsWith(c); };
+
+ extern KVILIB_API void ensureLastCharIs(QString &szString,const QChar &c);
+
+ // wild expression matching
+ extern KVILIB_API bool matchWildExpressionsCI(const QString &szM1,const QString &szM2);
+ // wild or regexp matching
+ extern KVILIB_API bool matchStringCI(const QString &szExp,const QString &szStr,bool bIsRegExp = false,bool bExact = false);
+ extern KVILIB_API bool matchStringCS(const QString &szExp,const QString &szStr,bool bIsRegExp = false,bool bExact = false);
+
+ extern KVILIB_API void vsprintf(QString &s,const QString &szFmt,kvi_va_list list);
+ extern KVILIB_API QString & sprintf(QString &s,const QString &szFmt,...);
+ extern KVILIB_API void stripRightWhiteSpace(QString &s);
+ extern KVILIB_API void stripLeft(QString &s,const QChar &c);
+ extern KVILIB_API void stripRight(QString &s,const QChar &c);
+ extern KVILIB_API void appendFormatted(QString &s,const QString &szFmt,...);
+ extern KVILIB_API void appendNumber(QString &s,double dReal);
+ extern KVILIB_API void appendNumber(QString &s,kvi_i64_t iInteger);
+ extern KVILIB_API void appendNumber(QString &s,int iInteger);
+ extern KVILIB_API void appendNumber(QString &s,unsigned int uInteger);
+ extern KVILIB_API void appendNumber(QString &s,kvi_u64_t uInteger);
+
+ extern KVILIB_API void cutFromFirst(QString &s,const QChar &c,bool bIncluded = true);
+ extern KVILIB_API void cutFromLast(QString &s,const QChar &c,bool bIncluded = true);
+ extern KVILIB_API void cutToFirst(QString &s,const QChar &c,bool bIncluded = true,bool bClearIfNotFound = false);
+ extern KVILIB_API void cutToLast(QString &s,const QChar &c,bool bIncluded = true,bool bClearIfNotFound = false);
+ extern KVILIB_API void cutFromFirst(QString &s,const QString &c,bool bIncluded = true);
+ extern KVILIB_API void cutFromLast(QString &s,const QString &c,bool bIncluded = true);
+ extern KVILIB_API void cutToFirst(QString &s,const QString &c,bool bIncluded = true,bool bClearIfNotFound = false);
+ extern KVILIB_API void cutToLast(QString &s,const QString &c,bool bIncluded = true,bool bClearIfNotFound = false);
+
+ extern KVILIB_API QString upperISO88591(const QString &szSrc);
+ extern KVILIB_API QString lowerISO88591(const QString &szSrc);
+ extern KVILIB_API QString getToken(QString &szString,const QChar &sep);
+
+ extern KVILIB_API void transliterate(QString &s,const QString &szToFind,const QString &szReplacement);
+
+ extern KVILIB_API void bufferToHex(QString &szRetBuffer,const unsigned char * buffer,unsigned int len);
+
+ // a global empty string (note that this is ALSO NULL under Qt 3.x)
+ extern KVILIB_API const QString empty;
+
+ ///
+ /// A portability wrapper which with Qt3 and Qt4.
+ /// Returns a lowcase version of the parameter string.
+ ///
+ inline QString toLower(const QString &s)
+ {
+#ifdef COMPILE_USE_QT4
+ return s.toLower();
+#else
+ return s.lower();
+#endif
+ }
+
+ inline int find(const QString &s,QChar c,int index = 0,bool cs = true)
+ {
+#ifdef COMPILE_USE_QT4
+ return s.indexOf(c,index,cs ? Qt::CaseSensitive : Qt::CaseInsensitive);
+#else
+ return s.find(c,index,cs);
+#endif
+ }
+
+ inline int find(const QString &s,char c,int index = 0,bool cs = true)
+ {
+#ifdef COMPILE_USE_QT4
+ return s.indexOf(c,index,cs ? Qt::CaseSensitive : Qt::CaseInsensitive);
+#else
+ return s.find(c,index,cs);
+#endif
+ }
+
+ inline int find(const QString &s,const QString & str,int index = 0,bool cs = true)
+ {
+#ifdef COMPILE_USE_QT4
+ return s.indexOf(str,index,cs ? Qt::CaseSensitive : Qt::CaseInsensitive);
+#else
+ return s.find(str,index,cs);
+#endif
+ }
+
+ inline int find(const QString &s,const QRegExp & rx,int index = 0)
+ {
+#ifdef COMPILE_USE_QT4
+ return s.indexOf(rx,index);
+#else
+ return s.find(rx,index);
+#endif
+ }
+
+ inline int find(const QString &s,const char * str,int index = 0)
+ {
+#ifdef COMPILE_USE_QT4
+ return s.indexOf(QString(str),index);
+#else
+ return s.find(str,index);
+#endif
+ }
+
+ inline int findRev(const QString &s,QChar c,int index = -1,bool cs = true)
+ {
+#ifdef COMPILE_USE_QT4
+ return s.lastIndexOf(c,index,cs ? Qt::CaseSensitive : Qt::CaseInsensitive);
+#else
+ return s.findRev(c,index,cs);
+#endif
+ }
+
+ inline int findRev(const QString &s,char c,int index = -1,bool cs = true)
+ {
+#ifdef COMPILE_USE_QT4
+ return s.lastIndexOf(c,index,cs ? Qt::CaseSensitive : Qt::CaseInsensitive);
+#else
+ return s.findRev(c,index,cs);
+#endif
+ }
+
+ inline int findRev(const QString &s,const QString & str,int index = -1,bool cs = true)
+ {
+#ifdef COMPILE_USE_QT4
+ return s.lastIndexOf(str,index,cs ? Qt::CaseSensitive : Qt::CaseInsensitive);
+#else
+ return s.findRev(str,index,cs);
+#endif
+ }
+
+ inline int findRev(const QString &s,const QRegExp & rx,int index = -1)
+ {
+#ifdef COMPILE_USE_QT4
+ return s.lastIndexOf(rx,index);
+#else
+ return s.findRev(rx,index);
+#endif
+ }
+
+ inline int findRev(const QString &s,const char * str,int index = -1)
+ {
+#ifdef COMPILE_USE_QT4
+ return s.lastIndexOf(QString(str),index);
+#else
+ return s.findRev(str,index);
+#endif
+ }
+
+ inline QString trimmed(const QString &s)
+ {
+#ifdef COMPILE_USE_QT4
+ return s.trimmed();
+#else
+ return s.stripWhiteSpace();
+#endif
+ }
+
+ // WARNING: DO NOT USE CONSTRUCTS LIKE char * c = KviQString::toUtf8(something).data();
+ // They are dangerous since with many compilers the returned string gets destroyed
+ // at the end of the instruction and the c pointer gets thus invalidated.
+ // Use
+ // KviQCString tmp = KviQString::toUtf8(something);
+ // char * c = tmp.data();
+ // instead.
+ // Yes, I know that it sucks, but it's the only way to
+ // transit to qt 4.x more or less cleanly...
+ inline KviQCString toUtf8(const QString &s)
+ {
+#ifdef COMPILE_USE_QT4
+ return s.toUtf8();
+#else
+ return s.utf8();
+#endif
+ }
+
+ inline KviQCString toLocal8Bit(const QString &s)
+ {
+ return s.local8Bit();
+ }
+
+ inline kvi_i64_t toI64(QString &szNumber,bool * bOk)
+ {
+#if SIZEOF_LONG_INT == 8
+ return szNumber.toLong(bOk);
+#else
+ return szNumber.toLongLong(bOk);
+#endif
+ }
+
+ inline kvi_u64_t toU64(QString &szNumber,bool * bOk)
+ {
+#if SIZEOF_LONG_INT == 8
+ return szNumber.toULong(bOk);
+#else
+ return szNumber.toULongLong(bOk);
+#endif
+ }
+};
+
+// QT4SUX: Because QString::null is gone. QString() is SLOWER than QString::null since it invokes a constructor and destructor.
+
+#endif //!_KVI_QSTRING_H_
diff --git a/src/kvilib/core/kvi_strasm.h b/src/kvilib/core/kvi_strasm.h
new file mode 100644
index 00000000..5d3b19ca
--- /dev/null
+++ b/src/kvilib/core/kvi_strasm.h
@@ -0,0 +1,194 @@
+#ifndef _KVI_STRASM_H_
+#define _KVI_STRASM_H_
+
+//=============================================================================
+//
+// File : kvi_strasm.h
+// Creation date : Sun Jun 18 2000 18:38:26 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.
+//
+//=============================================================================
+
+//=============================================================================
+//
+// Inline assembly implementations of the commonly used string functions
+// These will work only on i386 based machines and can be compiled
+// only by gcc
+//
+//=============================================================================
+
+extern inline bool kvi_strEqualCS(const char * str1,const char * str2)
+{
+ // An instruction pattern is really useful in this case.
+ // When inlining, GCC can optimize to load esi and edi
+ // directly with the strings , without pushing and getting it
+ // from the stack...
+ register bool eax;
+ __asm__ __volatile__ (
+ " cld\n"
+ "1:\n"
+ " lodsb %%ds:(%%esi),%%al\n"
+ " scasb %%es:(%%edi),%%al\n"
+ " jne 2f\n"
+ " testb %%al,%%al\n"
+ " jne 1b\n"
+ " movl $0x1,%%eax\n"
+ " jmp 3f\n"
+ "2:\n"
+ " xorl %%eax,%%eax\n"
+ "3:"
+ : "=a" (eax), "=&S" (str1), "=&D" (str2)
+ : "1" (str1), "2" (str2)
+ );
+ return eax;
+}
+
+extern inline bool kvi_strEqualCSN(const char * str1,const char * str2,int len)
+{
+ register bool eax;
+ __asm__ __volatile__ (
+ "1:\n"
+ " decl %3\n"
+ " js 2f\n"
+ " movb (%1),%%al\n"
+ " incl %1\n"
+ " cmpb %%al,(%2)\n"
+ " jne 3f\n"
+ " incl %2\n"
+ " testb %%al,%%al\n"
+ " jne 1b\n"
+ "2:\n"
+ " movl $0x1,%%eax\n"
+ " jmp 4f\n"
+ "3:\n"
+ " xorl %%eax,%%eax\n"
+ "4:\n"
+ : "=a" (eax), "=r" (str1), "=r" (str2), "=r" (len)
+ : "1" (str1), "2" (str2), "3" (len)
+ );
+ return eax;
+}
+
+// OPTIMIZATION
+// The following two functions are used to compare a variable string with one in that
+// only A-Z<->a-z case insensivity is significant.
+// For example
+// kvi_strEqualNoLocalCI("a string that does not contain any strange char",str2)
+// will always give the correct result
+// These will NOT work with localizable characters:
+// 'a' with umlaut will be not equal to 'A' with umlaut
+
+extern inline bool kvi_strEqualNoLocaleCI(const char *str1,const char *str2)
+{
+ // Trivial implementation
+ // Ignores completely locales....only A-Z chars are transformed to a-z
+ // Anyway...it will work for IRC :)
+ register int reg;
+ register bool eax;
+ __asm__ __volatile__ (
+ "1:\n"
+ " movb (%2),%%al\n"
+ " cmpb $65,%%al\n"
+ " jb 2f\n"
+ " cmpb $90,%%al\n"
+ " ja 2f\n"
+ " addb $32,%%al\n"
+ "2:\n"
+ " movb (%3),%b1\n"
+ " cmpb $65,%b1\n"
+ " jb 3f\n"
+ " cmpb $90,%b1\n"
+ " ja 3f\n"
+ " addb $32,%b1\n"
+ "3:\n"
+ " cmpb %%al,%b1\n"
+ " jne 4f\n"
+ " incl %2\n"
+ " incl %3\n"
+ " testb %%al,%%al\n"
+ " jne 1b\n"
+ " movl $1,%%eax\n"
+ " jmp 5f\n"
+ "4:\n"
+ " xorl %%eax,%%eax\n"
+ "5:\n"
+ : "=a" (eax), "=q" (reg), "=r" (str1), "=r" (str2)
+ : "2" (str1), "3" (str2)
+ );
+ return eax;
+}
+
+extern inline bool kvi_strEqualNoLocaleCIN(const char *str1,const char *str2,int len)
+{
+
+ register int reg;
+ register bool eax;
+ __asm__ __volatile__ (
+ "1:\n"
+ " decl %4\n"
+ " js 4f\n"
+ " movb (%2),%%al\n"
+ " cmpb $65,%%al\n"
+ " jb 2f\n"
+ " cmpb $90,%%al\n"
+ " ja 2f\n"
+ " addb $32,%%al\n"
+ "2:\n"
+ " movb (%3),%b1\n"
+ " cmpb $65,%b1\n"
+ " jb 3f\n"
+ " cmpb $90,%b1\n"
+ " ja 3f\n"
+ " addb $32,%b1\n"
+ "3:\n"
+ " cmpb %%al,%b1\n"
+ " jne 5f\n"
+ " incl %2\n"
+ " incl %3\n"
+ " testb %%al,%%al\n"
+ " jne 1b\n"
+ "4:\n"
+ " movl $1,%%eax\n"
+ " jmp 6f\n"
+ "5:\n"
+ " xorl %%eax,%%eax\n"
+ "6:\n"
+ : "=a" (eax), "=q" (reg), "=r" (str1), "=r" (str2), "=r" (len)
+ : "2" (str1), "3" (str2), "4" (len)
+ );
+ return eax;
+}
+
+
+extern inline int kvi_strLen(const char * str)
+{
+ register int ecx;
+ __asm__ __volatile__(
+ " cld\n"
+ " repne\n"
+ " scasb\n"
+ " notl %0\n"
+ " decl %0"
+ : "=c" (ecx), "=&D" (str)
+ : "0" (0xffffffff), "1" (str), "a" (0)
+ );
+ return ecx;
+}
+
+#endif //_KVI_STRASM_H_
diff --git a/src/kvilib/core/kvi_string.cpp b/src/kvilib/core/kvi_string.cpp
new file mode 100644
index 00000000..3f201352
--- /dev/null
+++ b/src/kvilib/core/kvi_string.cpp
@@ -0,0 +1,3063 @@
+//=============================================================================
+//
+// File : kvi_string.cpp
+// Creation date : Fri Mar 19 1999 03:20:45 by Szymon Stefanek
+//
+// This file is part of the KVirc irc client distribution
+// Copyright (C) 1999-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.
+//
+//=============================================================================
+
+#define __KVILIB__
+
+
+#define _KVI_DEBUG_CHECK_RANGE_
+#include "kvi_debug.h"
+
+#define _KVI_STRING_CPP_
+#include "kvi_string.h"
+
+#include "kvi_memmove.h"
+#include "kvi_malloc.h"
+
+#include "kvi_qstring.h"
+
+kvi_wslen_t kvi_wstrlen(const kvi_wchar_t * str)
+{
+ const kvi_wchar_t * ptr = str;
+ while(*ptr)ptr++;
+ return (ptr - str);
+}
+
+
+// %s = Latin1 char string (can't be null)
+// %d = signed int (short,char)
+// %u = unsigned int (short,char)
+// %c = char value (kvi_wchar_t value)
+
+// %f = double value
+
+// %w = kvi_wchar_t string (can't be null)
+
+// %S = Latin1 KviStr pointer (#ifdef WSTRINGCONFIG_USE_KVISTR) : can't be NULL!
+// %W = KviWStr pointer : can't be NULL!
+// %Q = QString pointer : can't be NULL!
+
+#define _WSTRING_WMEMCPY(_dst,_src,_len) kvi_fastmoveodd((void *)(_dst),(const void *)(_src),sizeof(kvi_wchar_t) * (_len))
+#define _WSTRING_STRLEN(_str) kvi_strLen(_str)
+
+#define WVSNPRINTF_BODY \
+\
+ register kvi_wchar_t *p; \
+ long int argValue; \
+ unsigned long argUValue; \
+\
+ kvi_wchar_t numberBuffer[32]; \
+ kvi_wchar_t *pNumBuf; \
+ unsigned int tmp; \
+\
+ for(p=buffer ; *fmt ; ++fmt) \
+ { \
+ if(len < 1)return (-1); \
+\
+ if(*fmt != '%') \
+ { \
+ *p++ = *fmt; \
+ --len; \
+ continue; \
+ } \
+\
+ ++fmt; \
+\
+ switch(*fmt) \
+ { \
+ case 's': \
+ { \
+ char * argString = kvi_va_arg(list,char *); \
+ argValue = (int)_WSTRING_STRLEN(argString); \
+ if(len <= argValue)return (-1); \
+ while(*argString)*p++ = *argString++; \
+ len -= argValue; \
+ } \
+ break; \
+ case 'S': \
+ { \
+ KviStr * pString = kvi_va_arg(list,KviStr *); \
+ char * argString = pString->ptr(); \
+ if(len <= ((int)(pString->len())))return (-1); \
+ while(*argString)*p++ = *argString++; \
+ len -= pString->len(); \
+ } \
+ break; \
+ case 'Q': \
+ { \
+ QString * pString = kvi_va_arg(list,QString *); \
+ if(pString->length() > 0) \
+ { \
+ if(len <= ((int)(pString->length())))return (-1); \
+ _WSTRING_WMEMCPY(p,pString->unicode(),pString->length()); \
+ p += pString->length(); \
+ len -= pString->length(); \
+ } \
+ } \
+ break; \
+ case 'd': \
+ argValue = kvi_va_arg(list,int); \
+ if(argValue < 0) \
+ { \
+ *p++ = '-'; \
+ if(--len == 0)return (-1); \
+ argValue = -argValue; \
+ if(argValue < 0)argValue = 0; \
+ } \
+ pNumBuf = numberBuffer; \
+ do { \
+ tmp = argValue / 10; \
+ *pNumBuf++ = argValue - (tmp * 10) + '0'; \
+ } while((argValue = tmp)); \
+ argUValue = pNumBuf - numberBuffer; \
+ if(((unsigned int)len) <= argUValue)return (-1); \
+ do { \
+ *p++ = *--pNumBuf; \
+ } while(pNumBuf != numberBuffer); \
+ len -= argUValue; \
+ break; \
+ case 'u': \
+ argUValue = kvi_va_arg(list,unsigned int); \
+ pNumBuf = numberBuffer; \
+ do { \
+ tmp = argUValue / 10; \
+ *pNumBuf++ = argUValue - (tmp * 10) + '0'; \
+ } while((argUValue = tmp)); \
+ argValue = pNumBuf - numberBuffer; \
+ if(len <= argValue)return (-1); \
+ do { \
+ *p++ = *--pNumBuf; \
+ } while(pNumBuf != numberBuffer); \
+ len -= argValue; \
+ break; \
+ case 'f': \
+ { \
+ double dVal = (double)kvi_va_arg(list,double); \
+ char sprintfBuffer[32]; \
+ argValue = sprintf(sprintfBuffer,"%f",dVal); \
+ if(len <= argValue)return (-1); \
+ char * pSprintfBuffer = sprintfBuffer; \
+ while(*pSprintfBuffer)*p++ = *pSprintfBuffer++; \
+ len -= argValue; \
+ } \
+ break; \
+ case 'c': \
+ *p++ = (kvi_wchar_t)kvi_va_arg(list,int); \
+ --len; \
+ break; \
+ default: \
+ *p++ = '%'; \
+ if(--len == 0)return (-1); \
+ if(*fmt){ \
+ *p++ = *fmt; \
+ --len; \
+ } \
+ break; \
+ } \
+ continue; \
+ } \
+ if(len < 1)return (-1); \
+ *p = 0; \
+ return p-buffer;
+
+int kvi_wvsnprintcf(kvi_wchar_t *buffer,kvi_wslen_t len,const char *fmt,kvi_va_list list)
+{
+ WVSNPRINTF_BODY
+}
+
+int kvi_wvsnprintf(kvi_wchar_t *buffer,kvi_wslen_t len,const kvi_wchar_t *fmt,kvi_va_list list)
+{
+ WVSNPRINTF_BODY
+}
+
+bool kvi_qstringEqualCI(const QString &s1,const QString &s2)
+{
+ const QChar * p1 = s1.unicode();
+ const QChar * p2 = s2.unicode();
+ int l = s1.length() < s2.length() ? s1.length() : s2.length();
+#ifdef COMPILE_USE_QT4
+ while(l-- && (p1->toLower() == p2->toLower()))p1++,p2++;
+#else
+ while(l-- && (p1->lower() == p2->lower()))p1++,p2++;
+#endif
+ if(l==-1)return true;
+ return false;
+}
+
+bool kvi_matchStringCI(register const char * exp,register const char * str)
+{
+ // a
+ // .
+ // exp = a*x?mem*a
+ // str = arexoxmexamemizazv
+ // .
+ // n
+ const char * afterWild = 0;
+ const char * nextStrToCheck = 0;
+
+ while(*exp)
+ {
+ if(*exp == '*')
+ {
+ // exp is a wildcard...
+ afterWild = ++exp;
+ nextStrToCheck = str + 1;
+ if(!(*exp))return true; // and it's the last char in the string: matches everything ahead
+ continue;
+ }
+
+ if(!(*str))return false; // str finished but we had something to match :(
+
+ if(tolower(*exp) == tolower(*str))
+ {
+ // chars matched
+ ++exp;
+ ++str;
+ if((!(*exp)) && *str)goto check_recovery;
+ continue;
+ }
+
+ if(*exp == '?')
+ {
+ // any-char wildcard
+ ++exp;
+ ++str;
+ continue;
+ }
+
+check_recovery:
+ // chars unmatched!!!
+ if(afterWild)
+ {
+ // we had a wildcard in exp...
+ // let's use this jolly then
+ exp = afterWild;
+ str = nextStrToCheck;
+ nextStrToCheck++;
+ // and try to compare now
+ continue;
+ }
+
+ return false; // no match :(
+ }
+ return (!(*str));
+}
+
+
+bool kvi_matchStringCS(register const char * exp,register const char * str)
+{
+ // a
+ // .
+ // exp = a*x?mem*a
+ // str = arexoxmexamemizazv
+ // .
+ // n
+ const char * afterWild = 0;
+ const char * nextStrToCheck = 0;
+
+ while(*exp)
+ {
+ if(*exp == '*')
+ {
+ // exp is a wildcard...
+ afterWild = ++exp;
+ nextStrToCheck = str + 1;
+ if(!(*exp))return true; // and it's the last char in the string: matches everything ahead
+ continue;
+ }
+
+ if(!(*str))return false; // str finished but we had something to match :(
+
+ if(*exp == *str)
+ {
+ // chars matched
+ ++exp;
+ ++str;
+ if((!(*exp)) && *str)goto check_recovery;
+ continue;
+ }
+
+ if(*exp == '?')
+ {
+ // any-char wildcard
+ ++exp;
+ ++str;
+ continue;
+ }
+
+check_recovery:
+ // chars unmatched!!!
+ if(afterWild)
+ {
+ // we had a wildcard in exp...
+ // let's use this jolly then
+ exp = afterWild;
+ str = nextStrToCheck;
+ nextStrToCheck++;
+ // and try to compare now
+ continue;
+ }
+
+ return false; // no match :(
+ }
+ return (!(*str));
+}
+
+
+
+bool kvi_matchStringWithTerminator(register const char * exp,register const char * str,char terminator,const char ** r1,const char ** r2)
+{
+#define NOT_AT_END(__str) (*__str && (*__str != terminator))
+
+ // a
+ // .
+ // exp = a*x?mem*a
+ // str = arexoxmexamemizazv
+ // .
+ // n
+ const char * afterWild = 0;
+ const char * nextStrToCheck = 0;
+
+ while(NOT_AT_END(exp))
+ {
+ if(*exp == '*')
+ {
+ // exp is a wildcard...
+ afterWild = ++exp;
+ nextStrToCheck = str + 1;
+ if(!(NOT_AT_END(exp)))
+ {
+ while(NOT_AT_END(str))str++;
+ *r1 = exp;
+ *r2 = str;
+ return true; // and it's the last char in the string: matches everything ahead
+ }
+ continue;
+ }
+
+ if(!(*str))return false; // str finished but we had something to match :(
+
+ if(tolower(*exp) == tolower(*str))
+ {
+ // chars matched
+ ++exp;
+ ++str;
+ if((!(NOT_AT_END(exp))) && NOT_AT_END(str))goto check_recovery;
+ continue;
+ }
+
+ if(*exp == '?')
+ {
+ // any-char wildcard
+ ++exp;
+ ++str;
+ continue;
+ }
+
+check_recovery:
+ // chars unmatched!!!
+ if(afterWild)
+ {
+ // we had a wildcard in exp...
+ // let's use this jolly then
+ exp = afterWild;
+ str = nextStrToCheck;
+ nextStrToCheck++;
+ // and try to compare now
+ continue;
+ }
+
+ return false; // no match :(
+ }
+ *r1 = exp;
+ *r2 = str;
+ return (!(NOT_AT_END(str)));
+
+#undef NOT_AT_END
+}
+
+bool kvi_matchWildExpr(register const char *m1,register const char *m2)
+{
+ //Matches two regular expressions containging wildcards (* and ?)
+
+ // s1
+ // m1
+ // mask1 : *xor
+ // mask2 : xorand*xor
+ // m2
+ // s2
+
+ // s2
+ // m2
+ // |
+ // XorT!xor@111.111.111.11
+ //
+ // *!*@*.net
+ // |
+ // m1
+ // s1
+ //
+
+ if(!(m1 && m2 && (*m1)))return false;
+ const char * savePos1 = 0;
+ const char * savePos2 = m2;
+ while(*m1)
+ {
+ //loop managed by m1 (initially first mask)
+ if(*m1=='*')
+ {
+ //Found a wildcard in m1
+ savePos1 = ++m1; //move to the next char and save the position...this is our jolly
+ if(!*savePos1)return true; //last was a wildcard , matches everything ahead...
+ savePos2 = m2+1; //next return state for the second string
+ continue; //and return
+ }
+ if(!(*m2))return false; //m2 finished and we had something to match here!
+ if(tolower(*m1)==tolower(*m2))
+ {
+ //chars matched
+ m1++; //Go ahead in the two strings
+ m2++; //
+ if((!(*m1)) && *m2 && savePos1)
+ {
+ //m1 finished , but m2 not yet and we have a savePosition for m1 (there was a wildcard)...
+ //retry matching the string following the * from the savePos2 (one char ahead last time)
+ m1 = savePos1; //back to char after wildcard
+ m2 = savePos2; //back to last savePos2
+ savePos2++; //next savePos2 will be next char
+ }
+ } else {
+ if(*m2 == '*')
+ {
+ //A wlidcard in the second string
+ //Invert the game : mask1 <-> mask2
+ //mask2 now leads the game...
+ savePos1 = m1; //aux
+ m1 = m2; //...swap
+ m2 = savePos1; //...swap
+ savePos1 = m1; //sync save pos1
+ savePos2 = m2 + 1; //sync save pos2
+ continue; //...and again
+ }
+ // m1 != m2 , m1 != * , m2 != *
+ if((*m1 == '?') || (*m2 == '?'))
+ {
+ m1++;
+ m2++;
+ if((!(*m1)) && *m2 && savePos1)
+ {
+ //m1 finished , but m2 not yet and we have a savePosition for m1 (there was a wildcard)...
+ //retry matching the string following the * from the savePos2 (one char ahead last time)
+ m1 = savePos1; //back to char after wildcard
+ m2 = savePos2; //back to last savePos2
+ savePos2++; //next savePos2 will be next char
+ }
+ } else {
+ if(savePos1)
+ {
+ //Have a jolly man...allow not matching...
+ m1 = savePos1; //go back to char after wildcard...need to rematch...
+ m2 = savePos2; //back to last savePos2
+ savePos2++; //and set next savePos2
+ } else return false; //No previous wildcards...not matched!
+ }
+ }
+ }
+ return (!(*m2)); //m1 surely finished , so for the match , m2 must be finished too
+
+}
+
+/*
+
+ WARNING: Don't remove: working code but actually unused in KVIrc
+ Later it might become useful
+
+bool kvi_matchWildExprCS(register const char *m1,register const char *m2)
+{
+ if(!(m1 && m2 && (*m1)))return false;
+ const char * savePos1 = 0;
+ const char * savePos2 = m2;
+ while(*m1){ //loop managed by m1 (initially first mask)
+ if(*m1=='*'){
+ //Found a wildcard in m1
+ savePos1 = ++m1; //move to the next char and save the position...this is our jolly
+ if(!*savePos1)return true; //last was a wildcard , matches everything ahead...
+ savePos2 = m2+1; //next return state for the second string
+ continue; //and return
+ }
+ if(!(*m2))return false; //m2 finished and we had something to match here!
+ if((*m1)==(*m2)){
+ //chars matched
+ m1++; //Go ahead in the two strings
+ m2++; //
+ if((!(*m1)) && *m2 && savePos1){
+ //m1 finished , but m2 not yet and we have a savePosition for m1 (there was a wildcard)...
+ //retry matching the string following the * from the savePos2 (one char ahead last time)
+ m1 = savePos1; //back to char after wildcard
+ m2 = savePos2; //back to last savePos2
+ savePos2++; //next savePos2 will be next char
+ }
+ } else {
+ if(*m2 == '*'){
+ //A wlidcard in the second string
+ //Invert the game : mask1 <-> mask2
+ //mask2 now leads the game...
+ savePos1 = m1; //aux
+ m1 = m2; //...swap
+ m2 = savePos1; //...swap
+ savePos1 = m1; //sync save pos1
+ savePos2 = m2 + 1; //sync save pos2
+ continue; //...and again
+ }
+ if(savePos1){ //Have a jolly man...allow not matching...
+ m1 = savePos1; //go back to char after wildcard...need to rematch...
+ m2 = savePos2; //back to last savePos2
+ savePos2++; //and set next savePos2
+ } else return false; //No previous wildcards...not matched!
+ }
+ }
+ return (!(*m2)); //m1 surely finished , so for the match , m2 must be finished too
+
+}
+*/
+
+bool kvi_matchWildExprWithTerminator(register const char *m1,register const char *m2,char terminator,
+ const char ** r1,const char ** r2)
+{
+ //Matches two regular expressions containging wildcards
+
+#define NOT_AT_END(__str) (*__str && (*__str != terminator))
+
+ bool bSwapped = false;
+ if(!(m1 && m2 && (NOT_AT_END(m1))))return false;
+ const char * savePos1 = 0;
+ const char * savePos2 = m2;
+ while(NOT_AT_END(m1))
+ {
+ //loop managed by m1 (initially first mask)
+ if(*m1=='*')
+ {
+ //Found a wildcard in m1
+ savePos1 = ++m1; //move to the next char and save the position...this is our jolly
+ if(!NOT_AT_END(savePos1))
+ {
+ //last was a wildcard , matches everything ahead...
+ while(NOT_AT_END(m2))m2++;
+ *r1 = bSwapped ? m2 : m1;
+ *r2 = bSwapped ? m1 : m2;
+ return true;
+ }
+ savePos2 = m2+1; //next return state for the second string
+ continue; //and return
+ }
+ if(!NOT_AT_END(m2))return false; //m2 finished and we had something to match here!
+ if(tolower(*m1)==tolower(*m2))
+ {
+ //chars matched
+ m1++; //Go ahead in the two strings
+ m2++; //
+ if((!NOT_AT_END(m1)) && NOT_AT_END(m2) && savePos1)
+ {
+ //m1 finished , but m2 not yet and we have a savePosition for m1 (there was a wildcard)...
+ //retry matching the string following the * from the savePos2 (one char ahead last time)
+ m1 = savePos1; //back to char after wildcard
+ m2 = savePos2; //back to last savePos2
+ savePos2++; //next savePos2 will be next char
+ }
+ } else {
+ if(*m2 == '*')
+ {
+ //A wlidcard in the second string
+ //Invert the game : mask1 <-> mask2
+ //mask2 now leads the game...
+ bSwapped = !bSwapped;
+ savePos1 = m1; //aux
+ m1 = m2; //...swap
+ m2 = savePos1; //...swap
+ savePos1 = m1; //sync save pos1
+ savePos2 = m2 + 1; //sync save pos2
+ continue; //...and again
+ }
+ // m1 != m2 , m1 != * , m2 != *
+ if((*m1 == '?') || (*m2 == '?'))
+ {
+ m1++;
+ m2++;
+ if((!NOT_AT_END(m1)) && NOT_AT_END(m2) && savePos1)
+ {
+ //m1 finished , but m2 not yet and we have a savePosition for m1 (there was a wildcard)...
+ //retry matching the string following the * from the savePos2 (one char ahead last time)
+ m1 = savePos1; //back to char after wildcard
+ m2 = savePos2; //back to last savePos2
+ savePos2++; //next savePos2 will be next char
+ }
+ } else {
+ if(savePos1)
+ {
+ //Have a jolly man...allow not matching...
+ m1 = savePos1; //go back to char after wildcard...need to rematch...
+ m2 = savePos2; //back to last savePos2
+ savePos2++; //and set next savePos2
+ } else return false; //No previous wildcards...not matched!
+ }
+ }
+ }
+ *r1 = bSwapped ? m2 : m1;
+ *r2 = bSwapped ? m1 : m2;
+
+ return (!NOT_AT_END(m2)); //m1 surely finished , so for the match , m2 must be finished too
+
+#undef NOT_AT_END
+}
+
+
+
+const char * kvi_extractToken(KviStr &str,const char *aux_ptr,char sep)
+{
+ __range_valid(aux_ptr);
+ while(*aux_ptr && (*aux_ptr == sep))aux_ptr++;
+ const char *p=aux_ptr;
+ while(*p && (*p != sep))p++;
+ str.m_len=p-aux_ptr;
+ str.m_ptr = (char *)kvi_realloc(str.m_ptr,str.m_len+1);
+ kvi_fastmove(str.m_ptr,aux_ptr,str.m_len);
+ *(str.m_ptr+str.m_len)='\0';
+ while(*p && (*p == sep))p++;
+ return p;
+}
+
+const char * kvi_extractUpTo(KviStr &str,const char *aux_ptr,char sep)
+{
+ __range_valid(aux_ptr);
+ const char *p=aux_ptr;
+ while(*p && (*p != sep))p++;
+ str.m_len=p-aux_ptr;
+ str.m_ptr = (char *)kvi_realloc(str.m_ptr,str.m_len+1);
+ kvi_fastmove(str.m_ptr,aux_ptr,str.m_len);
+ *(str.m_ptr+str.m_len)='\0';
+ return p;
+}
+
+int kvi_vsnprintf(char *buffer,int len,const char *fmt,kvi_va_list list)
+{
+ __range_valid(fmt);
+ __range_valid(buffer);
+ __range_valid(len > 0); //printing 0 characters is senseless
+
+ register char *p;
+ char *argString;
+ long argValue;
+ unsigned long argUValue;
+
+ //9999999999999999999999999999999\0
+ char numberBuffer[32]; //enough ? 10 is enough for 32bit unsigned int...
+ char *pNumBuf;
+ unsigned int tmp;
+
+
+ for(p=buffer ; *fmt ; ++fmt)
+ {
+ if(len < 1)return (-1); //not enough space ... (in fact this could be len < 2 for the terminator)
+ //copy up to a '%'
+ if(*fmt != '%')
+ {
+ *p++ = *fmt;
+ --len;
+ continue;
+ }
+
+ ++fmt; //skip this '%'
+ switch(*fmt)
+ {
+ case 's': //string
+ argString = kvi_va_arg(list,char *);
+ if(!argString)continue;
+ argValue = (long)strlen(argString);
+ //check for space...
+ if(len <= argValue)return (-1); //not enough space for buffer and terminator
+ while(*argString)*p++ = *argString++;
+ len -= argValue;
+ continue;
+ case 'd': //signed integer
+ argValue = kvi_va_arg(list,int);
+ if(argValue < 0){ //negative integer
+ *p++ = '-';
+ if(--len == 0)return (-1);
+ argValue = -argValue; //need to have it positive
+ // most negative integer exception (avoid completely senseless (non digit) responses)
+ if(argValue < 0)argValue = 0; //we get -0 here
+ }
+ //write the number in a temporary buffer
+ pNumBuf = numberBuffer;
+ do {
+ tmp = argValue / 10;
+ *pNumBuf++ = argValue - (tmp * 10) + '0';
+ } while((argValue = tmp));
+ //copy now....
+ argUValue = pNumBuf - numberBuffer; //length of the number string
+ if(((uint)len) <= argUValue)return (-1); //not enough space for number and terminator
+ do { *p++ = *--pNumBuf; } while(pNumBuf != numberBuffer);
+ len -= argUValue;
+ continue;
+ case 'u': //unsigned integer
+ argUValue = kvi_va_arg(list,unsigned int); //many implementations place int here
+ //write the number in a temporary buffer
+ pNumBuf = numberBuffer;
+ do {
+ tmp = argUValue / 10;
+ *pNumBuf++ = argUValue - (tmp * 10) + '0';
+ } while((argUValue = tmp));
+ //copy now....
+ argValue = pNumBuf - numberBuffer; //length of the number string
+ if(len <= argValue)return (-1); //not enough space for number and terminator
+ do { *p++ = *--pNumBuf; } while(pNumBuf != numberBuffer);
+ len -= argValue;
+ continue;
+ case 'c': //char
+ //
+ // I'm not sure about this...
+ // In the linux kernel source the
+ // unsigned char is extracted from an integer type.
+ // We assume that gcc stacks a char argument
+ // as sizeof(int) bytes value.
+ // Is this always true ?
+ //
+ *p++ = (char)kvi_va_arg(list,int);
+ --len;
+ continue;
+ case 'Q': // QString! (this should almost never happen)
+ {
+ QString * s = kvi_va_arg(list,QString *);
+ KviQCString cs = KviQString::toUtf8(*s);
+ const char * t = cs.data();
+ if(!t)continue; // nothing to do
+ //check for space...
+ if(len <= (int)cs.length())return (-1); //not enough space for buffer and terminator
+ while(*t)*p++ = *t++;
+ len -= cs.length();
+ continue;
+ }
+ default: //a normal percent
+ *p++ = '%'; //write it
+ if(--len == 0)return (-1); //not enough space for next char or terminator
+ if(*fmt){ //this if is just in case that we have a % at the end of the string.
+ *p++ = *fmt; //and write this char
+ --len;
+ }
+ continue;
+ }
+ }
+ if(len < 1)return (-1); //missing space for terminator
+ *p = '\0';
+ return p-buffer;
+}
+
+//
+// Nearly the same as the above function...
+//
+
+int kvi_irc_vsnprintf(char *buffer,const char *fmt,kvi_va_list list,bool *bTruncated)
+{
+ __range_valid(fmt);
+ __range_valid(buffer);
+ if( !( buffer && fmt) ) return false;
+ register char *p;
+ char *argString;
+ long argValue;
+ unsigned long argUValue;
+ char numberBuffer[64]; //enough ? 10 is enough for 32bit unsigned int...
+ char *pNumBuf;
+ unsigned int tmp;
+ *bTruncated = false;
+ int len = 512;
+
+ for (p=buffer ; *fmt ; ++fmt) {
+ if(len < 3)goto truncate;
+ //copy up to a '%'
+ if (*fmt != '%') {
+ *p++ = *fmt;
+ --len;
+ continue;
+ }
+ ++fmt; //skip this '%'
+ switch(*fmt){
+ case 's': //string
+ argString = kvi_va_arg(list,char *);
+ if(!argString)continue;
+ //check for space...
+ while(*argString){
+ *p++ = *argString++;
+ if(--len < 3)goto truncate;
+ }
+ continue;
+ case 'Q': // QString! (this should almost never happen)
+ {
+ QString * s = kvi_va_arg(list,QString *);
+ KviQCString cs = KviQString::toUtf8(*s);
+ const char * t = cs.data();
+ if(!t)continue; // nothing to do
+ while(*t)
+ {
+ *p++ = *t++;
+ if(--len < 3)goto truncate;
+ }
+ continue;
+ }
+ case 'd': //signed integer
+ argValue = kvi_va_arg(list,int);
+ if(argValue < 0){ //negative integer
+ *p++ = '-';
+ if(--len < 3)goto truncate; //place just for CRLF
+ argValue = -argValue; //need to have it positive
+ if(argValue < 0)argValue = 0; // -0 (hack the exception)
+ }
+ //write the number in a temporary buffer
+ pNumBuf = numberBuffer;
+ do {
+ tmp = argValue / 10;
+ *pNumBuf++ = argValue - (tmp * 10) + '0';
+ } while((argValue = tmp));
+ //copy now....
+ do {
+ *p++ = *--pNumBuf;
+ if(--len < 3)goto truncate;
+ } while(pNumBuf != numberBuffer);
+ continue;
+ case 'u': //unsigned integer
+ argUValue = kvi_va_arg(list,unsigned int); //many implementations place int here
+ //write the number in a temporary buffer
+ pNumBuf = numberBuffer;
+ do {
+ tmp = argUValue / 10;
+ *pNumBuf++ = argUValue - (tmp * 10) + '0';
+ } while((argUValue = tmp));
+ //copy now....
+ if(--len < 3)goto truncate; //no place for digits
+ do {
+ *p++ = *--pNumBuf;
+ if(--len < 3)goto truncate;
+ } while(pNumBuf != numberBuffer);
+ continue;
+ case 'c': //char
+ *p++ = (char)kvi_va_arg(list,int);
+ --len;
+ continue;
+ default: //a normal percent
+ *p++ = '%'; //write it
+ if(--len < 3)goto truncate; //not enough space for next char
+ if(*fmt){ //this if is just in case that we have a % at the end of the string.
+ *p++ = *fmt; //and write this char
+ --len;
+ }
+ continue;
+ }
+ }
+ //succesfull finish
+ __range_valid(len >= 2);
+ *p++ = '\r';
+ *p = '\n';
+ return ((p-buffer)+1);
+truncate:
+ __range_valid(len >= 2);
+ *bTruncated = true;
+ *p++ = '\r';
+ *p = '\n';
+ return ((p-buffer)+1);
+}
+
+#ifndef COMPILE_ix86_ASM
+
+bool kvi_strEqualCS(const char *str1,const char *str2)
+{
+ __range_valid(str1);
+ __range_valid(str2);
+ if( !( str1 && str2 ) ) return false;
+ register unsigned char *s1 = (unsigned char *)str1;
+ register unsigned char *s2 = (unsigned char *)str2;
+ while(*s1)if(*s1++ != *s2++)return false;
+ return (*s1 == *s2);
+}
+
+bool kvi_strEqualCSN(const char *str1,const char *str2,int len)
+{
+ __range_valid(str1);
+ __range_valid(str2);
+ __range_valid(len >= 0);
+ if( !( str1 && str2 && (len >= 0) ) ) return false;
+ register unsigned char *s1 = (unsigned char *)str1;
+ register unsigned char *s2 = (unsigned char *)str2;
+ while(len-- && *s1)if(*s1++ != *s2++)return false;
+ return (len < 0);
+}
+
+#endif
+
+bool kvi_strEqualCIN(const char *str1,const char *str2,int len)
+{
+ __range_valid(str1);
+ __range_valid(str2);
+ __range_valid(len >= 0);
+ if( !( str1 && str2 && (len >= 0) ) ) return false;
+ register unsigned char *s1 = (unsigned char *)str1;
+ register unsigned char *s2 = (unsigned char *)str2;
+ while(len-- && *s1)if(tolower(*s1++) != tolower(*s2++))return false;
+ return (len < 0);
+}
+
+bool kvi_strEqualCI(const char *str1,const char *str2)
+{
+ __range_valid(str1);
+ __range_valid(str2);
+ if( !( str1 && str2) ) return false;
+ register unsigned char *s1 = (unsigned char *)str1;
+ register unsigned char *s2 = (unsigned char *)str2;
+ while(*s1)if(tolower(*s1++) != tolower(*s2++))return false;
+ return (*s1 == *s2);
+}
+
+//note that greater here means that come AFTER in the alphabetic order
+// return < 0 ---> str1 < str2
+// return = 0 ---> str1 = str2
+// return > 0 ---> str1 > str2
+int kvi_strcmpCI(const char *str1,const char *str2)
+{
+ //abcd abce
+ __range_valid(str1);
+ __range_valid(str2);
+ if( !( str1 && str2) ) return false;
+ register unsigned char *s1 = (unsigned char *)str1;
+ register unsigned char *s2 = (unsigned char *)str2;
+ int diff;
+ unsigned char rightchar;
+ while(!(diff=(rightchar=tolower(*s1++)) - tolower(*s2++)))if(!rightchar)break;
+ return diff; //diff is nonzero or end of both was reached (it is positive if *s2 > *s1
+}
+
+//
+////note that greater here means that come AFTER in the alphabetic order
+//// return < 0 ---> str1 < str2
+//// return = 0 ---> str1 = str2
+//// return > 0 ---> str1 > str2
+//int kvi_strcmpCIN(const char *str1,const char *str2,int len)
+//{
+// //abcd abce
+// __range_valid(str1);
+// __range_valid(str2);
+// register unsigned char *s1 = (unsigned char *)str1;
+// register unsigned char *s2 = (unsigned char *)str2;
+// int diff;
+// unsigned char rightchar;
+// while(len--)
+// {
+// if(!(diff=(rightchar=tolower(*s1++)) - tolower(*s2++)))break;
+// if(!rightchar)break;
+// }
+// return diff; //diff is nonzero or end of both was reached (it is positive if *s2 > *s1
+//}
+
+int kvi_strcmpCS(const char *str1,const char *str2)
+{
+ //abcd abce
+ __range_valid(str1);
+ __range_valid(str2);
+ if( !( str1 && str2) ) return false;
+ register unsigned char *s1 = (unsigned char *)str1;
+ register unsigned char *s2 = (unsigned char *)str2;
+ int diff;
+ while(!(diff=(*s1)-(*s2++)))if(!*s1++)break;
+ return diff; //diff is nonzero or end of both was reached (it is positive if *s2 > *s1
+}
+
+int kvi_strMatchRevCS(const char *str1, const char *str2, int index)
+{
+ __range_valid(str1);
+ __range_valid(str2);
+ if( !( str1 && str2) ) return false;
+ register char *s1=(char *)str1;
+ register char *s2=(char *)str2;
+
+ int curlen=(int)strlen(str1);
+ int diff;
+
+ if (index<0 || index >= curlen) index = curlen-1;
+
+ s1+=index;
+ while (*s2) s2++;
+ s2--;
+
+ // now start comparing
+ while (1){
+ /* in this case, we have str1 = "lo" and str2 = "hello" */
+ if (s1<str1 && !(s2<str2)) return 256;
+ if (s2<str2) return 0;
+ if ((diff=(*s1)-(*s2))) return diff;
+ s1--;
+ s2--;
+ }
+}
+
+KviStr::KviStr()
+{
+ m_ptr = (char *)kvi_malloc(1);
+ *m_ptr = '\0';
+ m_len = 0;
+}
+
+KviStr::KviStr(const char *str)
+{
+ //Deep copy constructor
+ if(str){
+ //Deep copy
+ m_len = (int)strlen(str);
+ m_ptr = (char *)kvi_malloc(m_len+1);
+ kvi_fastmove(m_ptr,str,m_len+1);
+ } else {
+ m_ptr = (char *)kvi_malloc(1);
+ *m_ptr = '\0';
+ m_len = 0;
+ }
+}
+
+KviStr::KviStr(const KviQCString &str)
+{
+ //Deep copy constructor
+ if(str.data())
+ {
+ //Deep copy
+ m_len = str.length();
+ m_ptr = (char *)kvi_malloc(m_len+1);
+ kvi_fastmove(m_ptr,str,m_len+1);
+ } else {
+ m_ptr = (char *)kvi_malloc(1);
+ *m_ptr = '\0';
+ m_len = 0;
+ }
+}
+
+
+KviStr::KviStr(const char *str,int len)
+{
+ __range_valid(str);
+ //__range_valid(len <= ((int)strlen(str))); <-- we trust the user here (and a strlen() call may run AFTER len if data is not null terminated)
+ __range_valid(len >= 0);
+ m_len = len;
+ m_ptr = (char *)kvi_malloc(m_len+1);
+ kvi_fastmove(m_ptr,str,m_len);
+ *(m_ptr+m_len) = '\0';
+}
+
+KviStr::KviStr(const char *bg,const char *end)
+{
+ __range_valid(bg);
+ __range_valid(end);
+ __range_valid(bg <= end);
+ m_len = end-bg;
+ m_ptr = (char *)kvi_malloc(m_len +1);
+ kvi_fastmove(m_ptr,bg,m_len);
+ *(m_ptr + m_len)='\0';
+}
+
+KviStr::KviStr(KviFormatConstructorTag tag,const char *fmt,...)
+{
+ m_ptr=(char *)kvi_malloc(256);
+ //First try
+ kvi_va_list list;
+ kvi_va_start(list,fmt);
+ //print...with max 256 chars
+ m_len=kvi_vsnprintf(m_ptr,256,fmt,list);
+ kvi_va_end(list);
+
+ //check if we failed
+ if(m_len < 0){
+ //yes , failed....
+ int dummy=256;
+ do{ //we failed , so retry with 256 more chars
+ dummy+=256;
+ //realloc
+ m_ptr=(char *)kvi_realloc(m_ptr,dummy);
+ //print...
+ kvi_va_start(list,fmt);
+ m_len=kvi_vsnprintf(m_ptr,dummy,fmt,list);
+ kvi_va_end(list);
+ } while(m_len < 0);
+ }
+ //done...
+ //now m_len is the length of the written string not including the terminator...
+ //perfect! :)
+ m_ptr=(char *)kvi_realloc(m_ptr,m_len+1);
+}
+
+KviStr::KviStr(const KviStr &str)
+{
+ __range_valid(str.m_ptr);
+ m_len = str.m_len;
+ m_ptr = (char *)kvi_malloc(m_len+1);
+ kvi_fastmove(m_ptr,str.m_ptr,m_len+1);
+}
+
+KviStr::KviStr(const QString &str)
+{
+ KviQCString sz = KviQString::toUtf8(str);
+ if(sz.length() > 0)
+ {
+ m_len = sz.length();
+ m_ptr = (char *)kvi_malloc(m_len+1);
+ kvi_fastmove(m_ptr,sz.data(),m_len+1);
+ } else {
+ m_ptr = (char *)kvi_malloc(1);
+ *m_ptr = '\0';
+ m_len = 0;
+ }
+}
+
+KviStr::KviStr(char c,int fillLen)
+{
+ __range_valid(fillLen >= 0);
+ m_len = fillLen;
+ m_ptr = (char *)kvi_malloc(m_len+1);
+ register char *p=m_ptr;
+ while(fillLen--)*p++=c;
+ *p='\0';
+}
+
+
+KviStr::KviStr(const kvi_wchar_t * unicode)
+{
+ if(!unicode)
+ {
+ m_len = 0;
+ m_ptr = (char *)kvi_malloc(1);
+ *m_ptr = 0;
+ } else {
+ m_len = kvi_wstrlen(unicode);
+ m_ptr = (char *)kvi_malloc(m_len + 1);
+ register char * p = m_ptr;
+ while(*unicode)*p++ = *unicode++;
+ *p = 0;
+ }
+}
+
+KviStr::KviStr(const kvi_wchar_t * unicode,int len)
+{
+ m_len = len;
+ m_ptr = (char *)kvi_malloc(m_len + 1);
+ register char * p = m_ptr;
+ char * end = p + len;
+ while(p != end)
+ {
+ *p++ = *unicode++;
+ }
+ *p = 0;
+}
+
+
+
+
+KviStr::~KviStr()
+{
+ kvi_free(m_ptr);
+}
+
+void KviStr::setLength(int iLen)
+{
+ __range_valid(iLen >= 0);
+ m_len = iLen;
+ m_ptr = (char *)kvi_realloc(m_ptr,m_len+1);
+ *(m_ptr + m_len) = '\0';
+}
+
+KviStr & KviStr::operator=(const KviStr &str)
+{
+ __range_valid(str.m_ptr);
+ __range_valid(str.m_ptr != m_ptr);
+ m_len = str.m_len;
+ m_ptr = (char *)kvi_realloc(m_ptr,m_len+1);
+ kvi_fastmove(m_ptr,str.m_ptr,m_len+1);
+ return (*this);
+}
+
+KviStr & KviStr::operator=(const KviQCString &str)
+{
+ m_len = str.length();
+ m_ptr = (char *)kvi_realloc(m_ptr,m_len+1);
+ if(str.data())kvi_fastmove(m_ptr,str.data(),m_len+1);
+ else *m_ptr = 0;
+ return (*this);
+}
+
+KviStr & KviStr::operator=(const char *str)
+{
+ //__range_valid(str);
+ if(str){
+ m_len = (int)strlen(str);
+ m_ptr = (char *)kvi_realloc(m_ptr,m_len+1);
+ kvi_memmove(m_ptr,str,m_len+1);
+ } else {
+ m_ptr = (char *)kvi_realloc(m_ptr,1);
+ *m_ptr = '\0';
+ m_len = 0;
+ }
+ return (*this);
+}
+
+void KviStr::clear()
+{
+ m_ptr = (char *)kvi_realloc(m_ptr,1);
+ *m_ptr = '\0';
+ m_len = 0;
+}
+
+
+bool KviStr::hasNonWhiteSpaceData() const
+{
+ const char * aux = m_ptr;
+ while(*aux)
+ {
+ if(((*aux) != ' ') && ((*aux) != '\t'))return true;
+ aux++;
+ }
+ return false;
+}
+
+static char hexdigits[16] = { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' };
+
+void KviStr::bufferToHex(const char *buffer,int len)
+{
+ __range_valid(buffer);
+ m_len = (len * 2);
+ m_ptr = (char *)kvi_realloc(m_ptr,m_len + 1);
+ char * aux = m_ptr;
+ while(len)
+ {
+ *aux = hexdigits[(unsigned int)(((unsigned char)(*buffer)) / 16)];
+ aux++;
+ *aux = hexdigits[(unsigned int)(((unsigned char)(*buffer)) % 16)];
+ aux++;
+ len--;
+ buffer++;
+ }
+ *(m_ptr+m_len) = '\0';
+}
+
+
+
+static char get_decimal_from_hex_digit_char(char dgt)
+{
+ if((dgt >= '0') && (dgt <= '9'))return (dgt - '0');
+ if((dgt >= 'A') && (dgt <= 'F'))return (10 + (dgt - 'A'));
+ if((dgt >= 'a') && (dgt <= 'f'))return (10 + (dgt - 'a'));
+ return -1;
+}
+
+// This is just error-correcting...it treats non hex stuff as zeros
+/*
+static inline char get_decimal_from_hex_digit_char(char dgt)
+{
+ char c = pedantic_get_decimal_from_hex_digit(dgt);
+ if(c == -1)return 0;
+ return c;
+}
+
+int KviStr::hexToBuffer(char ** buffer,bool bNullToNewlines)
+{
+ int len;
+ if(m_len % 2)len = (m_len / 2) + 1;
+ else len = (m_len / 2);
+ *buffer = (char *)kvi_malloc(len);
+
+ char * ptr = *buffer;
+
+ char * aux = m_ptr;
+ while(*aux)
+ {
+ *ptr = get_decimal_from_hex_digit_char(*aux) * 16;
+ aux++;
+ if(*aux)
+ {
+ *ptr += get_decimal_from_hex_digit_char(*aux);
+ aux++;
+ }
+ if(bNullToNewlines)if(!(*ptr))*ptr = '\n';
+ ptr++;
+ }
+ return len;
+}
+*/
+
+int KviStr::hexToBuffer(char ** buffer,bool bNullToNewlines)
+{
+ *buffer = 0;
+ if((m_len == 0) || (m_len & 1))return -1; // this is an error
+ int len = (m_len / 2);
+ if(len < 1)return -1;
+ *buffer = (char *)kvi_malloc(len);
+
+ char * ptr = *buffer;
+ char * aux = m_ptr;
+
+ char aux2;
+
+ while(*aux)
+ {
+ *ptr = get_decimal_from_hex_digit_char(*aux) * 16;
+ if(*ptr == -1)
+ {
+ kvi_free(*buffer);
+ *buffer = 0;
+ return -1;
+ }
+ aux++;
+ aux2 = get_decimal_from_hex_digit_char(*aux);
+ if(aux2 == -1)
+ {
+ kvi_free(*buffer);
+ *buffer = 0;
+ return -1;
+ }
+ *ptr += aux2;
+ aux++;
+ if(bNullToNewlines)if(!(*ptr))*ptr = '\n';
+ ptr++;
+ }
+ return len;
+}
+
+static const char * base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+
+void KviStr::bufferToBase64(const char * buffer,int len)
+{
+ m_len = (len / 3) << 2;
+ if(len % 3)m_len += 4;
+
+ m_ptr = (char *)kvi_realloc(m_ptr,m_len + 1);
+
+ unsigned char aux1,aux2,aux3;
+ char * aux_ptr = m_ptr;
+ while(len > 2)
+ {
+ aux1 = (unsigned char)*buffer++;
+ aux2 = (unsigned char)*buffer++;
+ aux3 = (unsigned char)*buffer++;
+ *aux_ptr++ = base64_chars[(aux1 & 0xFC) >> 2];
+ *aux_ptr++ = base64_chars[((aux1 & 0x03) << 4) | ((aux2 & 0xF0) >> 4)];
+ *aux_ptr++ = base64_chars[((aux2 & 0x0F) << 2) | ((aux3 & 0xC0) >> 6)];
+ *aux_ptr++ = base64_chars[(aux3 & 0x3F)];
+ len -= 3;
+ }
+ switch(len)
+ {
+ case 2:
+ aux1 = (unsigned char)*buffer++;
+ aux2 = (unsigned char)*buffer++;
+ *aux_ptr++ = base64_chars[(aux1 & 0xFC) >> 2];
+ *aux_ptr++ = base64_chars[((aux1 & 0x03) << 4) | ((aux2 & 0xF0) >> 4)];
+ *aux_ptr++ = base64_chars[((aux2 & 0x0F) << 2)];
+ *aux_ptr++ = '=';
+ break;
+ case 1:
+ aux1 = (unsigned char)*buffer++;
+ aux2 = (unsigned char)*buffer++;
+ *aux_ptr++ = base64_chars[(aux1 & 0xFC) >> 2];
+ *aux_ptr++ = base64_chars[((aux1 & 0x03) << 4)];
+ *aux_ptr++ = '=';
+ *aux_ptr++ = '=';
+ break;
+ }
+ *aux_ptr = 0;
+}
+
+static unsigned char get_base64_idx(char base64)
+{
+ if((base64 >= 'A') && (base64 <= 'Z'))return (base64 - 'A');
+ if((base64 >= 'a') && (base64 <= 'z'))return ((base64 - 'a') + 26);
+ if((base64 >= '0') && (base64 <= '9'))return ((base64 - '0') + 52);
+ if(base64 == '+')return 62;
+ if(base64 == '/')return 63;
+ if(base64 == '=')return 64;
+ return 65;
+}
+
+
+int KviStr::base64ToBuffer(char ** buffer,bool bNullToNewlines)
+{
+ *buffer = 0;
+ if((m_len == 0) || (m_len & 3))return -1; // this is an error
+ int len = (m_len >> 2) * 3;
+ *buffer = (char *)kvi_malloc(len);
+
+ char * auxBuf = *buffer;
+
+ unsigned char aux1,aux2,aux3,aux4;
+ char * aux_ptr = m_ptr;
+
+ int newLen = len;
+
+ while(*aux_ptr)
+ {
+ if(newLen != len)
+ {
+ // ops... there was a padding and we still have chars after it
+ // this is an error
+ kvi_free(*buffer);
+ *buffer = 0;
+ return -1;
+ }
+ aux1 = get_base64_idx(*aux_ptr++);
+ aux2 = get_base64_idx(*aux_ptr++);
+ aux3 = get_base64_idx(*aux_ptr++);
+ aux4 = get_base64_idx(*aux_ptr++);
+ if((aux3 > 64) || (aux4 > 64))
+ {
+ // error
+ kvi_free(*buffer);
+ *buffer = 0;
+ return -1;
+ }
+ if((aux1 | aux2) > 63)
+ {
+ // again error...impossible padding
+ kvi_free(*buffer);
+ *buffer = 0;
+ return -1;
+ }
+ if(aux4 == 64)
+ {
+ if(aux3 == 64)
+ {
+ // Double padding, only one digit here
+ *auxBuf++ = (char)((aux1 << 2) | (aux2 >> 4));
+ newLen -= 2;
+ } else {
+ // Single padding, two digits here
+ *auxBuf++ = (char)((aux1 << 2) | (aux2 >> 4)); // >> 4 is a shr , not a ror! :)
+ *auxBuf++ = (char)((aux2 << 4) | (aux3 >> 2));
+ newLen -= 1;
+ }
+ } else {
+ if(aux3 == 64)
+ {
+ // error... impossible padding
+ kvi_free(*buffer);
+ *buffer = 0;
+ return -1;
+ } else {
+ // Ok , no padding, three digits here
+ *auxBuf++ = (char)((aux1 << 2) | (aux2 >> 4));
+ *auxBuf++ = (char)((aux2 << 4) | (aux3 >> 2));
+ *auxBuf++ = (char)((aux3 << 6) | aux4);
+ }
+ }
+ }
+
+ if(newLen != len)*buffer = (char *)kvi_realloc(*buffer,newLen);
+ return newLen;
+}
+
+KviStr & KviStr::setStr(const char *str,int len)
+{
+ if(!str)
+ {
+ clear();
+ return *this;
+ }
+ int alen = (int)strlen(str);
+ if((len < 0) || (len > alen))m_len = alen;
+ else m_len = len;
+ m_ptr = (char *)kvi_realloc(m_ptr,m_len+1);
+ kvi_memmove(m_ptr,str,m_len);
+ *(m_ptr+m_len) = '\0';
+ return (*this);
+}
+
+KviStr & KviStr::operator=(const QString &str)
+{
+ KviQCString sz = KviQString::toUtf8(str);
+ if(sz.length() > 0){
+ m_len = sz.length();
+ m_ptr = (char *)kvi_realloc(m_ptr,m_len+1);
+ kvi_fastmove(m_ptr,sz.data(),m_len+1);
+ } else {
+ m_ptr = (char *)kvi_realloc(m_ptr,1);
+ *m_ptr = '\0';
+ m_len = 0;
+ }
+ return (*this);
+}
+
+KviStr & KviStr::operator=(char c)
+{
+ m_len = 1;
+ m_ptr = (char *)kvi_realloc(m_ptr,2);
+ *m_ptr = c;
+ *(m_ptr+1)='\0';
+ return (*this);
+}
+
+void KviStr::append(char c)
+{
+ m_ptr = (char *)kvi_realloc(m_ptr,m_len+2);
+ *(m_ptr+m_len)=c;
+ m_len++;
+ *(m_ptr+m_len)='\0';
+}
+
+void KviStr::append(const KviStr &str)
+{
+ __range_valid(str.m_ptr);
+ m_ptr = (char *)kvi_realloc(m_ptr,m_len+str.m_len+1);
+ kvi_fastmove((m_ptr+m_len),str.m_ptr,str.m_len+1);
+ m_len += str.m_len;
+}
+
+void KviStr::append(const char *str)
+{
+ if(!str)return;
+ int len = (int)strlen(str);
+ m_ptr = (char *)kvi_realloc(m_ptr,m_len+len+1);
+ kvi_fastmove((m_ptr+m_len),str,len+1);
+ m_len += len;
+}
+
+void KviStr::append(const QString &str)
+{
+ KviQCString sz = KviQString::toUtf8(str);
+ if(sz.length() < 1)return;
+ m_ptr = (char *)kvi_realloc(m_ptr,m_len+sz.length()+1);
+ kvi_fastmove((m_ptr+m_len),sz.data(),sz.length()+1);
+ m_len += sz.length();
+}
+
+void KviStr::append(const char *str,int len)
+{
+ __range_valid(str);
+// __range_valid(len <= ((int)strlen(str)));
+ __range_valid(len >= 0);
+ m_ptr = (char *)kvi_realloc(m_ptr,m_len+len+1);
+ kvi_fastmove((m_ptr+m_len),str,len);
+ m_len += len;
+ *(m_ptr + m_len)='\0';
+}
+
+void KviStr::append(KviFormatConstructorTag tag,const char *fmt,...)
+{
+ int auxLen;
+ m_ptr=(char *)kvi_realloc(m_ptr,m_len + 256);
+ //First try
+ kvi_va_list list;
+ kvi_va_start(list,fmt);
+ //print...with max 256 chars
+ auxLen =kvi_vsnprintf(m_ptr + m_len,256,fmt,list);
+ kvi_va_end(list);
+
+ //check if we failed
+ if(auxLen < 0){
+ //yes , failed....
+ int dummy=256;
+ do{ //we failed , so retry with 256 more chars
+ dummy+=256;
+ //realloc
+ m_ptr=(char *)kvi_realloc(m_ptr,m_len + dummy);
+ //print...
+ kvi_va_start(list,fmt);
+ auxLen=kvi_vsnprintf(m_ptr + m_len,dummy,fmt,list);
+ kvi_va_end(list);
+ } while(auxLen < 0);
+ }
+ m_len += auxLen;
+ //done...
+ //now m_len is the length of the written string not including the terminator...
+ //perfect! :)
+ m_ptr=(char *)kvi_realloc(m_ptr,m_len+1);
+}
+
+void KviStr::extractFromString(const char *begin,const char *end)
+{
+ __range_valid(begin);
+ __range_valid(end);
+ __range_valid(end >= begin);
+ m_len = end-begin;
+ m_ptr = (char *)kvi_realloc(m_ptr,m_len+1);
+ kvi_fastmove(m_ptr,begin,m_len);
+ *(m_ptr + m_len)='\0';
+}
+
+void KviStr::prepend(const KviStr &str)
+{
+ __range_valid(str.m_ptr);
+ __range_valid(str.m_ptr != m_ptr);
+ m_ptr = (char *)kvi_realloc(m_ptr,m_len+str.m_len+1);
+ kvi_memmove((m_ptr+str.m_len),m_ptr,m_len+1); //move self
+ kvi_fastmove(m_ptr,str.m_ptr,str.m_len);
+ m_len += str.m_len;
+}
+
+void KviStr::prepend(const char *str)
+{
+ if(!str)return;
+ int len = (int)strlen(str);
+ m_ptr = (char *)kvi_realloc(m_ptr,m_len+len+1);
+ kvi_memmove((m_ptr+len),m_ptr,m_len+1); //move self
+ kvi_fastmove(m_ptr,str,len);
+ m_len += len;
+}
+
+void KviStr::prepend(const char *str,int len)
+{
+ __range_valid(str);
+ __range_valid(len <= ((int)strlen(str)));
+ __range_valid(len >= 0);
+ m_ptr = (char *)kvi_realloc(m_ptr,m_len+len+1);
+ kvi_memmove((m_ptr+len),m_ptr,m_len+1); //move self
+ kvi_fastmove(m_ptr,str,len);
+ m_len += len;
+}
+
+unsigned char iso88591_toUpper_map[256]=
+{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+ 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
+ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
+};
+
+void KviStr::toUpperISO88591()
+{
+ register char *p=m_ptr;
+ while(*p)
+ {
+ *p=(char)iso88591_toUpper_map[(unsigned char)*p];
+ p++;
+ }
+}
+
+void KviStr::toUpper()
+{
+ register char *p=m_ptr;
+ while(*p)
+ {
+ *p=toupper(*p);
+ p++;
+ }
+}
+
+unsigned char iso88591_toLower_map[256]=
+{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
+ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
+};
+
+void KviStr::toLowerISO88591()
+{
+ register char *p=m_ptr;
+ while(*p)
+ {
+ *p=(char)iso88591_toLower_map[(unsigned char)*p];
+ p++;
+ }
+}
+
+
+void KviStr::toLower()
+{
+ register char *p=m_ptr;
+ while(*p)
+ {
+ *p=tolower(*p);
+ p++;
+ }
+}
+
+KviStr KviStr::upper() const
+{
+ KviStr tmp(*this);
+ tmp.toUpper();
+ return tmp;
+}
+
+KviStr KviStr::upperISO88591() const
+{
+ KviStr tmp(*this);
+ tmp.toUpperISO88591();
+ return tmp;
+}
+
+KviStr KviStr::lower() const
+{
+ KviStr tmp(*this);
+ tmp.toLower();
+ return tmp;
+}
+
+KviStr KviStr::lowerISO88591() const
+{
+ KviStr tmp(*this);
+ tmp.toLowerISO88591();
+ return tmp;
+}
+
+KviStr KviStr::left(int maxLen) const
+{
+ if(maxLen <= 0)
+ {
+ KviStr empty;
+ return empty;
+ }
+ if(maxLen > m_len)maxLen=m_len;
+ KviStr str(m_ptr,maxLen);
+ return str;
+}
+
+KviStr KviStr::right(int maxLen) const
+{
+ if(maxLen <= 0)
+ {
+ KviStr empty;
+ return empty;
+ }
+ if(maxLen > m_len)maxLen=m_len;
+ KviStr str((m_ptr+(m_len-maxLen)),maxLen);
+ return str;
+}
+
+KviStr KviStr::middle(int idx,int maxLen) const
+{
+ __range_valid(maxLen >= 0);
+ __range_valid(idx >= 0);
+ if((maxLen <= 0) || (idx < 0)){ //max len negative...invalid params
+ KviStr ret;
+ return ret;
+ }
+ if((maxLen + idx) <= m_len){ //valid params
+ KviStr str(m_ptr+idx,maxLen);
+ return str;
+ }
+ if(idx < m_len){ //string shorter than requested
+ KviStr str(m_ptr+idx);
+ return str;
+ }
+ // idx out of bounds
+ KviStr ret;
+ return ret;
+}
+
+KviStr ** KviStr::splitToArray(char sep,int max,int * realCount) const
+{
+ KviStr ** strings = (KviStr **)kvi_malloc(sizeof(KviStr *));
+ int number = 0;
+ char * ptr = m_ptr;
+ char * last = ptr;
+ while((max > 0) && *ptr)
+ {
+ strings = (KviStr **)kvi_realloc((void *)strings,sizeof(KviStr *) * (number + 2));
+ if(max > 1)
+ {
+ while(*ptr && (*ptr != sep))ptr++;
+ strings[number] = new KviStr(last,ptr - last);
+ } else {
+ strings[number] = new KviStr(ptr);
+ }
+ number++;
+ max--;
+ if(*ptr)
+ {
+ ptr++;
+ last = ptr;
+ }
+ }
+ if(realCount)*realCount = number;
+ strings[number] = 0;
+ return strings;
+}
+/*
+ WORKING BUT UNUSED
+
+KviStr ** KviStr::splitToArray(const char * sep,int max,int * realCount) const
+{
+ KviStr ** strings = (KviStr **)kvi_malloc(sizeof(KviStr *));
+ KviStr tmp = *this;
+ int idx = tmp.findFirstIdx(sep);
+ int number = 0;
+ int seplen = kvi_strLen(sep);
+
+
+ while(idx != -1)
+ {
+ strings = (KviStr **)kvi_realloc(sizeof(KviStr *) * (number + 2));
+ strings[number] = new KviStr(tmp.ptr(),idx);
+ tmp.cutLeft(idx + seplen);
+ number++;
+ idx = tmp.findFirstIdx(sep);
+ }
+
+ if(tmp.hasData())
+ {
+ strings = (KviStr **)kvi_realloc(sizeof(KviStr *) * (number + 2));
+ strings[number] = new KviStr(tmp);
+ number++;
+ }
+
+ if(realCount)*realCount = number;
+ strings[number] = 0;
+ return strings;
+}
+*/
+void KviStr::freeArray(KviStr ** strings)
+{
+ if(!strings)return;
+ KviStr ** aux = strings;
+ while(*aux)
+ {
+ delete (*aux); // delete (KviStr *)
+ aux++;
+ }
+ kvi_free(strings);
+}
+
+void KviStr::freeBuffer(char * buffer)
+{
+ if(!buffer)return;
+ kvi_free(buffer);
+}
+
+void KviStr::joinFromArray(KviStr ** strings,const char * sep,bool bLastSep)
+{
+ setLen(0);
+ if(!strings)return;
+
+ while(*strings)
+ {
+ append(*(*strings));
+ strings++;
+ if(*strings)
+ {
+ if(sep)append(sep);
+ } else {
+ if(sep && bLastSep)append(sep);
+ }
+ }
+}
+
+KviStr & KviStr::insert(int idx,const char *data)
+{
+ __range_valid(data);
+ if(idx <= m_len){
+ int len = (int)strlen(data);
+ m_ptr = (char *)kvi_realloc(m_ptr,m_len+len+1);
+ kvi_memmove(m_ptr+idx+len,m_ptr+idx,(m_len - idx)+1);
+ kvi_fastmove(m_ptr+idx,data,len);
+ m_len+=len;
+ }
+ return (*this);
+}
+
+KviStr & KviStr::insert(int idx,char c)
+{
+ if(idx <= m_len){
+ m_ptr = (char *)kvi_realloc(m_ptr,m_len+2);
+ kvi_memmove(m_ptr+idx+1,m_ptr+idx,(m_len - idx)+1);
+ m_len++;
+ *(m_ptr + idx) = c;
+ }
+ return (*this);
+}
+
+// FIXME: #warning "Double check the following two functions !!!"
+
+KviStr & KviStr::hexEncodeWithTable(const unsigned char table[256])
+{
+ char * aux = m_ptr;
+ char * begin = m_ptr;
+
+ char * n = 0;
+ int curSize = 0;
+
+ while(*aux)
+ {
+ if(table[*((unsigned char *)aux)] || (*aux == '%'))
+ {
+ int len = aux - begin;
+ n = (char *)kvi_realloc(n,curSize + len + 3);
+ kvi_memmove(n + curSize,begin,len);
+ curSize += len;
+
+ n[curSize] = '%';
+ curSize++;
+ n[curSize] = hexdigits[(unsigned int)(((unsigned char)(*aux)) / 16)];
+ curSize++;
+ n[curSize] = hexdigits[(unsigned int)(((unsigned char)(*aux)) % 16)];
+ curSize++;
+
+ aux++;
+ begin = aux;
+
+ } else aux++;
+ }
+
+ int len = aux - begin;
+ n = (char *)kvi_realloc(n,curSize + len + 1);
+ kvi_memmove(n + curSize,begin,len);
+ curSize += len;
+
+ n[curSize] = '\0';
+
+ kvi_free((void *)m_ptr);
+ m_ptr = n;
+ m_len = curSize;
+
+ return (*this);
+}
+
+KviStr & KviStr::hexEncodeWhiteSpace()
+{
+ static unsigned char ascii_jump_table[256]=
+ {
+ // 000 001 002 003 004 005 006 007 008 009 010 011 012 013 014 015
+ // NUL SOH STX ETX EOT ENQ ACK BEL BS HT LF VT FF CR SO SI
+ 1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,
+ // 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031
+ // DLE DC1 DC2 DC3 DC4 NAK SYN ETB CAN EM SUB ESC FS GS RS US
+ 1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,
+ // 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047
+ // ! " # $ % & ' ( ) * + , - . /
+ 1 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,
+ // 048 049 050 051 052 053 054 055 056 057 058 059 060 061 062 063
+ // 0 1 2 3 4 5 6 7 8 9 : ; < = > ?
+ 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,
+ // 064 065 066 067 068 069 070 071 072 073 074 075 076 077 078 079
+ // @ A B C D E F G H I J K L M N O
+ 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,
+ // 080 081 082 083 084 085 086 087 088 089 090 091 092 093 094 095
+ // P Q R S T U V W X Y Z [ \ ] ^ _
+ 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,
+ // 096 097 098 099 100 101 102 103 104 105 106 107 108 109 110 111
+ // ` a b c d e f g h i j k l m n o
+ 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,
+ // 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
+ // p q r s t u v w x y z { | } ~ 
+ 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,
+ // 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
+ //
+ 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,
+ // 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
+ //
+ 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,
+ // 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
+ //
+ 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,
+ // 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
+ //
+ 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,
+ // 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
+ // � � � � � � � � � � � � � � � �
+ 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,
+ // 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223
+ // � � � � � � � � � � � � � � � �
+ 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,
+ // 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239
+ // � � � � � � � � � � � � � � � �
+ 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,
+ // 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255
+ // � � � � � � � �
+ 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0
+ };
+
+ return hexEncodeWithTable(ascii_jump_table);
+}
+
+KviStr & KviStr::hexDecode(const char * pFrom)
+{
+ // WARNING: pFrom can be also m_ptr here!
+ const char * aux = pFrom;
+ const char * begin = pFrom;
+
+ char * n = 0;
+ int curSize = 0;
+
+ while(*aux)
+ {
+ if(*aux == '%')
+ {
+ // move last block
+ int len = aux - begin;
+ n = (char *)kvi_realloc(n,curSize + len + 1);
+ kvi_memmove(n + curSize,begin,len);
+ curSize += len;
+
+ // get the hex code
+ aux++;
+
+ char theChar = get_decimal_from_hex_digit_char(*aux);
+ if(theChar < 0)
+ {
+ n[curSize] = '%'; // wrong code...just a '%'
+ curSize++;
+ } else {
+ aux++;
+ char theChar2 = get_decimal_from_hex_digit_char(*aux);
+ if(theChar2 < 0)
+ {
+ // wrong code...just a '%' and step back
+ n[curSize] = '%';
+ curSize++;
+ aux--;
+ } else {
+ n[curSize] = (theChar * 16) + theChar2;
+ curSize++;
+ aux++;
+ }
+ }
+
+ begin = aux;
+
+ } else aux++;
+ }
+
+ int len = aux - begin;
+ n = (char *)kvi_realloc(n,curSize + len + 2);
+ kvi_memmove(n + curSize,begin,len);
+ curSize += len;
+ n[curSize] = '\0';
+
+ kvi_free((void *)m_ptr);
+ m_ptr = n;
+ m_len = curSize;
+
+ return (*this);
+}
+
+KviStr & KviStr::replaceAll(char c,const char *str)
+{
+ int idx = findFirstIdx(c);
+ KviStr tmp;
+ while(idx >= 0){
+ if(idx > 0)tmp += left(idx);
+ cutLeft(idx+1);
+ tmp.append(str);
+ idx = findFirstIdx(c);
+ }
+ tmp.append(*this);
+ // Now copy
+ m_len = tmp.m_len;
+ m_ptr = (char *)kvi_realloc(m_ptr,m_len+1);
+ kvi_fastmove(m_ptr,tmp.m_ptr,m_len+1);
+ return (*this);
+}
+
+KviStr & KviStr::replaceAll(char *toFind,const char *str,bool bCaseS)
+{
+ int len = (int)strlen(toFind);
+ int idx = findFirstIdx(toFind,bCaseS);
+ KviStr tmp;
+ while(idx >= 0)
+ {
+ if(idx > 0)tmp += left(idx);
+ cutLeft(idx+len);
+ tmp.append(str);
+ idx = findFirstIdx(toFind,bCaseS);
+ }
+ tmp.append(*this);
+ // Now copy
+ m_len = tmp.m_len;
+ m_ptr = (char *)kvi_realloc(m_ptr,m_len+1);
+ kvi_fastmove(m_ptr,tmp.m_ptr,m_len+1);
+ return (*this);
+}
+
+KviStr & KviStr::transliterate(const char * szToFind,const char * szReplacement)
+{
+ while(*szToFind && *szReplacement)
+ {
+ char * p = m_ptr;
+ while(*p)
+ {
+ if(*p == *szToFind)*p = *szReplacement;
+ ++p;
+ }
+ ++szToFind;
+ ++szReplacement;
+ }
+ return (*this);
+}
+
+
+int KviStr::occurences(char c,bool caseS) const
+{
+ register char *p = m_ptr;
+ int cnt=0;
+ if(caseS){
+ while(*p){
+ if(*p == c)cnt++;
+ p++;
+ }
+ } else {
+ char b=tolower(c);
+ while(*p){
+ if(tolower(*p) == b)cnt++;
+ p++;
+ }
+ }
+ return cnt;
+}
+
+int KviStr::occurences(const char *str,bool caseS) const
+{
+ __range_valid(str);
+ register char *p = m_ptr;
+ int cnt=0;
+ int len = (int)strlen(str);
+ if(caseS){
+ while(*p){
+ if(*p == *str){
+ if(kvi_strEqualCSN(p,str,len))cnt++;
+ }
+ p++;
+ }
+ } else {
+ while(*p){
+ char c = tolower(*str);
+ if(tolower(*p) == c){
+ if(kvi_strEqualCIN(p,str,len))cnt++;
+ }
+ p++;
+ }
+ }
+ return cnt;
+}
+
+bool KviStr::contains(char c,bool caseS) const
+{
+ register char *p = m_ptr;
+ if(caseS)
+ {
+ while(*p)
+ {
+ if(*p == c)return true;
+ p++;
+ }
+ } else {
+ char b=tolower(c);
+ while(*p)
+ {
+ if(tolower(*p) == b)return true;
+ p++;
+ }
+ }
+ return false;
+}
+
+bool KviStr::contains(const char *str,bool caseS) const
+{
+ __range_valid(str);
+ register char *p = m_ptr;
+ int len = (int)strlen(str);
+ if(caseS)
+ {
+ while(*p)
+ {
+ if(*p == *str)
+ {
+ if(kvi_strEqualCSN(p,str,len))return true;
+ }
+ p++;
+ }
+ } else {
+ while(*p)
+ {
+ char c = tolower(*str);
+ if(tolower(*p) == c)
+ {
+ if(kvi_strEqualCIN(p,str,len))return true;
+ }
+ p++;
+ }
+ }
+ return false;
+}
+
+
+KviStr & KviStr::setNum(long num)
+{
+ char numberBuffer[30];
+ bool bNegative = false;
+ long tmp;
+ register char *p;
+ register char *pNumBuf = numberBuffer;
+
+ // somebody can explain me why -(-2147483648) = -2147483648 ? (2^31)
+ // it is like signed char x = 128 ---> 10000000 that is signed -0 (!?)
+ // mmmmh...or it is assumed to be -128 (a number rappresentation exception)
+ // at least on my machine it happens...
+
+ // found the solution by myself today...
+ //
+ // ABS(3) Linux Programmer's Manual ABS(3)
+ // NAME
+ // abs - computes the absolute value of an integer.
+ // ...
+ // DESCRIPTION
+ // The abs() function computes the absolute value of the integer argument j.
+ // RETURN VALUE
+ // Returns the absolute value of the integer argument.
+ // CONFORMING TO
+ // SVID 3, POSIX, BSD 4.3, ISO 9899
+ // NOTE ##################################################################################
+ // Trying to take the absolute value of the most negative integer is not defined.
+ // #######################################################################################
+
+ // so should i use temporaneous doubles to make calculations ?
+
+ if(num < 0){ //negative integer
+ bNegative = true;
+ num = -num; //need to have it positive
+ if(num < 0){ // 2^31 exception
+ // We need to avoid absurd responses like ".(./),." :)
+ num = 0; // we get a negative zero here...it is still an exception
+ }
+ }
+
+ //write the number in a temporary buffer (at least '0')
+ do {
+ tmp = num / 10;
+ *pNumBuf++ = num - (tmp * 10) + '0';
+ } while((num = tmp));
+
+ //copy now....
+ m_len = pNumBuf - numberBuffer; //length of the number string
+ if(bNegative){
+ m_len++;
+ m_ptr = (char *)kvi_realloc(m_ptr,m_len+1);
+ p=m_ptr;
+ *p++='-';
+ } else {
+ m_ptr = (char *)kvi_realloc(m_ptr,m_len+1);
+ p=m_ptr;
+ }
+ do { *p++ = *--pNumBuf; } while(pNumBuf != numberBuffer);
+ *(m_ptr + m_len)='\0';
+ return (*this);
+}
+
+KviStr & KviStr::setNum(unsigned long num)
+{
+ char numberBuffer[30];
+ unsigned long tmp;
+ register char *p;
+ register char *pNumBuf = numberBuffer;
+
+ //write the number in a temporary buffer (at least '0')
+ do {
+ tmp = num / 10;
+ *pNumBuf++ = num - (tmp * 10) + '0';
+ } while((num = tmp));
+
+ //copy now....
+ m_len = pNumBuf - numberBuffer; //length of the number string
+ m_ptr = (char *)kvi_realloc(m_ptr,m_len+1);
+ p=m_ptr;
+ do { *p++ = *--pNumBuf; } while(pNumBuf != numberBuffer);
+ *(m_ptr + m_len)='\0';
+ return (*this);
+}
+
+long KviStr::toLong(bool *bOk) const
+{
+ long result = 0;
+ if(bOk)*bOk = false;
+ register char *p=m_ptr;
+ bool bNeg = false;
+ while(isspace(*p))p++; //skip spaces
+ if(*p == '-'){
+ bNeg = true;
+ p++;
+ } else {
+ if(*p == '+')p++;
+ }
+ if(isdigit(*p)){ //point to something interesting ?
+ do{
+ result = (result * 10) + (*p - '0');
+ p++;
+ } while(isdigit(*p));
+ if(bNeg)result = -result;
+ while(isspace(*p))p++; //skip trailing spaces
+ if(*p)return 0; //if this is not the end...die.
+ if(bOk)*bOk = true;
+ return result;
+ }
+ return 0;
+}
+
+unsigned long KviStr::toULong(bool *bOk) const
+{
+ unsigned long result = 0;
+ if(bOk)*bOk = false;
+ register char *p=m_ptr;
+ while(isspace(*p))p++; //skip spaces
+ if(isdigit(*p)){ //point to something interesting ?
+ do{
+ result = (result * 10) + (*p - '0');
+ p++;
+ } while(isdigit(*p));
+ while(isspace(*p))p++; //skip trailing spaces
+ if(*p)return 0; //if this is not the end...die.
+ if(bOk)*bOk = true;
+ return result;
+ }
+ return 0;
+}
+
+long KviStr::toLongExt(bool *bOk,int base)
+{
+ if(m_len == 0){
+ if(bOk)*bOk = false;
+ return 0;
+ }
+ char * endptr;
+ long result = strtol(m_ptr,&endptr,base);
+ if(*endptr){
+ // must be whitespaces , otherwise there is trailing garbage inside
+ while(isspace(*endptr) && (*endptr))endptr++;
+ if(*endptr){
+ // still not at the end
+ // trailing garbage not allowed
+ if(bOk)*bOk = false;
+ return result;
+ }
+ }
+ if(bOk)*bOk = true;
+ return result;
+}
+
+//
+//working code , but unused in kvirc
+//
+//unsigned long KviStr::toULongExt(bool *bOk = 0,int base = 0)
+//{
+// if(m_len == 0){
+// if(bOk)*bOk = false;
+// return 0;
+// }
+// char * endptr;
+// unsigned long result = strtoul(m_ptr,&endptr,base);
+// if(*endptr != '\0'){
+// if(bOk)*bOk = false;
+// }
+// return result;
+//}
+
+KviStr & KviStr::cutLeft(int len)
+{
+ __range_valid(len >= 0);
+ if(len <= m_len){
+ m_len -= len;
+ kvi_memmove(m_ptr,m_ptr+len,m_len+1);
+ m_ptr = (char *)kvi_realloc(m_ptr,m_len+1);
+ } else {
+ m_ptr = (char *)kvi_realloc(m_ptr,1);
+ *m_ptr = '\0';
+ m_len = 0;
+ }
+ return (*this);
+}
+
+KviStr & KviStr::cutRight(int len)
+{
+ __range_valid(len >= 0);
+ if(len <= m_len){
+ m_len -= len;
+ m_ptr = (char *)kvi_realloc(m_ptr,m_len+1);
+ *(m_ptr +m_len)='\0';
+ } else {
+ m_ptr = (char *)kvi_realloc(m_ptr,1);
+ *m_ptr = '\0';
+ m_len = 0;
+ }
+ return (*this);
+}
+
+KviStr & KviStr::cut(int idx,int len)
+{
+ __range_valid(idx >= 0);
+ __range_valid(len >= 0);
+ if(idx < m_len){
+ // idx = 3 len = 3 m_len = 10
+ // 0123456789
+ // abcdefghij
+ // ^ ^
+ // p1 p2
+ char * p1 = m_ptr+idx;
+ if(len + idx > m_len)len = m_len - idx;
+ char * p2 = p1+len;
+ kvi_memmove(p1,p2,(m_len - (len+idx)) +1);
+ m_len -= len;
+ m_ptr = (char *)kvi_realloc(m_ptr,m_len+1);
+ }
+ return (*this);
+}
+
+KviStr & KviStr::cutToFirst(char c,bool bIncluded)
+{
+ int idx = findFirstIdx(c);
+ if(idx != -1)cutLeft(bIncluded ? idx + 1 : idx);
+ return (*this);
+}
+
+KviStr KviStr::leftToFirst(char c,bool bIncluded) const
+{
+ int idx = findFirstIdx(c);
+ if(idx == -1)return KviStr(*this);
+ return KviStr(m_ptr,bIncluded ? idx + 1 : idx);
+}
+
+
+KviStr KviStr::leftToLast(char c,bool bIncluded) const
+{
+ int idx = findLastIdx(c);
+ return KviStr(m_ptr,bIncluded ? idx + 1 : idx);
+}
+
+KviStr & KviStr::cutFromFirst(char c,bool bIncluded)
+{
+ int idx = findFirstIdx(c);
+ if(idx != -1)cutRight(bIncluded ? (m_len - idx) : (m_len - (idx + 1)));
+ return (*this);
+}
+
+KviStr & KviStr::cutToLast(char c,bool bIncluded)
+{
+ int idx = findLastIdx(c);
+ if(idx != -1)cutLeft(bIncluded ? idx + 1 : idx);
+ return (*this);
+}
+
+KviStr & KviStr::cutFromLast(char c,bool bIncluded)
+{
+ int idx = findLastIdx(c);
+ if(idx != -1)cutRight(bIncluded ? (m_len - idx) : (m_len - (idx + 1)));
+ return (*this);
+}
+
+KviStr & KviStr::cutToFirst(const char *c,bool bIncluded)
+{
+ int len = (int)strlen(c);
+ int idx = findFirstIdx(c);
+ if(idx != -1)cutLeft(bIncluded ? idx + len : idx);
+ return (*this);
+}
+
+KviStr & KviStr::cutFromFirst(const char *c,bool bIncluded)
+{
+ int len = (int)strlen(c);
+ int idx = findFirstIdx(c);
+ if(idx != -1)cutRight(bIncluded ? (m_len - idx) : (m_len - (idx + len)));
+ return (*this);
+}
+
+KviStr & KviStr::cutToLast(const char *c,bool bIncluded)
+{
+ int len = (int)strlen(c);
+ int idx = findLastIdx(c);
+ if(idx != -1)cutLeft(bIncluded ? idx + len : idx);
+ return (*this);
+}
+
+KviStr & KviStr::cutFromLast(const char *c,bool bIncluded)
+{
+ int len = (int)strlen(c);
+ int idx = findLastIdx(c);
+ if(idx != -1)cutRight(bIncluded ? (m_len - idx) : (m_len - (idx + len)));
+ return (*this);
+}
+
+KviStr & KviStr::setLen(int len)
+{
+ __range_valid(len >= 0);
+ m_ptr = (char *)kvi_realloc(m_ptr,len+1);
+ *(m_ptr+len)='\0';
+ m_len = len;
+ return (*this);
+}
+
+KviStr & KviStr::stripLeftWhiteSpace()
+{
+ register char *p=m_ptr;
+ while(isspace(*p))p++;
+ m_len -= (p-m_ptr);
+ kvi_memmove(m_ptr,p,m_len+1);
+ m_ptr = (char *)kvi_realloc(m_ptr,m_len+1);
+ return (*this);
+}
+
+KviStr & KviStr::stripLeft(char c)
+{
+ __range_valid(c != '\0');
+ register char *p=m_ptr;
+ while(*p == c)p++;
+ m_len -= (p-m_ptr);
+ kvi_memmove(m_ptr,p,m_len+1);
+ m_ptr = (char *)kvi_realloc(m_ptr,m_len+1);
+ return (*this);
+}
+
+bool KviStr::getToken(KviStr & str,char sep)
+{
+ __range_valid(str.m_ptr);
+ __range_valid(str.m_ptr != m_ptr);
+ register char *p=m_ptr;
+ //skip to the end
+ while(*p && (*p != sep))p++;
+ //0123456789
+ //abcd xyz
+ //^ ^
+ str.m_len = p-m_ptr;
+ str.m_ptr = (char *)kvi_realloc(str.m_ptr,str.m_len+1);
+ kvi_fastmove(str.m_ptr,m_ptr,str.m_len);
+ *(str.m_ptr + str.m_len)='\0';
+ while(*p && (*p == sep))p++;
+ cutLeft(p-m_ptr);
+ return (m_len != 0);
+}
+
+bool KviStr::getLine(KviStr &str)
+{
+ __range_valid(str.m_ptr);
+ __range_valid(str.m_ptr != m_ptr);
+ if(m_len == 0)return false;
+ register char *p=m_ptr;
+ //skip to the end
+ while(*p && (*p != '\n'))p++;
+ //0123456789
+ //abcd xyz
+ //^ ^
+ str.m_len = p-m_ptr;
+ str.m_ptr = (char *)kvi_realloc(str.m_ptr,str.m_len+1);
+ kvi_fastmove(str.m_ptr,m_ptr,str.m_len);
+ *(str.m_ptr + str.m_len)='\0';
+ p++;
+ cutLeft(p-m_ptr);
+ return true;
+}
+
+KviStr KviStr::getToken(char sep)
+{
+ register char *p=m_ptr;
+ while(*p && (*p != sep))p++;
+ KviStr ret(m_ptr,p);
+ while(*p && (*p == sep))p++;
+ cutLeft(p-m_ptr);
+ return ret;
+}
+
+KviStr & KviStr::sprintf(const char *fmt,...)
+{
+ m_ptr=(char *)kvi_realloc(m_ptr,256);
+ //First try
+ kvi_va_list list;
+ kvi_va_start(list,fmt);
+ //print...with max 256 chars
+ m_len=kvi_vsnprintf(m_ptr,256,fmt,list);
+ kvi_va_end(list);
+
+ //check if we failed
+ if(m_len < 0){
+ //yes , failed....
+ int dummy=256;
+ do{ //we failed , so retry with 256 more chars
+ dummy+=256;
+ //realloc
+ m_ptr=(char *)kvi_realloc(m_ptr,dummy);
+ //print...
+ kvi_va_start(list,fmt);
+ m_len=kvi_vsnprintf(m_ptr,dummy,fmt,list);
+ kvi_va_end(list);
+ } while(m_len < 0);
+ }
+ //done...
+ //now m_len is the length of the written string not including the terminator...
+ //perfect! :)
+ m_ptr=(char *)kvi_realloc(m_ptr,m_len+1);
+ return (*this);
+}
+
+int KviStr::find(const char *str,int idx,bool caseS) const
+{
+ if(idx >= m_len)return -1;
+ register char *p=m_ptr + idx;
+ int len = (int)strlen(str);
+ if(caseS){
+ for(;;){
+ while(*p && (*p != *str))p++;
+ if(*p){
+ if(kvi_strEqualCSN(str,p,len))return (p-m_ptr);
+ else p++;
+ } else return -1;
+ }
+ } else {
+ for(;;){
+ char tmp = toupper(*str);
+ while(*p && (toupper(*p) != tmp))p++;
+ if(*p){
+ if(kvi_strEqualCIN(str,p,len))return (p-m_ptr);
+ else p++;
+ } else return -1;
+ }
+ }
+}
+
+int KviStr::find(char c,int idx) const
+{
+ if(idx >= m_len)return -1;
+ register char *p=m_ptr + idx;
+ while(*p && (*p != c))p++;
+ return (*p ? p-m_ptr : -1);
+}
+
+
+int KviStr::findRev(const char *str,int idx,bool caseS) const
+{
+ if((m_len + idx) < 0)return -1;
+ register char *p=m_ptr + m_len + idx;
+ int len = (int)strlen(str);
+ if(caseS)
+ {
+ for(;;)
+ {
+ while((p >= m_ptr) && (*p != *str))p--;
+ if(p >= m_ptr){
+ if(kvi_strEqualCSN(str,p,len))return (p-m_ptr);
+ else p--;
+ } else return -1;
+ }
+ } else {
+ for(;;){
+ char tmp = toupper(*str);
+ while((p >= m_ptr) && (toupper(*p) != tmp))p--;
+ if(p >= m_ptr){
+ if(kvi_strEqualCIN(str,p,len))return (p-m_ptr);
+ else p--;
+ } else return -1;
+ }
+ }
+}
+
+int KviStr::findFirstIdx(char c) const
+{
+ register char *p=m_ptr;
+ while(*p && (*p != c))p++;
+ return (*p ? p-m_ptr : -1);
+}
+
+int KviStr::findFirstIdx(const char *str,bool caseS) const
+{
+ // This function can't be used to search inside
+ // multibyte encoded strings... convert your
+ // code to QString and use QString::findRev().
+ // We must throw away KviStr at all in this case...
+
+ // return QString(m_ptr).find(QString(str),0,caseS);;
+
+ // Both this KviStr and the const char * str are assumed
+ // to be in the proper (and same) encoding.
+ // If KviStr is in encoding A then QString(m_ptr) might
+ // or not be decoded correctly.
+ // Also if KviStr is in UTF-8 (for example), then
+ // a position in QString() does not map to the position in the char array
+ // since a single UNICODE char may use one or more bytes...
+
+ __range_valid(str);
+ register char *p=m_ptr;
+ int len = (int)strlen(str);
+ if(caseS){
+ for(;;){
+ while(*p && (*p != *str))p++;
+ if(*p){
+ if(kvi_strEqualCSN(str,p,len))return (p-m_ptr);
+ else p++;
+ } else return -1;
+ }
+ } else {
+ // this will NOT work for strings that aren't in the current system encoding :(
+ for(;;){
+ char tmp = toupper(*str);
+ while(*p && (toupper(*p) != tmp))p++;
+ if(*p){
+ if(kvi_strEqualCIN(str,p,len))return (p-m_ptr);
+ else p++;
+ } else return -1;
+ }
+ }
+}
+
+int KviStr::findLastIdx(char c) const
+{
+ //Empty string ?
+ if(m_len < 1)return -1;
+ //p points to the last character in the string
+ register char *p=((m_ptr+m_len)-1);
+ //go back until we find a match or we run to the first char in the string.
+ while((*p != c) && (p > m_ptr))p--;
+ //if *p == c --> matched , else we are at the beginning of the string.
+ return ((*p == c)? p-m_ptr : -1);
+}
+
+int KviStr::findLastIdx(const char *str,bool caseS) const
+{
+ // This function can't be used to search inside
+ // multibyte encoded strings... convert your
+ // code to QString and use QString::findRev().
+ // We must throw away KviStr at all in this case...
+
+ // return QString(m_ptr).findRev(QString(str),-1,caseS);
+
+ __range_valid(str);
+ //Calc the len of the searched string
+ int len = (int)strlen(str);
+ //Too long ?
+ if(m_len < len)return -1;
+ //p points to the last character in the string
+ register char *p=((m_ptr+m_len)-1);
+ if(caseS){
+ for(;;){
+ //go back until we find a character that mathes or we run to the first char.
+ while((*p != *str) && (p > m_ptr))p--;
+ if(*p == *str){
+ //maybe occurence....
+ if(kvi_strEqualCSN(str,p,len))return (p-m_ptr);
+ else {
+ //Nope...continue if there is more data to check...
+ if(p == m_ptr)return -1;
+ p--;
+ }
+ } else return -1; //Beginning of the string
+ }
+ } else {
+ // case insensitive
+ for(;;){
+ //go back until we find a character that mathes or we run to the first char.
+ char tmp = toupper(*str);
+ while((toupper(*p) != tmp) && (p > m_ptr))p--;
+ if(toupper(*p) == tmp){
+ //maybe occurence....
+ if(kvi_strEqualCIN(str,p,len))return (p-m_ptr);
+ else {
+ //Nope...continue if there is more data to check...
+ if(p == m_ptr)return -1;
+ p--;
+ }
+ } else return -1; //Beginning of the string
+ }
+ }
+}
+
+KviStr & KviStr::stripWhiteSpace()
+{
+ // 0123456789
+ // abcd 0
+ // ^ ^
+ // left right
+ register char *left=m_ptr;
+ register char *right=m_ptr+m_len-1;
+ // skip initial spaces
+ while(isspace(*left))left++;
+ if(*left){
+ // valid string , left points to first non-space
+ while((right >= left) && isspace(*right))right--;
+ // 0123456789
+ // abcd 0
+ // ^ ^
+ // left right
+ m_len = (right - left)+1;
+ kvi_memmove(m_ptr,left,m_len);
+ m_ptr = (char *)kvi_realloc(m_ptr,m_len+1);
+ *(m_ptr+m_len)='\0';
+ } else {
+ m_ptr = (char *)kvi_realloc(m_ptr,1);
+ *m_ptr = '\0';
+ m_len = 0;
+ }
+ return (*this);
+}
+
+KviStr & KviStr::stripRightWhiteSpace()
+{
+ if(*m_ptr)
+ {
+ register char *right=m_ptr+m_len-1;
+ const char *start=right;
+ while((right >= m_ptr) && isspace( *right ))right--;
+ if(right != start)
+ {
+ m_len = (right - m_ptr) + 1;
+ m_ptr = (char *)kvi_realloc(m_ptr,m_len+1);
+ *(m_ptr+m_len)='\0';
+ }
+ }
+ return (*this);
+}
+
+KviStr & KviStr::stripRight(char c)
+{
+ if(*m_ptr)
+ {
+ register char *right=m_ptr+m_len-1;
+ const char *start=right;
+ while((right >= m_ptr) && (*right == c))right--;
+ if(right != start)
+ {
+ m_len = (right - m_ptr) + 1;
+ m_ptr = (char *)kvi_realloc(m_ptr,m_len+1);
+ *(m_ptr+m_len)='\0';
+ }
+ }
+ return (*this);
+}
+
+KviStr & KviStr::stripSpace()
+{
+ // 0123456789
+ // abcd 0
+ // ^ ^
+ // left right
+ register char *left=m_ptr;
+ register char *right=m_ptr+m_len-1;
+ // skip initial spaces
+ while((*left == ' ') || (*left == '\t'))left++;
+ if(*left){
+ // valid string , left points to first non-space
+ while((right >= left) && ((*right == ' ') || (*right == '\t')))right--;
+ // 0123456789
+ // abcd 0
+ // ^ ^
+ // left right
+ m_len = (right - left)+1;
+ kvi_memmove(m_ptr,left,m_len);
+ m_ptr = (char *)kvi_realloc(m_ptr,m_len+1);
+ *(m_ptr+m_len)='\0';
+ } else {
+ m_ptr = (char *)kvi_realloc(m_ptr,1);
+ *m_ptr = '\0';
+ m_len = 0;
+ }
+ return (*this);
+}
+
+bool KviStr::isNum() const
+{
+ register char *p=m_ptr;
+ while(isspace(*p))p++;
+ if(*p=='-')p++;
+ if(!isdigit(*p))return false;
+ while(isdigit(*p))p++;
+ while(isspace(*p))p++;
+ return (*p=='\0');
+}
+
+bool KviStr::isUnsignedNum() const
+{
+ register char *p=m_ptr;
+ while(isspace(*p))p++;
+ if(!isdigit(*p))return false;
+ while(isdigit(*p))p++;
+ while(isspace(*p))p++;
+ return (*p=='\0');
+}
+
+static KviStr g_szApplicationWideEmptyString;
+
+KviStr & KviStr::emptyString()
+{
+ return g_szApplicationWideEmptyString;
+}
+
+
+bool KviStr::ext_contains(register const char * data,const char * item,bool caseS)
+{
+ if(item && data)
+ {
+ int len = (int)strlen(item);
+ char c = tolower(*item);
+ if(caseS)
+ {
+ while(*data)
+ {
+ while(*data && (tolower(*data) != c))data++;
+ if(*data)
+ {
+ if(kvi_strEqualCSN(item,data,len))return true;
+ else data++;
+ }
+ }
+ } else {
+ while(*data)
+ {
+ while(*data && (tolower(*data) != c))data++;
+ if(*data)
+ {
+ if(kvi_strEqualCIN(item,data,len))return true;
+ else data++;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+
+//void KviStr::pointerToBitString(const void * ptr)
+//{
+// m_len = (sizeof(void *) * 8);
+// m_ptr = kvi_realloc(m_ptr,m_len + 1);
+// for(int i=0;i < m_len;i++)
+// {
+// m_ptr[i] = (ptr & 1) ? '1' : '0';
+// ptr >> 1;
+// }
+// m_ptr[i] = '\0';
+//}
+//
+//void * KviStr::bitStringToPointer()
+//{
+// if(m_len != (sizeof(void *) * 8))return 0;
+// const char * aux = m_ptr;
+// void * ptr = 0;
+// for(int i=m_len - 1;i >= 0;i--)
+// {
+// if(m_ptr[i] == '1')ptr &= 1;
+// else if(m_ptr[i] !='0')return 0;
+// ptr << 1;
+// }
+// return ptr;
+//}
+
+
+
+
+// static char ascii_jump_table[256]=
+// {
+// // 000 001 002 003 004 005 006 007 008 009 010 011 012 013 014 015
+// // NUL SOH STX ETX EOT ENQ ACK BEL BS HT LF VT FF CR SO SI
+// 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,
+// // 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031
+// // DLE DC1 DC2 DC3 DC4 NAK SYN ETB CAN EM SUB ESC FS GS RS US
+// 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,
+// // 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047
+// // ! " # $ % & ' ( ) * + , - . /
+// 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,
+// // 048 049 050 051 052 053 054 055 056 057 058 059 060 061 062 063
+// // 0 1 2 3 4 5 6 7 8 9 : ; < = > ?
+// 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,
+// // 064 065 066 067 068 069 070 071 072 073 074 075 076 077 078 079
+// // @ A B C D E F G H I J K L M N O
+// 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,
+// // 080 081 082 083 084 085 086 087 088 089 090 091 092 093 094 095
+// // P Q R S T U V W X Y Z [ \ ] ^ _
+// 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,
+// // 096 097 098 099 100 101 102 103 104 105 106 107 108 109 110 111
+// // ` a b c d e f g h i j k l m n o
+// 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,
+// // 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
+// // p q r s t u v w x y z { | } ~ 
+// 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,
+// // 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
+// //
+// 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,
+// // 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
+// //
+// 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,
+// // 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
+// //
+// 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,
+// // 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
+// //
+// 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,
+// // 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
+// // � � � � � � � � � � � � � � � �
+// 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,
+// // 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223
+// // � � � � � � � � � � � � � � � �
+// 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,
+// // 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239
+// // � � � � � � � � � � � � � � � �
+// 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,
+// // 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255
+// // � � � � � � � �
+// 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0
+// };
diff --git a/src/kvilib/core/kvi_string.h b/src/kvilib/core/kvi_string.h
new file mode 100644
index 00000000..602173cd
--- /dev/null
+++ b/src/kvilib/core/kvi_string.h
@@ -0,0 +1,552 @@
+#ifndef _KVI_STRING_H_
+#define _KVI_STRING_H_
+//=============================================================================
+//
+// File : kvi_string.h
+// Creation date : Fri Mar 19 1999 03:06:26 by Szymon Stefanek
+//
+// This file is part of the KVirc irc client distribution
+// Copyright (C) 1999-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 <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifdef HAVE_STRINGS_H
+ #include <strings.h> // useless ?
+#endif
+
+#include <qglobal.h>
+#include <qstring.h>
+
+
+#include "kvi_qcstring.h"
+#include "kvi_inttypes.h"
+#include "kvi_heapobject.h"
+#include "kvi_stdarg.h"
+
+
+
+//
+// sigh...
+// IRC is not UNICODE ...(yet) :(
+//
+
+#undef __KVI_EXTERN
+#ifdef _KVI_STRING_CPP_
+ #define __KVI_EXTERN
+#else
+ #define __KVI_EXTERN extern
+#endif
+
+
+__KVI_EXTERN KVILIB_API bool kvi_qstringEqualCI(const QString &s1,const QString &s2);
+
+
+// Include inlined assembly implementations if required
+#ifdef COMPILE_ix86_ASM
+ #include "kvi_strasm.h"
+#else
+ // Returns true if the string str1 is equal to str2. case sensitive.
+ __KVI_EXTERN KVILIB_API bool kvi_strEqualCS(const char *str1,const char *str2);
+ // Returns true if the forst len characters of string str1 are equal to str2.
+ // case sensitive.
+ // Note that if str1 or str2 are shorter than len characters then are considered as NOT equal!
+ __KVI_EXTERN KVILIB_API bool kvi_strEqualCSN(const char *str1,const char *str2,int len);
+ // no such tricks in non-asm
+ #define kvi_strEqualNoLocaleCI(str1,str2) kvi_strEqualCI(str1,str2)
+ #define kvi_strEqualNoLocaleCIN(str1,str2,len) kvi_strEqualCIN(str1,str2,len)
+ #define kvi_strLen(str) strlen(str)
+#endif
+
+// Returns true if the string str1 is equal to str2.
+// case insensitive.
+__KVI_EXTERN KVILIB_API bool kvi_strEqualCI(const char *str1,const char *str2);
+// Returns true if the forst len characters of string str1 are equal to str2.
+// case insensitive.
+// Note that if str1 or str2 are shorter than len characters then are considered as NOT equal!
+__KVI_EXTERN KVILIB_API bool kvi_strEqualCIN(const char *str1,const char *str2,int len);
+// My own implementations of strcmp and strncasecmp
+// Once I wrote it , I KNOW what they do : ALWAYS :)
+// Note that greater here means that comes AFTER in the alphabetic order.
+__KVI_EXTERN KVILIB_API int kvi_strcmpCI(const char *str1,const char *str2);
+//__KVI_EXTERN KVILIB_API int kvi_strcmpCIN(const char *str1,const char *str2,int len);
+__KVI_EXTERN KVILIB_API int kvi_strcmpCS(const char *str1,const char *str2);
+
+// some wide char stuff
+typedef kvi_u16_t kvi_wchar_t;
+typedef kvi_u32_t kvi_wslen_t;
+
+__KVI_EXTERN KVILIB_API kvi_wslen_t kvi_wstrlen(const kvi_wchar_t * str);
+__KVI_EXTERN KVILIB_API int kvi_wvsnprintcf(kvi_wchar_t * buffer,kvi_wslen_t len,const char *fmt,kvi_va_list list);
+__KVI_EXTERN KVILIB_API int kvi_wvsnprintf(kvi_wchar_t * buffer,kvi_wslen_t len,const kvi_wchar_t *fmt,kvi_va_list list);
+
+//=============================================================================
+//
+// A simple string class.<br>
+// -No data sharing.<br>
+// -Not UNICODE.<br>
+// -Has ALWAYS NON-NULL DATA.<br>
+// -(Maybe)Unsafe :)<br>
+// WARNING : Handle with care and use at own risk :)<br>
+//
+//=============================================================================
+
+class KVILIB_API KviStr : public KviHeapObject
+{
+public:
+ // No particular reason for these two names...
+ // It is just because I like it :)
+
+ enum KviFormatConstructorTag { Format , Sprintf };
+
+ //=============================================================================
+ // Constructors
+ //=============================================================================
+
+ // Empty string == "", len = 0, 1 byte allocated
+ KviStr();
+
+ // Deep copy of the NULL TERMINATED string (NULL str SAFE)
+ KviStr(const char *str);
+
+ // Copy len characters from string str (NOT NULL str SAFE, str MUST be at least len chars long)
+ KviStr(const char *str,int len);
+
+ // bg and end are pointers to a SINGLE string.<br>
+ // A string is extracted starting from bg and ending at end (not included).<br>
+ KviStr(const char *bg,const char *end);
+
+ // Format constructor.<br>
+ // tag is....yes....a dummy number used to resolve ambiguities.<br>
+ // It is SAFE: will fail only if we run out of memory,<br>
+ // but can handle only %s %d %u and %c.
+ KviStr(KviFormatConstructorTag tag,const char *fmt,...);
+
+ // Carbon copy :)...fast
+ KviStr(const KviStr &str);
+
+ // Compat with QT...<br>
+ // WARNING : With QT2.x it WILL loose UNICODE data.<br>
+ // Safe even if the QString is null.
+ KviStr(const QString &str);
+
+ KviStr(const KviQCString &str);
+
+ // Fill sonstructor.
+ // Creates a string long fillLen characters filled with character c.<br>
+ KviStr(char c,int fillLen = 1);
+
+ KviStr(const kvi_wchar_t * unicode);
+
+ KviStr(const kvi_wchar_t * unicode,int len);
+
+ // just free(m_ptr)
+ ~KviStr();
+public:
+ //yes...public..but think it as private...:)
+ char *m_ptr; // pointer to allocated buffer , do not change this!
+ int m_len; // string data length not including the terminator
+
+public:
+ //=============================================================================
+ // Basic const interface (read stuff)
+ //=============================================================================
+
+ // Internal data buffer
+ char * ptr() const { return m_ptr; };
+ // Length: fast, cached
+ int len() const { return m_len; };
+
+ // I hate this operator...but sometimes it is really useful
+ // especially in macros (kvi_options.cpp)
+ operator const char * () const { return m_ptr; };
+
+ bool isEmpty() const { return (m_len == 0); };
+ bool hasData() const { return (m_len != 0); };
+
+ // this is better than string = "", it does not call strlen
+ void clear();
+
+ // forces the length of this string to be iLen (iLen does NOT include the trailing null : it is automatically added)
+ void setLength(int iLen);
+
+ // Returns true if there is something "readable" inside the string
+ bool hasNonWhiteSpaceData() const;
+
+ // Character at zero-based index : always safe!
+ char & at(int idx) const { return ((idx < m_len) ? m_ptr[idx] : m_ptr[m_len]); };
+
+ // character checks
+ bool lastCharIs(char ch) const { return (m_len > 0) ? (*(m_ptr + m_len - 1) == ch) : false; };
+ bool firstCharIs(char ch) const { return (*m_ptr == ch); };
+
+ // upper and lower case copies
+ KviStr upper() const;
+ KviStr lower() const;
+ KviStr upperISO88591() const;
+ KviStr lowerISO88591() const;
+
+ // left , right & co.
+ // all parameters are safety-checked
+ KviStr left(int maxLen) const;
+ KviStr right(int maxLen) const ;
+ KviStr middle(int idx,int maxLen) const;
+
+ KviStr leftToFirst(char c,bool bIncluded = false) const;
+ KviStr leftToLast(char c,bool bIncluded = false) const;
+// KviStr leftToFirst(const char * str); const;
+
+ //=============================================================================
+ // Non-const interface (write stuff)
+ //=============================================================================
+
+ // Null terminator is NOT included in len
+ KviStr & setLen(int len);
+ // str must not be 0, but len can be anything (it is checked)
+ KviStr & setStr(const char *str,int len = -1);
+ // Like the special constructor that gets the same args.
+ void extractFromString(const char *begin,const char *end);
+
+
+ // Safe sprintf. This one will never write past the end of the string
+ // It can handle only %s %d %u and %c format flags.
+ KviStr & sprintf(const char *fmt,...);
+
+ // append functions
+ void append(const KviStr &str);
+ void append(const QString &str);
+ void append(char c);
+ void append(const char *str); // str CAN be 0
+ void append(const char *str,int len); // str CAN NOT be 0, and MUST be at least len chars long
+ void append(KviFormatConstructorTag dummy,const char *fmt,...);
+
+ // prepend stuff , same as above
+ void prepend(const KviStr &str);
+ void prepend(const char *str); // str CAN be 0
+ void prepend(const char *str,int len); // str CAN NOT be 0, and MUST be at least len chars long
+
+ // if lastCharIs ch does nothing otherwise appends it
+ void ensureLastCharIs(char ch) { if(!lastCharIs(ch))append(ch); };
+
+ // Change THIS string to uppercase or lowercase
+ void toUpperISO88591();
+ void toUpper(); // this is LOCALE AWARE (in Turkish it maps i to Ý!)
+ void toLowerISO88591();
+ void toLower();
+
+ // Assignment
+ KviStr & operator=(const KviStr &str); // deep copy
+ KviStr & operator=(const char *str); // str can be NULL here
+ KviStr & operator=(char c); // 2 bytes allocated ,m_len = 1
+ KviStr & operator=(const QString &str);
+ KviStr & operator=(const KviQCString &str);
+
+ // Append operators
+ KviStr & operator+=(const KviStr &str) { append(str); return (*this); };
+ KviStr & operator+=(const char *str) { append(str); return (*this); };
+ KviStr & operator+=(char c) { append(c); return (*this); };
+ KviStr & operator+=(const QString &str) { append(str); return (*this); };
+
+ // Comparison
+ bool equalsCI(const KviStr &other) const { if(m_len != other.m_len)return false; return kvi_strEqualCI(m_ptr,other.m_ptr); };
+ bool equalsCS(const KviStr &other) const { if(m_len != other.m_len)return false; return kvi_strEqualCS(m_ptr,other.m_ptr); };
+ bool equalsCI(const char * other) const { return kvi_strEqualCI(m_ptr,other); };
+ bool equalsCS(const char * other) const { return kvi_strEqualCS(m_ptr,other); };
+ bool equalsCIN(const char * other,int len) const { return kvi_strEqualCIN(m_ptr,other,len); };
+ bool equalsCSN(const char * other,int len) const { return kvi_strEqualCSN(m_ptr,other,len); };
+
+ //=============================================================================
+ // HEX and Base64 stuff
+ //=============================================================================
+
+ // HEX transforms functions
+ void bufferToHex(const char *buffer,int len);
+ // Allocates the needed buffer and returns the allocated length,
+ // returns -1 in case of error (and allocates nothing)
+ // The string MUST contain only hex digits, and the digits MUST be in couples. (len % 2) must equal 0!
+ // So this will fail also if there are leading or trailing spaces!
+ int hexToBuffer(char ** buffer,bool bNullToNewlines = false);
+ // BASE64 stuff
+ void bufferToBase64(const char * buffer,int len);
+ // same as hexToBuffer but obviously transforms base64 notation to binary data (len % 4) must equal 0!
+ int base64ToBuffer(char ** buffer,bool bNullToNewlines = false);
+
+ // frees a buffer allocated by hexToBuffer or base64ToBuffer
+ static void freeBuffer(char * buffer);
+
+ //=============================================================================
+ // Splitters
+ //=============================================================================
+
+ // cut
+ KviStr & cutLeft(int len); // kills the first len characters
+ KviStr & cutRight(int len); // kills the last len characters
+ KviStr & cut(int idx,int len);
+ KviStr & cutToFirst(char c,bool bIncluded = true); // cuts the left part of the string up to the first character c or does nothing if the char c is not in the string
+ KviStr & cutToLast(char c,bool bIncluded = true);
+ KviStr & cutFromFirst(char c,bool bIncluded = true);
+ KviStr & cutFromLast(char c,bool bIncluded = true);
+ KviStr & cutToFirst(const char *c,bool bIncluded = true); // cuts the left part of the string up to the first character c or does nothing if the char c is not in the string
+ KviStr & cutToLast(const char *c,bool bIncluded = true);
+ KviStr & cutFromFirst(const char *c,bool bIncluded = true);
+ KviStr & cutFromLast(const char *c,bool bIncluded = true);
+ // & paste
+ KviStr & insert(int idx,const char *data);
+ KviStr & insert(int idx,char c);
+ //Replaces all occurences of char c with the string str
+ KviStr & replaceAll(char c,const char *str);
+ //same as above but with a string
+ KviStr & replaceAll(char *toFind,const char *str,bool bCaseS = true);
+
+ KviStr & transliterate(const char * szToFind,const char * szReplacement);
+
+ // Strips whitespace characters from beginning of this string.
+ KviStr & stripLeftWhiteSpace();
+ KviStr & stripRightWhiteSpace();
+ // Stips inital and final WHITESPACE characters (see man isspace),<br>
+ // and returns a reference to this string.
+ KviStr & stripWhiteSpace();
+
+ // Strips spaces and tabs only
+ KviStr & stripSpace();
+ // Strips all occurences of the character c from the beginning of the string.<br>
+ // Note that c can not be '\0' :)
+ KviStr & stripLeft(char c);
+ KviStr & stripRight(char c);
+
+ //=============================================================================
+ // Tokenize
+ //=============================================================================
+
+ // Extracts (copy to str and remove) a token from this string ,<br>
+ // and returns true if there are more tokens to extract<br>
+ // Does not strip initial separators!!<br>
+ // str can NOT be this string.
+ bool getToken(KviStr &str,char sep);
+ // Does not strip initial separators!<br>
+ // Can assign also to this string.
+ KviStr getToken(char sep);
+ // Extracts a line from the string.<br>
+ // Returns false if there was no data to extract
+ bool getLine(KviStr &str);
+
+ // splits this string in a null-terminated array of strings
+ // separated by sep.
+ KviStr ** splitToArray(char sep,int max,int * realCount) const;
+ //KviStr ** splitToArray(const char * sep,int max,int * realCount) const;
+ static void freeArray(KviStr ** strings);
+ // joins the array to this string
+ // if sep is not 0 , it is inserted between the strings
+ // if bLastSep is true and sep is non 0 , then sep is also appended at the end
+ // of the buffer (after the last string)
+ void joinFromArray(KviStr ** strings,const char * sep = 0,bool bLastSep = false);
+
+ //=============================================================================
+ // Utils
+ //=============================================================================
+
+ // encodes chars that have nonzero in the jumptable
+ // into %HH equivalents
+ KviStr & hexEncodeWithTable(const unsigned char table[256]);
+ KviStr & hexEncodeWhiteSpace();
+ KviStr & hexDecode(const char * pFrom);
+ KviStr & hexDecode(){ return hexDecode(m_ptr); };
+
+ //=============================================================================
+ // Contains / occurence count
+ //=============================================================================
+
+ // Returns true if at least one occurence of str is found
+ bool contains(const char *str,bool caseS=true) const;
+ // Returns true if at least one occurence of character c is found in this string
+ bool contains(char c,bool caseS=true) const;
+ // Returns the number of occurences of string str in this string.<br>
+ // Overlapped matches are counted.
+ int occurences(const char *str,bool caseS=true) const;
+ // Returns the number of occurences of character c in this string
+ int occurences(char c,bool caseS=true) const;
+
+ //=============================================================================
+ // Find
+ //=============================================================================
+
+ // Finds the first occurence of the character c in this string,<br>
+ // and returns its zero-based index or -1 if c can not be found.<br>
+ // c can NOT be '\0' here.
+ int findFirstIdx(char c) const;
+ // Finds the first occurence of the sub-string str in this string,<br>
+ // and returns its zero-based index or -1 if the sub-string can not be found.<br>
+ // str can NOT be 0 here.
+ int findFirstIdx(const char *str,bool caseS = true) const;
+ // Finds the last occurence of the character c in this string,<br>
+ // and returns its zero-based index or -1 if the character can not be found.
+ int findLastIdx(char c) const;
+ // Finds the last occurence of the sub-string str in this string,<br>
+ // and returns its zero-based index or -1 if the sub-string can not be found.<br>
+ // str can NOT be 0 here.
+ int findLastIdx(const char *str,bool caseS = true) const;
+
+ int find(char c,int startIdx) const;
+ int find(const char * str,int startIdx,bool caseS = true) const;
+ int findRev(const char * str,int startIdx,bool caseS = true) const;
+
+ //=============================================================================
+ // Numbers
+ //=============================================================================
+
+ // everything in base 10.... no overflow checks here
+ long toLong(bool *bOk=0) const;
+ unsigned long toULong(bool *bOk=0) const;
+ char toChar(bool *bOk=0) const { return (char)toLong(bOk); };
+ unsigned char toUChar(bool *bOk=0) const { return (unsigned char)toULong(bOk); };
+ int toInt(bool *bOk=0) const { return (int)toLong(bOk); };
+ unsigned int toUInt(bool *bOk=0) const { return (unsigned int)toULong(bOk); };
+ short toShort(bool *bOk=0) const { return (short)toLong(bOk); };
+ unsigned short toUShort(bool *bOk=0) const { return (unsigned short)toLong(bOk); };
+
+ KviStr & setNum(long num);
+ KviStr & setNum(unsigned long num);
+
+ KviStr & setNum(int num) { return setNum((long)num); };
+ KviStr & setNum(unsigned int num) { return setNum((unsigned long)num); };
+ KviStr & setNum(short num) { return setNum((long)num); };
+ KviStr & setNum(unsigned short num) { return setNum((unsigned long)num); };
+ KviStr & setNum(char num) { return setNum((long)num); };
+ KviStr & setNum(unsigned char num) { return setNum((unsigned long)num); };
+
+ // Retuns true if the string contains only digits and an optional '-' character
+ // at the beginning.<be>
+ // Space characters are allowed at the begginning and the end.<br>
+ // There is no overflow check!
+ bool isNum() const;
+ bool isUnsignedNum() const;
+
+ // special functions for multiple bases
+ long toLongExt(bool *bOk = 0,int base = 0);
+ // unsigned long toULongExt(bool *bOk = 0,int base = 0); //never used
+
+ // returns an empty string...
+ // this if often useful!
+ static KviStr & emptyString();
+
+ //=============================================================================
+ // Dead interface
+ //=============================================================================
+
+ // Transform a pointer to a string with all 0 and 1
+ // void pointerToBitString(const void * ptr);
+ // Get a pointer from a string all of 0 and 1 : return 0 if invalid
+ // void * bitStringToPointer();
+
+ //=============================================================================
+ // "External string" helper functions
+ //=============================================================================
+
+ // FIXME: Should it be KviStrExt::contains namespace ?
+ static bool ext_contains(register const char * data,const char * item,bool caseS = true);
+};
+
+// FIXME: the functions below should end in the KviStr namespace ???
+
+
+// Cool string parsing function.
+// It will extract the first found token from the string aux_ptr , and return
+// a pointer to the beginning of the next token , or end of the string.
+// It skips the initial sep characters!
+__KVI_EXTERN KVILIB_API const char * kvi_extractToken(KviStr &str,const char *aux_ptr,char sep =' ');
+// Does not skip the beginning separators!
+// Extracts data from the string up to the next separator character or the end of the string.
+// and returns a pointer to that separator (or string end).
+__KVI_EXTERN KVILIB_API const char * kvi_extractUpTo(KviStr &str,const char *aux_ptr,char sep=' ');
+// Reduced vsnprintf...
+// Handles %s,%c,%d,%u (%% are TWO percents here and not one.)
+// Returns -1 if the formatted string exceeded the buffer length.
+// Otherwise returns the length of the formatted buffer...(not including '\0')
+__KVI_EXTERN KVILIB_API int kvi_vsnprintf(char *buffer,int len,const char *fmt,kvi_va_list list);
+// Reduced vsnprintf: special version for irc.
+// Handles %s,%c,%d,%u (%% are TWO percents here and not one.)
+// Writes up to 510 characters and terminates the string with a CRLF
+// Sets bTruncated if the requested format string was too large to fit in 512 bytes
+// otherwise sets it to false; The buffer MUST be at least 512 bytes long.
+// Always returns the length of the formatted buffer...(max 512 - min 2=CRLF)
+__KVI_EXTERN KVILIB_API int kvi_irc_vsnprintf(char *buffer,const char *fmt,kvi_va_list list,bool *bTruncated);
+
+// WILDCARD EXPRESSION MATCHING FUNCTIONS
+
+// Returns true if the two regular expressions with wildcards matches
+__KVI_EXTERN KVILIB_API bool kvi_matchWildExpr(register const char *m1,register const char *m2);
+// Returns true if the two regular expressions with wildcards matches, case sensitive
+//__KVI_EXTERN bool kvi_matchWildExprCS(register const char *m1,register const char *m2); // actually unused
+// Same as kvi_matchWildExpr but with an additional char that acts as string terminator
+// If there is a match this function returns true and puts the pointers where it stopped in r1 and r2
+__KVI_EXTERN KVILIB_API bool kvi_matchWildExprWithTerminator(register const char *m1,register const char *m2,char terminator,
+ const char ** r1,const char ** r2);
+
+// Returns true if the wildcard expression exp matches the string str
+__KVI_EXTERN KVILIB_API bool kvi_matchStringCI(register const char * exp,register const char * str);
+#define kvi_matchString kvi_matchStringCI
+__KVI_EXTERN KVILIB_API bool kvi_matchStringCS(register const char * exp,register const char * str);
+__KVI_EXTERN KVILIB_API bool kvi_matchStringWithTerminator(register const char * exp,register const char * str,char terminator,const char ** r1,const char ** r2);
+
+// This function works like a particular case of strncmp.
+// It evaluates if str2 is the terminal part of str1.
+// example: if str1 is "this is an experiment" and str2 is "xperiment"
+// return 0.
+// With the index parameter, the match start on str1 from the specified
+// index. For example:
+// if str1 is "this is an experiment" and str2 is "an" we have return !0
+// but "this is an experiment"
+// 012345678901234567890
+// if we call kvi_strsubRevCS("this is an experiment","an", 9) we got a match.
+__KVI_EXTERN KVILIB_API int kvi_strMatchRevCS(const char *str1, const char *str2, int index=-1);
+
+// KviStr comparison non-member operators
+__KVI_EXTERN KVILIB_API inline bool operator==(const KviStr &left,const KviStr &right)
+{ return (left.m_len == right.m_len) ? kvi_strEqualCS(left.m_ptr,right.m_ptr) : false; }
+__KVI_EXTERN KVILIB_API inline bool operator==(const KviStr &left,const char *right)
+{ return kvi_strEqualCS(left.m_ptr,right); }
+__KVI_EXTERN KVILIB_API inline bool operator==(const char *left,const KviStr &right)
+{ return kvi_strEqualCS(left,right.m_ptr); }
+__KVI_EXTERN KVILIB_API inline bool operator!=(const KviStr &left,const KviStr &right)
+{ return !kvi_strEqualCS(left.m_ptr,right.m_ptr); }
+__KVI_EXTERN KVILIB_API inline bool operator!=(const KviStr &left,const char *right)
+{ return !kvi_strEqualCS(left.m_ptr,right); }
+__KVI_EXTERN KVILIB_API inline bool operator!=(const char *left,const KviStr &right)
+{ return !kvi_strEqualCS(left,right.m_ptr); }
+
+__KVI_EXTERN KVILIB_API inline KviStr operator+(const KviStr &left,const KviStr &right)
+{ KviStr ret(left); ret += right; return ret; }
+__KVI_EXTERN KVILIB_API inline KviStr operator+(const KviStr &left,const char *right)
+{ KviStr ret(left); ret += right; return ret; }
+__KVI_EXTERN KVILIB_API inline KviStr operator+(const char *left,const KviStr &right)
+{ KviStr ret(left); ret += right; return ret; }
+__KVI_EXTERN KVILIB_API inline KviStr operator+(const KviStr &left,char right)
+{ KviStr ret(left); ret += right; return ret; }
+__KVI_EXTERN KVILIB_API inline KviStr operator+(char left,const KviStr &right)
+{ KviStr ret(left); ret += right; return ret; }
+
+inline int kvi_compare(const KviStr * p1,const KviStr * p2)
+{
+ return kvi_strcmpCI(p1->ptr(),p2->ptr());
+}
+
+#endif //_KVI_STRING_H_
diff --git a/src/kvilib/core/kvi_stringarray.cpp b/src/kvilib/core/kvi_stringarray.cpp
new file mode 100644
index 00000000..d160ce28
--- /dev/null
+++ b/src/kvilib/core/kvi_stringarray.cpp
@@ -0,0 +1,119 @@
+//=================================================================================================
+//
+// File : kvi_stringarray.cpp
+// Creation date : Tue Jun 6 02:20:20 by Szymon Stefanek
+//
+// This file is part of the KVirc irc client distribution
+// Copyright (C) 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__
+
+
+#include "kvi_stringarray.h"
+#include "kvi_malloc.h"
+
+KviStringArray::KviStringArray()
+{
+ m_uSize = 0;
+ m_pData = 0;
+ m_uHighestIdx = 0;
+}
+
+KviStringArray::~KviStringArray()
+{
+ if(m_pData)clear();
+}
+
+
+void KviStringArray::clear()
+{
+ if(!m_pData)return;
+ for(unsigned int i=0;i<m_uSize;i++)
+ {
+ if(m_pData[i])delete m_pData[i];
+ }
+ kvi_free(m_pData);
+ m_pData = 0;
+ m_uHighestIdx = 0;
+ m_uSize = 0;
+}
+
+void KviStringArray::insert(unsigned int uIdx,KviStr * pVal)
+{
+ if(m_uSize <= uIdx)
+ {
+ unsigned int uOldSize = m_uSize;
+ m_uSize = uIdx + KVI_STRING_ARRAY_FREESPACE_SIZE;
+ m_pData = (KviStr **)kvi_realloc(m_pData,m_uSize * sizeof(KviStr *));
+ for(unsigned int u = uOldSize;u < m_uSize;u++)
+ {
+ m_pData[u] = 0;
+ }
+ } else {
+ if(m_pData[uIdx])delete m_pData[uIdx];
+ }
+ if(uIdx > m_uHighestIdx)m_uHighestIdx = uIdx;
+ m_pData[uIdx] = pVal;
+}
+
+void KviStringArray::remove(unsigned int uIdx)
+{
+ if(uIdx > m_uHighestIdx)return;
+ if(m_pData[uIdx])
+ {
+ delete m_pData[uIdx];
+ m_pData[uIdx] = 0;
+ if(uIdx == m_uHighestIdx)
+ {
+ // shrink the array
+ if(m_uHighestIdx == 0)clear();
+ else {
+ unsigned int u = m_uHighestIdx - 1;
+ while(!m_pData[u])u--;
+ if((m_uHighestIdx - u) > KVI_STRING_ARRAY_FREESPACE_SIZE)shrink(u);
+ else m_uHighestIdx = u; // just set the max index
+ }
+ }
+ }
+}
+
+void KviStringArray::shrink(unsigned int uMaxItem)
+{
+ m_uHighestIdx = uMaxItem;
+ m_uSize = uMaxItem + 1;
+ m_pData = (KviStr **)kvi_realloc(m_pData,sizeof(KviStr *) * m_uSize);
+}
+
+void KviStringArray::copyFrom(KviStringArray * a)
+{
+ clear();
+ m_uSize = a->m_uSize;
+ m_uHighestIdx = a->m_uHighestIdx;
+ if(m_uSize > 0)
+ {
+ m_pData = (KviStr **)kvi_malloc(sizeof(KviStr *) * m_uSize);
+ for(unsigned int i=0;i<m_uSize;i++)
+ {
+ if(a->m_pData[i])m_pData[i] = new KviStr(*(a->m_pData[i]));
+ else m_pData[i] = 0;
+ }
+ } else {
+ m_pData = 0;
+ }
+}
diff --git a/src/kvilib/core/kvi_stringarray.h b/src/kvilib/core/kvi_stringarray.h
new file mode 100644
index 00000000..3db9a564
--- /dev/null
+++ b/src/kvilib/core/kvi_stringarray.h
@@ -0,0 +1,55 @@
+#ifndef _KVI_STRINGARRAY_H_
+#define _KVI_STRINGARRAY_H_
+//=================================================================================================
+//
+// File : kvi_stringarray.h
+// Creation date : Tue Jun 6 02:20:20 by Szymon Stefanek
+//
+// This file is part of the KVirc irc client distribution
+// Copyright (C) 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.
+//
+//=================================================================================================
+
+#include "kvi_settings.h"
+#include "kvi_string.h"
+#include "kvi_heapobject.h"
+
+#define KVI_STRING_ARRAY_FREESPACE_SIZE 16
+
+class KVILIB_API KviStringArray : public KviHeapObject
+{
+public:
+ KviStringArray();
+ ~KviStringArray();
+public:
+ unsigned int m_uSize;
+ unsigned int m_uHighestIdx;
+ KviStr ** m_pData;
+public:
+ void clear();
+ void insert(unsigned int uIdx,KviStr * pVal);
+ void copyFrom(KviStringArray * a);
+ unsigned int size(){ return (m_uSize == 0) ? 0 : (m_uHighestIdx + 1); };
+ bool isEmpty(){ return m_uSize == 0; };
+ void remove(unsigned int uIdx);
+ void shrink(unsigned int uMaxItem);
+ KviStr * uncheckedAt(unsigned int uIdx){ return m_pData[uIdx]; };
+ KviStr * at(unsigned int uIdx){ return m_uSize > uIdx ? m_pData[uIdx] : 0; };
+ KviStr * getAt(unsigned int uIdx){ KviStr * t = at(uIdx); if(t)m_pData[uIdx] = 0; return t; };
+};
+
+#endif //_KVI_STRINGARRAY_H_
diff --git a/src/kvilib/core/kvi_valuelist.h b/src/kvilib/core/kvi_valuelist.h
new file mode 100644
index 00000000..fde9d5b6
--- /dev/null
+++ b/src/kvilib/core/kvi_valuelist.h
@@ -0,0 +1,37 @@
+#ifndef _KVI_VALUELIST_H_
+#define _KVI_VALUELIST_H_
+//=================================================================================================
+//
+// File : kvi_valuelist.h
+// Creation date : Mon Jan 15 2007 04:53 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 <q3valuelist.h>
+ #define KviValueList Q3ValueList
+#else
+ #include <qvaluelist.h>
+ #define KviValueList QValueList
+#endif
+
+#endif //_KVI_VALUELIST_H_