diff options
Diffstat (limited to 'src/kvilib/core')
| -rw-r--r-- | src/kvilib/core/Makefile.am | 5 | ||||
| -rw-r--r-- | src/kvilib/core/kvi_bswap.h | 63 | ||||
| -rw-r--r-- | src/kvilib/core/kvi_error.cpp | 237 | ||||
| -rw-r--r-- | src/kvilib/core/kvi_error.h | 188 | ||||
| -rw-r--r-- | src/kvilib/core/kvi_heapobject.cpp | 96 | ||||
| -rw-r--r-- | src/kvilib/core/kvi_heapobject.h | 50 | ||||
| -rw-r--r-- | src/kvilib/core/kvi_inttypes.h | 95 | ||||
| -rw-r--r-- | src/kvilib/core/kvi_malloc.cpp | 198 | ||||
| -rw-r--r-- | src/kvilib/core/kvi_malloc.h | 88 | ||||
| -rw-r--r-- | src/kvilib/core/kvi_memmove.cpp | 253 | ||||
| -rw-r--r-- | src/kvilib/core/kvi_memmove.h | 105 | ||||
| -rw-r--r-- | src/kvilib/core/kvi_pointerhashtable.h | 999 | ||||
| -rw-r--r-- | src/kvilib/core/kvi_pointerlist.h | 1069 | ||||
| -rw-r--r-- | src/kvilib/core/kvi_qcstring.h | 39 | ||||
| -rw-r--r-- | src/kvilib/core/kvi_qstring.cpp | 1125 | ||||
| -rw-r--r-- | src/kvilib/core/kvi_qstring.h | 293 | ||||
| -rw-r--r-- | src/kvilib/core/kvi_strasm.h | 194 | ||||
| -rw-r--r-- | src/kvilib/core/kvi_string.cpp | 3063 | ||||
| -rw-r--r-- | src/kvilib/core/kvi_string.h | 552 | ||||
| -rw-r--r-- | src/kvilib/core/kvi_stringarray.cpp | 119 | ||||
| -rw-r--r-- | src/kvilib/core/kvi_stringarray.h | 55 | ||||
| -rw-r--r-- | src/kvilib/core/kvi_valuelist.h | 37 | 
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 0000000..c84487e --- /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 0000000..5d5ef5b --- /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 0000000..6497c75 --- /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 0000000..7ab55e8 --- /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 0000000..7568086 --- /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 0000000..3d1638c --- /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 0000000..6405ee7 --- /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 0000000..9c418ec --- /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 0000000..8a7204a --- /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 0000000..1beb920 --- /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 0000000..d1319a4 --- /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 0000000..9066c09 --- /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 0000000..381780c --- /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 0000000..0693e20 --- /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 0000000..eba255a --- /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 0000000..c82063e --- /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 0000000..5d3b19c --- /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 0000000..3f20135 --- /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 0000000..602173c --- /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 0000000..d160ce2 --- /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 0000000..3db9a56 --- /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 0000000..fde9d5b --- /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_  | 
