1 #ifndef _KVI_STRING_H_
2 #define _KVI_STRING_H_
3 //=============================================================================
4 //
5 //   File : KviCString.h
6 //   Creation date : Fri Mar 19 1999 03:06:26 by Szymon Stefanek
7 //
8 //   This file is part of the KVIrc IRC client distribution
9 //   Copyright (C) 1999-2008 Szymon Stefanek (pragma at kvirc dot net)
10 //
11 //   This program is FREE software. You can redistribute it and/or
12 //   modify it under the terms of the GNU General Public License
13 //   as published by the Free Software Foundation; either version 2
14 //   of the License, or (at your option) any later version.
15 //
16 //   This program is distributed in the HOPE that it will be USEFUL,
17 //   but WITHOUT ANY WARRANTY; without even the implied warranty of
18 //   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 //   See the GNU General Public License for more details.
20 //
21 //   You should have received a copy of the GNU General Public License
22 //   along with this program. If not, write to the Free Software Foundation,
23 //   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24 //
25 //=============================================================================
26 
27 #include "kvi_settings.h"
28 
29 #include <stdio.h>
30 #include <string.h>
31 #include <ctype.h>
32 
33 #ifdef HAVE_STRINGS_H
34 #include <strings.h> // useless ?
35 #endif
36 
37 #include <QByteArray>
38 #include <QtGlobal>
39 
40 #include "kvi_inttypes.h"
41 #include "kvi_stdarg.h"
42 #include "KviHeapObject.h"
43 
44 //
45 //  IRC is not UNICODE ...(yet) :(
46 //
47 
48 #undef __KVI_EXTERN
49 #ifdef _KVI_STRING_CPP_
50 #define __KVI_EXTERN
51 #else
52 #define __KVI_EXTERN extern
53 #endif
54 
55 __KVI_EXTERN KVILIB_API bool kvi_qstringEqualCI(const QString & s1, const QString & s2);
56 
57 // Include inlined assembly implementations if required
58 
59 // Returns true if the string str1 is equal to str2. case sensitive.
60 __KVI_EXTERN KVILIB_API bool kvi_strEqualCS(const char * str1, const char * str2);
61 // Returns true if the forst len characters of string str1 are equal to str2.
62 // case sensitive.
63 // Note that if str1 or str2 are shorter than len characters then are considered as NOT equal!
64 __KVI_EXTERN KVILIB_API bool kvi_strEqualCSN(const char * str1, const char * str2, int len);
65 // no such tricks in non-asm
66 #define kvi_strEqualNoLocaleCI(str1, str2) kvi_strEqualCI(str1, str2)
67 #define kvi_strEqualNoLocaleCIN(str1, str2, len) kvi_strEqualCIN(str1, str2, len)
68 #define kvi_strLen(str) strlen(str)
69 
70 // Returns true if the string str1 is equal to str2.
71 // case insensitive.
72 __KVI_EXTERN KVILIB_API bool kvi_strEqualCI(const char * str1, const char * str2);
73 // Returns true if the forst len characters of string str1 are equal to str2.
74 // case insensitive.
75 // Note that if str1 or str2 are shorter than len characters then are considered as NOT equal!
76 __KVI_EXTERN KVILIB_API bool kvi_strEqualCIN(const char * str1, const char * str2, int len);
77 // My own implementations of strcmp and strncasecmp
78 // Once I wrote it, I KNOW what they do : ALWAYS :)
79 // Note that greater here means that comes AFTER in the alphabetic order.
80 __KVI_EXTERN KVILIB_API int kvi_strcmpCI(const char * str1, const char * str2);
81 //__KVI_EXTERN KVILIB_API int kvi_strcmpCIN(const char *str1,const char *str2,int len);
82 __KVI_EXTERN KVILIB_API int kvi_strcmpCS(const char * str1, const char * str2);
83 
84 // some wide char stuff
85 typedef kvi_u16_t kvi_wchar_t;
86 typedef kvi_u32_t kvi_wslen_t;
87 
88 __KVI_EXTERN KVILIB_API kvi_wslen_t kvi_wstrlen(const kvi_wchar_t * str);
89 __KVI_EXTERN KVILIB_API int kvi_wvsnprintcf(kvi_wchar_t * buffer, kvi_wslen_t len, const char * fmt, kvi_va_list list);
90 __KVI_EXTERN KVILIB_API int kvi_wvsnprintf(kvi_wchar_t * buffer, kvi_wslen_t len, const kvi_wchar_t * fmt, kvi_va_list list);
91 
92 //
93 // A simple string class.<br>
94 // -No data sharing.<br>
95 // -Not UNICODE.<br>
96 // -Has ALWAYS NON-NULL DATA.<br>
97 // -(Maybe)Unsafe :)<br>
98 // WARNING : Handle with care and use at own risk :)<br>
99 //
100 
101 class KVILIB_API KviCString : public KviHeapObject
102 {
103 public:
104 	// No particular reason for these two names...
105 	// It is just because I like it :)
106 
107 	enum KviFormatConstructorTag
108 	{
109 		Format,
110 		Sprintf
111 	};
112 
113 	// Constructors
114 	// Empty string == "", len = 0, 1 byte allocated
115 	KviCString();
116 
117 	// Deep copy of the NULL TERMINATED string (NULL str SAFE)
118 	KviCString(const char * str);
119 
120 	// Copy len characters from string str (NOT NULL str SAFE, str MUST be at least len chars long)
121 	KviCString(const char * str, int len);
122 
123 	// bg and end are pointers to a SINGLE string.<br>
124 	// A string is extracted starting from bg and ending at end (not included).<br>
125 	KviCString(const char * bg, const char * end);
126 
127 	// Format constructor.<br>
128 	// tag is....yes....a dummy number used to resolve ambiguities.<br>
129 	// It is SAFE: will fail only if we run out of memory,<br>
130 	// but can handle only %s %d %u and %c.
131 	KviCString(KviFormatConstructorTag tag, const char * fmt, ...);
132 
133 	// Carbon copy :)...fast
134 	KviCString(const KviCString & str);
135 
136 	// Compat with QT...<br>
137 	// WARNING : With QT2.x it WILL loose UNICODE data.<br>
138 	// Safe even if the QString is null.
139 	KviCString(const QString & str);
140 
141 	KviCString(const QByteArray & str);
142 
143 	// Fill sonstructor.
144 	// Creates a string long fillLen characters filled with character c.<br>
145 	KviCString(char c, int fillLen = 1);
146 
147 	KviCString(const kvi_wchar_t * unicode);
148 
149 	KviCString(const kvi_wchar_t * unicode, int len);
150 
151 	// just free(m_ptr)
152 	~KviCString();
153 
154 public:
155 	//yes...public..but think it as private...:)
156 	char * m_ptr; // pointer to allocated buffer, do not change this!
157 	int m_len;    // string data length not including the terminator
158 
159 public:
160 
161 	// Basic const interface (read stuff)
162 	// Internal data buffer
ptr()163 	char * ptr() const { return m_ptr; };
164 	// Length: fast, cached
len()165 	int len() const { return m_len; };
166 
167 	// I hate this operator...but sometimes it is really useful
168 	// especially in macros (KviOptions.cpp)
169 	operator const char *() const { return m_ptr; };
170 
isEmpty()171 	bool isEmpty() const { return (m_len == 0); };
hasData()172 	bool hasData() const { return (m_len != 0); };
173 
174 	// this is better than string = "", it does not call strlen
175 	void clear();
176 
177 	// Returns true if there is something "readable" inside the string
178 	bool hasNonWhiteSpaceData() const;
179 
180 	// Character at zero-based index : always safe!
at(int idx)181 	char & at(int idx) const { return ((idx < m_len) ? m_ptr[idx] : m_ptr[m_len]); };
182 
183 	// character checks
lastCharIs(char ch)184 	bool lastCharIs(char ch) const { return (m_len > 0) ? (*(m_ptr + m_len - 1) == ch) : false; };
firstCharIs(char ch)185 	bool firstCharIs(char ch) const { return (*m_ptr == ch); };
186 
187 	// upper and lower case copies
188 	KviCString upper() const;
189 	KviCString lower() const;
190 	KviCString upperISO88591() const;
191 	KviCString lowerISO88591() const;
192 
193 	// left, right & co.
194 	// all parameters are safety-checked
195 	KviCString left(int maxLen) const;
196 	KviCString right(int maxLen) const;
197 	KviCString middle(int idx, int maxLen) const;
198 
199 	KviCString leftToFirst(char c, bool bIncluded = false) const;
200 	KviCString leftToLast(char c, bool bIncluded = false) const;
201 	//	KviCString leftToFirst(const char * str); const;
202 
203 	// Non-const interface (write stuff)
204 	// Null terminator is NOT included in len
205 	KviCString & setLen(int len);
206 
207 	// str must not be 0, but len can be anything (it is checked)
208 	KviCString & setStr(const char * str, int len = -1);
209 	// Like the special constructor that gets the same args.
210 	void extractFromString(const char * begin, const char * end);
211 
212 	// Safe sprintf. This one will never write past the end of the string
213 	// It can handle only %s %d %u and %c format flags.
214 	KviCString & sprintf(const char * fmt, ...);
215 
216 	KviCString & vsprintf(const char * fmt, kvi_va_list list);
217 
218 	// append functions
219 	void append(const KviCString & str);
220 	void append(const QString & str);
221 	void append(char c);
222 	void append(const char * str);          // str CAN be 0
223 	void append(const char * str, int len); // str CAN NOT be 0, and MUST be at least len chars long
224 	void append(KviFormatConstructorTag dummy, const char * fmt, ...);
225 
226 	// prepend stuff, same as above
227 	void prepend(const KviCString & str);
228 	void prepend(const char * str);          // str CAN be 0
229 	void prepend(const char * str, int len); // str CAN NOT be 0, and MUST be at least len chars long
230 
231 	// if lastCharIs ch does nothing otherwise appends it
ensureLastCharIs(char ch)232 	void ensureLastCharIs(char ch)
233 	{
234 		if(!lastCharIs(ch))
235 			append(ch);
236 	};
237 
238 	// Change THIS string to uppercase or lowercase
239 	void toUpperISO88591();
240 	void toUpper(); // this is LOCALE AWARE (in Turkish it maps i to Ý!)
241 	void toLowerISO88591();
242 	void toLower();
243 
244 	// Assignment
245 	KviCString & operator=(const KviCString & str); // deep copy
246 	KviCString & operator=(const char * str);       // str can be nullptr here
247 	KviCString & operator=(char c);                 // 2 bytes allocated,m_len = 1
248 	KviCString & operator=(const QString & str);
249 	KviCString & operator=(const QByteArray & str);
250 
251 	// Append operators
252 	KviCString & operator+=(const KviCString & str)
253 	{
254 		append(str);
255 		return (*this);
256 	};
257 	KviCString & operator+=(const char * str)
258 	{
259 		append(str);
260 		return (*this);
261 	};
262 	KviCString & operator+=(char c)
263 	{
264 		append(c);
265 		return (*this);
266 	};
267 	KviCString & operator+=(const QString & str)
268 	{
269 		append(str);
270 		return (*this);
271 	};
272 
273 	// Comparison
equalsCI(const KviCString & other)274 	bool equalsCI(const KviCString & other) const
275 	{
276 		if(m_len != other.m_len)
277 			return false;
278 		return kvi_strEqualCI(m_ptr, other.m_ptr);
279 	};
equalsCS(const KviCString & other)280 	bool equalsCS(const KviCString & other) const
281 	{
282 		if(m_len != other.m_len)
283 			return false;
284 		return kvi_strEqualCS(m_ptr, other.m_ptr);
285 	};
equalsCI(const char * other)286 	bool equalsCI(const char * other) const { return kvi_strEqualCI(m_ptr, other); };
equalsCS(const char * other)287 	bool equalsCS(const char * other) const { return kvi_strEqualCS(m_ptr, other); };
equalsCIN(const char * other,int len)288 	bool equalsCIN(const char * other, int len) const { return kvi_strEqualCIN(m_ptr, other, len); };
equalsCSN(const char * other,int len)289 	bool equalsCSN(const char * other, int len) const { return kvi_strEqualCSN(m_ptr, other, len); };
290 
291 	// HEX and Base64 stuff
292 	// HEX transforms functions
293 	void bufferToHex(const char * buffer, int len);
294 	// Allocates the needed buffer and returns the allocated length,
295 	// returns -1 in case of error (and allocates nothing)
296 	// The string MUST contain only hex digits, and the digits MUST be in couples. (len % 2) must equal 0!
297 	// So this will fail also if there are leading or trailing spaces!
298 	int hexToBuffer(char ** buffer, bool bNullToNewlines = false);
299 	// BASE64 stuff
300 	void bufferToBase64(const char * buffer, int len);
301 	// same as hexToBuffer but obviously transforms base64 notation to binary data (len % 4) must equal 0!
302 	int base64ToBuffer(char ** buffer, bool bNullToNewlines = false);
303 
304 	// frees a buffer allocated by hexToBuffer or base64ToBuffer
305 	static void freeBuffer(char * buffer);
306 
307 	// Splitters
308 	// cut
309 	KviCString & cutLeft(int len);  // kills the first len characters
310 	KviCString & cutRight(int len); // kills the last len characters
311 	KviCString & cut(int idx, int len);
312 	KviCString & 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
313 	KviCString & cutToLast(char c, bool bIncluded = true);
314 	KviCString & cutFromFirst(char c, bool bIncluded = true);
315 	KviCString & cutFromLast(char c, bool bIncluded = true);
316 	KviCString & 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
317 	KviCString & cutToLast(const char * c, bool bIncluded = true);
318 	KviCString & cutFromFirst(const char * c, bool bIncluded = true);
319 	KviCString & cutFromLast(const char * c, bool bIncluded = true);
320 	// & paste
321 	KviCString & insert(int idx, const char * data);
322 	KviCString & insert(int idx, char c);
323 	//Replaces all occurrences of char c with the string str
324 	KviCString & replaceAll(const char c, const char * str);
325 	//same as above but with a string
326 	KviCString & replaceAll(const char * toFind, const char * str, bool bCaseS = true);
327 
328 	KviCString & transliterate(const char * szToFind, const char * szReplacement);
329 
330 	// Strips whitespace characters from beginning of this string.
331 	KviCString & stripLeftWhiteSpace();
332 	KviCString & stripRightWhiteSpace();
333 	// Strips initial and final WHITESPACE characters (see man isspace),<br>
334 	// and returns a reference to this string.
335 	KviCString & trim();
336 
337 	// Strips spaces and tabs only
338 	KviCString & stripSpace();
339 	// Strips all occurrences of the character c from the beginning of the string.<br>
340 	// Note that c can not be '\0' :)
341 	KviCString & stripLeft(char c);
342 	KviCString & stripRight(char c);
343 
344 	// either "truncate to" or "add padding up" to iLen characters.
345 	KviCString & padRight(int iLen, const char c = '\0');
346 
347 	// Tokenize
348 	// Extracts (copy to str and remove) a token from this string,<br>
349 	// and returns true if there are more tokens to extract<br>
350 	// Does not strip initial separators!!<br>
351 	// str can NOT be this string.
352 	bool getToken(KviCString & str, char sep);
353 	// Does not strip initial separators!<br>
354 	// Can assign also to this string.
355 	KviCString getToken(char sep);
356 	// Extracts a line from the string.<br>
357 	// Returns false if there was no data to extract
358 	bool getLine(KviCString & str);
359 
360 	// splits this string in a null-terminated array of strings
361 	// separated by sep.
362 	KviCString ** splitToArray(char sep, int max, int * realCount) const;
363 	//KviCString ** splitToArray(const char * sep,int max,int * realCount) const;
364 	static void freeArray(KviCString ** strings);
365 	// joins the array to this string
366 	// if sep is not 0, it is inserted between the strings
367 	// if bLastSep is true and sep is non 0, then sep is also appended at the end
368 	// of the buffer (after the last string)
369 	void joinFromArray(KviCString ** strings, const char * sep = nullptr, bool bLastSep = false);
370 
371 	// Utils
372 	// encodes chars that have nonzero in the jumptable
373 	// into %HH equivalents
374 	KviCString & hexEncodeWithTable(const unsigned char table[256]);
375 	KviCString & hexEncodeWhiteSpace();
376 	KviCString & hexDecode(const char * pFrom);
hexDecode()377 	KviCString & hexDecode() { return hexDecode(m_ptr); };
378 
379 	// Contains / occurrence count
380 	// Returns true if at least one occurrence of str is found
381 	bool contains(const char * str, bool caseS = true) const;
382 	// Returns true if at least one occurrence of character c is found in this string
383 	bool contains(char c, bool caseS = true) const;
384 	// Returns the number of occurrences of string str in this string.<br>
385 	// Overlapped matches are counted.
386 	int occurrences(const char * str, bool caseS = true) const;
387 	// Returns the number of occurrences of character c in this string
388 	int occurrences(char c, bool caseS = true) const;
389 
390 	// Find
391 	// Finds the first occurrence of the character c in this string,<br>
392 	// and returns its zero-based index or -1 if c can not be found.<br>
393 	// c can NOT be '\0' here.
394 	int findFirstIdx(char c) const;
395 	// Finds the first occurrence of the sub-string str in this string,<br>
396 	// and returns its zero-based index or -1 if the sub-string can not be found.<br>
397 	// str can NOT be 0 here.
398 	int findFirstIdx(const char * str, bool caseS = true) const;
399 	// Finds the last occurrence of the character c in this string,<br>
400 	// and returns its zero-based index or -1 if the character can not be found.
401 	int findLastIdx(char c) const;
402 	// Finds the last occurrence of the sub-string str in this string,<br>
403 	// and returns its zero-based index or -1 if the sub-string can not be found.<br>
404 	// str can NOT be 0 here.
405 	int findLastIdx(const char * str, bool caseS = true) const;
406 
407 	int find(char c, int startIdx) const;
408 	int find(const char * str, int startIdx, bool caseS = true) const;
409 	int findRev(const char * str, int startIdx, bool caseS = true) const;
410 
411 	// Numbers
412 	// everything in base 10.... no overflow checks here
413 	long toLong(bool * bOk = nullptr) const;
414 	unsigned long toULong(bool * bOk = nullptr) const;
415 	long long toLongLong(bool * bOk = nullptr) const;
416 	unsigned long long toULongLong(bool * bOk = nullptr) const;
417 	char toChar(bool * bOk = nullptr) const { return (char)toLong(bOk); };
418 	unsigned char toUChar(bool * bOk = nullptr) const { return (unsigned char)toULong(bOk); };
419 	int toInt(bool * bOk = nullptr) const { return (int)toLong(bOk); };
420 	unsigned int toUInt(bool * bOk = nullptr) const { return (unsigned int)toULong(bOk); };
421 	short toShort(bool * bOk = nullptr) const { return (short)toLong(bOk); };
422 	unsigned short toUShort(bool * bOk = nullptr) const { return (unsigned short)toLong(bOk); };
423 
424 	KviCString & setNum(long num);
425 	KviCString & setNum(unsigned long num);
426 
setNum(int num)427 	KviCString & setNum(int num) { return setNum((long)num); };
setNum(unsigned int num)428 	KviCString & setNum(unsigned int num) { return setNum((unsigned long)num); };
setNum(short num)429 	KviCString & setNum(short num) { return setNum((long)num); };
setNum(unsigned short num)430 	KviCString & setNum(unsigned short num) { return setNum((unsigned long)num); };
setNum(char num)431 	KviCString & setNum(char num) { return setNum((long)num); };
setNum(unsigned char num)432 	KviCString & setNum(unsigned char num) { return setNum((unsigned long)num); };
433 
434 	// Returns true if the string contains only digits and an optional '-' character
435 	// at the beginning.<be>
436 	// Space characters are allowed at the begginning and the end.<br>
437 	// There is no overflow check!
438 	bool isNum() const;
439 	bool isUnsignedNum() const;
440 
441 	// special functions for multiple bases
442 	long toLongExt(bool * bOk = nullptr, int base = 0);
443 	// unsigned long toULongExt(bool *bOk = nullptr,int base = 0); //never used
444 
445 	// returns an empty string...
446 	// this if often useful!
447 	static KviCString & emptyString();
448 
449 	// Dead interface
450 
451 	// Transform a pointer to a string with all 0 and 1
452 	// void pointerToBitString(const void * ptr);
453 	// Get a pointer from a string all of 0 and 1 : return nullptr if invalid
454 	// void * bitStringToPointer();
455 
456 	// "External string" helper functions
457 
458 	// FIXME: Should it be KviCStringExt::contains namespace ?
459 	static bool ext_contains(const char * data, const char * item, bool caseS = true);
460 };
461 
462 // FIXME: the functions below should end in the KviCString namespace ???
463 
464 // Cool string parsing function.
465 // It will extract the first found token from the string aux_ptr, and return
466 // a pointer to the beginning of the next token, or end of the string.
467 // It skips the initial sep characters!
468 __KVI_EXTERN KVILIB_API const char * kvi_extractToken(KviCString & str, const char * aux_ptr, char sep = ' ');
469 // Does not skip the beginning separators!
470 // Extracts data from the string up to the next separator character or the end of the string.
471 // and returns a pointer to that separator (or string end).
472 __KVI_EXTERN KVILIB_API const char * kvi_extractUpTo(KviCString & str, const char * aux_ptr, char sep = ' ');
473 // Reduced vsnprintf...
474 // Handles %s,%c,%d,%u  (%% are TWO percents here and not one.)
475 // Returns -1 if the formatted string exceeded the buffer length.
476 // Otherwise returns the length of the formatted buffer...(not including '\0')
477 __KVI_EXTERN KVILIB_API int kvi_vsnprintf(char * buffer, int len, const char * fmt, kvi_va_list list);
478 // Reduced vsnprintf: special version for irc.
479 // Handles %s,%c,%d,%u  (%% are TWO percents here and not one.)
480 // Writes up to 510 characters and terminates the string with a CRLF
481 // Sets bTruncated if the requested format string was too large to fit in 512 bytes
482 // otherwise sets it to false; The buffer MUST be at least 512 bytes long.
483 // Always returns the length of the formatted buffer...(max 512 - min 2=CRLF)
484 __KVI_EXTERN KVILIB_API int kvi_irc_vsnprintf(char * buffer, const char * fmt, kvi_va_list list, bool * bTruncated);
485 
486 // WILDCARD EXPRESSION MATCHING FUNCTIONS
487 
488 // Returns true if the two regular expressions with wildcards matches
489 __KVI_EXTERN KVILIB_API bool kvi_matchWildExpr(const char * m1, const char * m2);
490 // Returns true if the two regular expressions with wildcards matches, case sensitive
491 //__KVI_EXTERN bool kvi_matchWildExprCS(const char *m1, const char *m2); // actually unused
492 // Same as kvi_matchWildExpr but with an additional char that acts as string terminator
493 // If there is a match this function returns true and puts the pointers where it stopped in r1 and r2
494 __KVI_EXTERN KVILIB_API bool kvi_matchWildExprWithTerminator(const char * m1, const char * m2, char terminator,
495     const char ** r1, const char ** r2);
496 
497 // Returns true if the wildcard expression exp matches the string str
498 __KVI_EXTERN KVILIB_API bool kvi_matchStringCI(const char * exp, const char * str);
499 #define kvi_matchString kvi_matchStringCI
500 __KVI_EXTERN KVILIB_API bool kvi_matchStringCS(const char * exp, const char * str);
501 __KVI_EXTERN KVILIB_API bool kvi_matchStringWithTerminator(const char * exp, const char * str, char terminator, const char ** r1, const char ** r2);
502 
503 // This function works like a particular case of strncmp.
504 // It evaluates if str2 is the terminal part of str1.
505 // example: if str1 is "this is an experiment" and str2 is "xperiment"
506 // return 0.
507 // With the index parameter, the match start on str1 from the specified
508 // index. For example:
509 // if str1 is "this is an experiment" and str2 is "an" we have return !0
510 // but "this is an experiment"
511 //      012345678901234567890
512 // if we call kvi_strsubRevCS("this is an experiment","an", 9) we got a match.
513 __KVI_EXTERN KVILIB_API int kvi_strMatchRevCS(const char * str1, const char * str2, int index = -1);
514 
515 // KviCString comparison non-member operators
516 __KVI_EXTERN inline bool operator==(const KviCString & left, const KviCString & right)
517 {
518 	return (left.m_len == right.m_len) ? kvi_strEqualCS(left.m_ptr, right.m_ptr) : false;
519 }
520 __KVI_EXTERN inline bool operator==(const KviCString & left, const char * right)
521 {
522 	return kvi_strEqualCS(left.m_ptr, right);
523 }
524 __KVI_EXTERN inline bool operator==(const char * left, const KviCString & right)
525 {
526 	return kvi_strEqualCS(left, right.m_ptr);
527 }
528 __KVI_EXTERN inline bool operator!=(const KviCString & left, const KviCString & right)
529 {
530 	return !kvi_strEqualCS(left.m_ptr, right.m_ptr);
531 }
532 __KVI_EXTERN inline bool operator!=(const KviCString & left, const char * right)
533 {
534 	return !kvi_strEqualCS(left.m_ptr, right);
535 }
536 __KVI_EXTERN inline bool operator!=(const char * left, const KviCString & right)
537 {
538 	return !kvi_strEqualCS(left, right.m_ptr);
539 }
540 
541 __KVI_EXTERN inline KviCString operator+(const KviCString & left, const KviCString & right)
542 {
543 	KviCString ret(left);
544 	ret += right;
545 	return ret;
546 }
547 __KVI_EXTERN inline KviCString operator+(const KviCString & left, const char * right)
548 {
549 	KviCString ret(left);
550 	ret += right;
551 	return ret;
552 }
553 __KVI_EXTERN inline KviCString operator+(const char * left, const KviCString & right)
554 {
555 	KviCString ret(left);
556 	ret += right;
557 	return ret;
558 }
559 __KVI_EXTERN inline KviCString operator+(const KviCString & left, char right)
560 {
561 	KviCString ret(left);
562 	ret += right;
563 	return ret;
564 }
565 __KVI_EXTERN inline KviCString operator+(char left, const KviCString & right)
566 {
567 	KviCString ret(left);
568 	ret += right;
569 	return ret;
570 }
571 
kvi_compare(const KviCString * p1,const KviCString * p2)572 inline int kvi_compare(const KviCString * p1, const KviCString * p2)
573 {
574 	return kvi_strcmpCI(p1->ptr(), p2->ptr());
575 }
576 
577 #endif //_KVI_STRING_H_
578