diff options
| author | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-02-24 02:13:59 +0000 | 
|---|---|---|
| committer | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-02-24 02:13:59 +0000 | 
| commit | a6d58bb6052ac8cb01805a48c4ad2f129126116f (patch) | |
| tree | dd867a099fcbb263a8009a9fb22695b87855dad6 /src/kvilib/core/kvi_string.h | |
| download | kvirc-a6d58bb6052ac8cb01805a48c4ad2f129126116f.tar.gz kvirc-a6d58bb6052ac8cb01805a48c4ad2f129126116f.zip | |
Added KDE3 version of kvirc
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/kvirc@1095341 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'src/kvilib/core/kvi_string.h')
| -rw-r--r-- | src/kvilib/core/kvi_string.h | 552 | 
1 files changed, 552 insertions, 0 deletions
| 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_ | 
