1 //=============================================================================
2 //
3 // File : KviCString.cpp
4 // Creation date : Fri Mar 19 1999 03:20:45 by Szymon Stefanek
5 //
6 // This file is part of the KVIrc IRC client distribution
7 // Copyright (C) 1999-2008 Szymon Stefanek (pragma at kvirc dot net)
8 //
9 // This program is FREE software. You can redistribute it and/or
10 // modify it under the terms of the GNU General Public License
11 // as published by the Free Software Foundation; either version 2
12 // of the License, or (at your option) any later version.
13 //
14 // This program is distributed in the HOPE that it will be USEFUL,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 // See the GNU General Public License for more details.
18 //
19 // You should have received a copy of the GNU General Public License
20 // along with this program. If not, write to the Free Software Foundation,
21 // Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 //
23 //=============================================================================
24
25 #include "kvi_debug.h"
26
27 #define _KVI_STRING_CPP_
28
29 #include "KviCString.h"
30 #include "KviMemory.h"
31
32 #include <QString>
33
34 static char hexdigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
35
kvi_wstrlen(const kvi_wchar_t * str)36 kvi_wslen_t kvi_wstrlen(const kvi_wchar_t * str)
37 {
38 const kvi_wchar_t * ptr = str;
39 while(*ptr)
40 ptr++;
41 return (ptr - str);
42 }
43
kvi_qstringEqualCI(const QString & s1,const QString & s2)44 bool kvi_qstringEqualCI(const QString & s1, const QString & s2)
45 {
46 const QChar * p1 = s1.unicode();
47 const QChar * p2 = s2.unicode();
48 int l = s1.length() < s2.length() ? s1.length() : s2.length();
49
50 while(l-- && (p1->toLower() == p2->toLower()))
51 p1++, p2++;
52
53 if(l == -1)
54 return true;
55 return false;
56 }
57
kvi_matchStringCI(const char * exp,const char * str)58 bool kvi_matchStringCI(const char * exp, const char * str)
59 {
60 // a
61 // .
62 // exp = a*x?mem*a
63 // str = arexoxmexamemizazv
64 // .
65 // n
66 const char * afterWild = nullptr;
67 const char * nextStrToCheck = nullptr;
68
69 while(*exp)
70 {
71 if(*exp == '*')
72 {
73 // exp is a wildcard...
74 afterWild = ++exp;
75 nextStrToCheck = str + 1;
76 if(!(*exp))
77 return true; // and it's the last char in the string: matches everything ahead
78 continue;
79 }
80
81 if(!(*str))
82 return false; // str finished but we had something to match :(
83
84 if(tolower(*exp) == tolower(*str))
85 {
86 // chars matched
87 ++exp;
88 ++str;
89 if((!(*exp)) && *str)
90 goto check_recovery;
91 continue;
92 }
93
94 if(*exp == '?')
95 {
96 // any-char wildcard
97 ++exp;
98 ++str;
99 continue;
100 }
101
102 check_recovery:
103 // chars unmatched!!!
104 if(afterWild)
105 {
106 // we had a wildcard in exp...
107 // let's use this jolly then
108 exp = afterWild;
109 str = nextStrToCheck;
110 nextStrToCheck++;
111 // and try to compare now
112 continue;
113 }
114
115 return false; // no match :(
116 }
117 return (!(*str));
118 }
119
kvi_matchStringCS(const char * exp,const char * str)120 bool kvi_matchStringCS(const char * exp, const char * str)
121 {
122 // a
123 // .
124 // exp = a*x?mem*a
125 // str = arexoxmexamemizazv
126 // .
127 // n
128 const char * afterWild = nullptr;
129 const char * nextStrToCheck = nullptr;
130
131 while(*exp)
132 {
133 if(*exp == '*')
134 {
135 // exp is a wildcard...
136 afterWild = ++exp;
137 nextStrToCheck = str + 1;
138 if(!(*exp))
139 return true; // and it's the last char in the string: matches everything ahead
140 continue;
141 }
142
143 if(!(*str))
144 return false; // str finished but we had something to match :(
145
146 if(*exp == *str)
147 {
148 // chars matched
149 ++exp;
150 ++str;
151 if((!(*exp)) && *str)
152 goto check_recovery;
153 continue;
154 }
155
156 if(*exp == '?')
157 {
158 // any-char wildcard
159 ++exp;
160 ++str;
161 continue;
162 }
163
164 check_recovery:
165 // chars unmatched!!!
166 if(afterWild)
167 {
168 // we had a wildcard in exp...
169 // let's use this jolly then
170 exp = afterWild;
171 str = nextStrToCheck;
172 nextStrToCheck++;
173 // and try to compare now
174 continue;
175 }
176
177 return false; // no match :(
178 }
179 return (!(*str));
180 }
181
kvi_matchStringWithTerminator(const char * exp,const char * str,char terminator,const char ** r1,const char ** r2)182 bool kvi_matchStringWithTerminator(const char * exp, const char * str, char terminator, const char ** r1, const char ** r2)
183 {
184 #define NOT_AT_END(__str) (*__str && (*__str != terminator))
185
186 // a
187 // .
188 // exp = a*x?mem*a
189 // str = arexoxmexamemizazv
190 // .
191 // n
192 const char * afterWild = nullptr;
193 const char * nextStrToCheck = nullptr;
194
195 while(NOT_AT_END(exp))
196 {
197 if(*exp == '*')
198 {
199 // exp is a wildcard...
200 afterWild = ++exp;
201 nextStrToCheck = str + 1;
202 if(!(NOT_AT_END(exp)))
203 {
204 while(NOT_AT_END(str))
205 str++;
206 *r1 = exp;
207 *r2 = str;
208 return true; // and it's the last char in the string: matches everything ahead
209 }
210 continue;
211 }
212
213 if(!(*str))
214 return false; // str finished but we had something to match :(
215
216 if(tolower(*exp) == tolower(*str))
217 {
218 // chars matched
219 ++exp;
220 ++str;
221 if((!(NOT_AT_END(exp))) && NOT_AT_END(str))
222 goto check_recovery;
223 continue;
224 }
225
226 if(*exp == '?')
227 {
228 // any-char wildcard
229 ++exp;
230 ++str;
231 continue;
232 }
233
234 check_recovery:
235 // chars unmatched!!!
236 if(afterWild)
237 {
238 // we had a wildcard in exp...
239 // let's use this jolly then
240 exp = afterWild;
241 str = nextStrToCheck;
242 nextStrToCheck++;
243 // and try to compare now
244 continue;
245 }
246
247 return false; // no match :(
248 }
249 *r1 = exp;
250 *r2 = str;
251 return (!(NOT_AT_END(str)));
252
253 #undef NOT_AT_END
254 }
255
kvi_matchWildExpr(const char * m1,const char * m2)256 bool kvi_matchWildExpr(const char * m1, const char * m2)
257 {
258 //Matches two regular expressions containging wildcards (* and ?)
259
260 // s1
261 // m1
262 // mask1 : *xor
263 // mask2 : xorand*xor
264 // m2
265 // s2
266
267 // s2
268 // m2
269 // |
270 // XorT!xor@111.111.111.11
271 //
272 // *!*@*.net
273 // |
274 // m1
275 // s1
276 //
277
278 if(!(m1 && m2 && (*m1)))
279 return false;
280 const char * savePos1 = nullptr;
281 const char * savePos2 = m2;
282 while(*m1)
283 {
284 //loop managed by m1 (initially first mask)
285 if(*m1 == '*')
286 {
287 //Found a wildcard in m1
288 savePos1 = ++m1; //move to the next char and save the position...this is our jolly
289 if(!*savePos1)
290 return true; //last was a wildcard, matches everything ahead...
291 savePos2 = m2 + 1; //next return state for the second string
292 continue; //and return
293 }
294 if(!(*m2))
295 return false; //m2 finished and we had something to match here!
296 if(tolower(*m1) == tolower(*m2))
297 {
298 //chars matched
299 m1++; //Go ahead in the two strings
300 m2++; //
301 if((!(*m1)) && *m2 && savePos1)
302 {
303 //m1 finished, but m2 not yet and we have a savePosition for m1 (there was a wildcard)...
304 //retry matching the string following the * from the savePos2 (one char ahead last time)
305 m1 = savePos1; //back to char after wildcard
306 m2 = savePos2; //back to last savePos2
307 savePos2++; //next savePos2 will be next char
308 }
309 }
310 else
311 {
312 if(*m2 == '*')
313 {
314 //A wlidcard in the second string
315 //Invert the game : mask1 <-> mask2
316 //mask2 now leads the game...
317 savePos1 = m1; //aux
318 m1 = m2; //...swap
319 m2 = savePos1; //...swap
320 savePos1 = m1; //sync save pos1
321 savePos2 = m2 + 1; //sync save pos2
322 continue; //...and again
323 }
324 // m1 != m2, m1 != *, m2 != *
325 if((*m1 == '?') || (*m2 == '?'))
326 {
327 m1++;
328 m2++;
329 if((!(*m1)) && *m2 && savePos1)
330 {
331 //m1 finished, but m2 not yet and we have a savePosition for m1 (there was a wildcard)...
332 //retry matching the string following the * from the savePos2 (one char ahead last time)
333 m1 = savePos1; //back to char after wildcard
334 m2 = savePos2; //back to last savePos2
335 savePos2++; //next savePos2 will be next char
336 }
337 }
338 else
339 {
340 if(savePos1)
341 {
342 //Have a jolly man...allow not matching...
343 m1 = savePos1; //go back to char after wildcard...need to rematch...
344 m2 = savePos2; //back to last savePos2
345 savePos2++; //and set next savePos2
346 }
347 else
348 return false; //No previous wildcards...not matched!
349 }
350 }
351 }
352 return (!(*m2)); //m1 surely finished, so for the match, m2 must be finished too
353 }
354
355 /*
356
357 WARNING: Don't remove: working code but actually unused in KVIrc
358 Later it might become useful
359
360 bool kvi_matchWildExprCS(const char *m1,const char *m2)
361 {
362 if(!(m1 && m2 && (*m1)))return false;
363 const char * savePos1 = nullptr;
364 const char * savePos2 = m2;
365 while(*m1){ //loop managed by m1 (initially first mask)
366 if(*m1=='*'){
367 //Found a wildcard in m1
368 savePos1 = ++m1; //move to the next char and save the position...this is our jolly
369 if(!*savePos1)return true; //last was a wildcard, matches everything ahead...
370 savePos2 = m2+1; //next return state for the second string
371 continue; //and return
372 }
373 if(!(*m2))return false; //m2 finished and we had something to match here!
374 if((*m1)==(*m2)){
375 //chars matched
376 m1++; //Go ahead in the two strings
377 m2++; //
378 if((!(*m1)) && *m2 && savePos1){
379 //m1 finished, but m2 not yet and we have a savePosition for m1 (there was a wildcard)...
380 //retry matching the string following the * from the savePos2 (one char ahead last time)
381 m1 = savePos1; //back to char after wildcard
382 m2 = savePos2; //back to last savePos2
383 savePos2++; //next savePos2 will be next char
384 }
385 } else {
386 if(*m2 == '*'){
387 //A wlidcard in the second string
388 //Invert the game : mask1 <-> mask2
389 //mask2 now leads the game...
390 savePos1 = m1; //aux
391 m1 = m2; //...swap
392 m2 = savePos1; //...swap
393 savePos1 = m1; //sync save pos1
394 savePos2 = m2 + 1; //sync save pos2
395 continue; //...and again
396 }
397 if(savePos1){ //Have a jolly man...allow not matching...
398 m1 = savePos1; //go back to char after wildcard...need to rematch...
399 m2 = savePos2; //back to last savePos2
400 savePos2++; //and set next savePos2
401 } else return false; //No previous wildcards...not matched!
402 }
403 }
404 return (!(*m2)); //m1 surely finished, so for the match, m2 must be finished too
405
406 }
407 */
408
kvi_matchWildExprWithTerminator(const char * m1,const char * m2,char terminator,const char ** r1,const char ** r2)409 bool kvi_matchWildExprWithTerminator(const char * m1, const char * m2, char terminator,
410 const char ** r1, const char ** r2)
411 {
412 //Matches two regular expressions containging wildcards
413
414 #define NOT_AT_END(__str) (*__str && (*__str != terminator))
415
416 bool bSwapped = false;
417 if(!(m1 && m2 && (NOT_AT_END(m1))))
418 return false;
419 const char * savePos1 = nullptr;
420 const char * savePos2 = m2;
421 while(NOT_AT_END(m1))
422 {
423 //loop managed by m1 (initially first mask)
424 if(*m1 == '*')
425 {
426 //Found a wildcard in m1
427 savePos1 = ++m1; //move to the next char and save the position...this is our jolly
428 if(!NOT_AT_END(savePos1))
429 {
430 //last was a wildcard, matches everything ahead...
431 while(NOT_AT_END(m2))
432 m2++;
433 *r1 = bSwapped ? m2 : m1;
434 *r2 = bSwapped ? m1 : m2;
435 return true;
436 }
437 savePos2 = m2 + 1; //next return state for the second string
438 continue; //and return
439 }
440 if(!NOT_AT_END(m2))
441 return false; //m2 finished and we had something to match here!
442 if(tolower(*m1) == tolower(*m2))
443 {
444 //chars matched
445 m1++; //Go ahead in the two strings
446 m2++; //
447 if((!NOT_AT_END(m1)) && NOT_AT_END(m2) && savePos1)
448 {
449 //m1 finished, but m2 not yet and we have a savePosition for m1 (there was a wildcard)...
450 //retry matching the string following the * from the savePos2 (one char ahead last time)
451 m1 = savePos1; //back to char after wildcard
452 m2 = savePos2; //back to last savePos2
453 savePos2++; //next savePos2 will be next char
454 }
455 }
456 else
457 {
458 if(*m2 == '*')
459 {
460 //A wlidcard in the second string
461 //Invert the game : mask1 <-> mask2
462 //mask2 now leads the game...
463 bSwapped = !bSwapped;
464 savePos1 = m1; //aux
465 m1 = m2; //...swap
466 m2 = savePos1; //...swap
467 savePos1 = m1; //sync save pos1
468 savePos2 = m2 + 1; //sync save pos2
469 continue; //...and again
470 }
471 // m1 != m2, m1 != *, m2 != *
472 if((*m1 == '?') || (*m2 == '?'))
473 {
474 m1++;
475 m2++;
476 if((!NOT_AT_END(m1)) && NOT_AT_END(m2) && savePos1)
477 {
478 //m1 finished, but m2 not yet and we have a savePosition for m1 (there was a wildcard)...
479 //retry matching the string following the * from the savePos2 (one char ahead last time)
480 m1 = savePos1; //back to char after wildcard
481 m2 = savePos2; //back to last savePos2
482 savePos2++; //next savePos2 will be next char
483 }
484 }
485 else
486 {
487 if(savePos1)
488 {
489 //Have a jolly man...allow not matching...
490 m1 = savePos1; //go back to char after wildcard...need to rematch...
491 m2 = savePos2; //back to last savePos2
492 savePos2++; //and set next savePos2
493 }
494 else
495 return false; //No previous wildcards...not matched!
496 }
497 }
498 }
499 *r1 = bSwapped ? m2 : m1;
500 *r2 = bSwapped ? m1 : m2;
501
502 return (!NOT_AT_END(m2)); //m1 surely finished, so for the match, m2 must be finished too
503
504 #undef NOT_AT_END
505 }
506
kvi_extractToken(KviCString & str,const char * aux_ptr,char sep)507 const char * kvi_extractToken(KviCString & str, const char * aux_ptr, char sep)
508 {
509 KVI_ASSERT(aux_ptr);
510 while(*aux_ptr && (*aux_ptr == sep))
511 aux_ptr++;
512 const char * p = aux_ptr;
513 while(*p && (*p != sep))
514 p++;
515 str.m_len = p - aux_ptr;
516 str.m_ptr = (char *)KviMemory::reallocate(str.m_ptr, str.m_len + 1);
517 KviMemory::copy(str.m_ptr, aux_ptr, str.m_len);
518 *(str.m_ptr + str.m_len) = '\0';
519 while(*p && (*p == sep))
520 p++;
521 return p;
522 }
523
kvi_extractUpTo(KviCString & str,const char * aux_ptr,char sep)524 const char * kvi_extractUpTo(KviCString & str, const char * aux_ptr, char sep)
525 {
526 KVI_ASSERT(aux_ptr);
527 const char * p = aux_ptr;
528 while(*p && (*p != sep))
529 p++;
530 str.m_len = p - aux_ptr;
531 str.m_ptr = (char *)KviMemory::reallocate(str.m_ptr, str.m_len + 1);
532 KviMemory::copy(str.m_ptr, aux_ptr, str.m_len);
533 *(str.m_ptr + str.m_len) = '\0';
534 return p;
535 }
536
kvi_vsnprintf(char * buffer,int len,const char * fmt,kvi_va_list list)537 int kvi_vsnprintf(char * buffer, int len, const char * fmt, kvi_va_list list)
538 {
539 KVI_ASSERT(fmt);
540 KVI_ASSERT(buffer);
541 KVI_ASSERT(len > 0); //printing 0 characters is senseless
542
543 char * p;
544 char * argString;
545 long argValue;
546 unsigned long argUValue;
547
548 //9999999999999999999999999999999\0
549 char numberBuffer[32]; //enough ? 10 is enough for 32bit unsigned int...
550 char * pNumBuf;
551 unsigned int tmp;
552
553 for(p = buffer; *fmt; ++fmt)
554 {
555 if(len < 1)
556 return (-1); //not enough space ... (in fact this could be len < 2 for the terminator)
557 //copy up to a '%'
558 if(*fmt != '%')
559 {
560 *p++ = *fmt;
561 --len;
562 continue;
563 }
564
565 ++fmt; //skip this '%'
566 switch(*fmt)
567 {
568 case 's': //string
569 argString = kvi_va_arg(list, char *);
570 if(!argString)
571 continue;
572 argValue = (long)strlen(argString);
573 //check for space...
574 if(len <= argValue)
575 return (-1); //not enough space for buffer and terminator
576 while(*argString)
577 *p++ = *argString++;
578 len -= argValue;
579 continue;
580 case 'd': //signed integer
581 argValue = kvi_va_arg(list, int);
582 if(argValue < 0)
583 { //negative integer
584 *p++ = '-';
585 if(--len == 0)
586 return (-1);
587 argValue = -argValue; //need to have it positive
588 // most negative integer exception (avoid completely senseless (non digit) responses)
589 if(argValue < 0)
590 argValue = 0; //we get -0 here
591 }
592 //write the number in a temporary buffer
593 pNumBuf = numberBuffer;
594 do
595 {
596 tmp = argValue / 10;
597 *pNumBuf++ = argValue - (tmp * 10) + '0';
598 } while((argValue = tmp));
599 //copy now....
600 argUValue = pNumBuf - numberBuffer; //length of the number string
601 if(((uint)len) <= argUValue)
602 return (-1); //not enough space for number and terminator
603 do
604 {
605 *p++ = *--pNumBuf;
606 } while(pNumBuf != numberBuffer);
607 len -= argUValue;
608 continue;
609 case 'u': //unsigned integer
610 argUValue = kvi_va_arg(list, unsigned int); //many implementations place int here
611 //write the number in a temporary buffer
612 pNumBuf = numberBuffer;
613 do
614 {
615 tmp = argUValue / 10;
616 *pNumBuf++ = argUValue - (tmp * 10) + '0';
617 } while((argUValue = tmp));
618 //copy now....
619 argValue = pNumBuf - numberBuffer; //length of the number string
620 if(len <= argValue)
621 return (-1); //not enough space for number and terminator
622 do
623 {
624 *p++ = *--pNumBuf;
625 } while(pNumBuf != numberBuffer);
626 len -= argValue;
627 continue;
628 case 'x': // hexadecimal unsigned integer
629 argUValue = kvi_va_arg(list, unsigned int); //many implementations place int here
630 //write the number in a temporary buffer
631 pNumBuf = numberBuffer;
632 do
633 {
634 tmp = argUValue / 16;
635 *pNumBuf++ = hexdigits[argUValue % 16];
636 } while((argUValue = tmp));
637 //copy now....
638 argValue = pNumBuf - numberBuffer; //length of the number string
639 if(len <= argValue)
640 return (-1); //not enough space for number and terminator
641 do
642 {
643 *p++ = *--pNumBuf;
644 } while(pNumBuf != numberBuffer);
645 len -= argValue;
646 continue;
647 case 'c': //char
648 //
649 // I'm not sure about this...
650 // In the linux kernel source the
651 // unsigned char is extracted from an integer type.
652 // We assume that gcc stacks a char argument
653 // as sizeof(int) bytes value.
654 // Is this always true ?
655 //
656 *p++ = (char)kvi_va_arg(list, int);
657 --len;
658 continue;
659 case 'Q': // QString! (this should almost never happen)
660 {
661 QString * s = kvi_va_arg(list, QString *);
662 QByteArray cs = (*s).toUtf8();
663 const char * t = cs.data();
664 if(!t)
665 continue; // nothing to do
666 //check for space...
667 if(len <= (int)cs.length())
668 return (-1); //not enough space for buffer and terminator
669 while(*t)
670 *p++ = *t++;
671 len -= cs.length();
672 continue;
673 }
674 default: //a normal percent
675 *p++ = '%'; //write it
676 if(--len == 0)
677 return (-1); //not enough space for next char or terminator
678 if(*fmt)
679 { //this if is just in case that we have a % at the end of the string.
680 *p++ = *fmt; //and write this char
681 --len;
682 }
683 continue;
684 }
685 }
686 if(len < 1)
687 return (-1); //missing space for terminator
688 *p = '\0';
689 return p - buffer;
690 }
691
692 //
693 // Nearly the same as the above function...
694 //
695
kvi_irc_vsnprintf(char * buffer,const char * fmt,kvi_va_list list,bool * bTruncated)696 int kvi_irc_vsnprintf(char * buffer, const char * fmt, kvi_va_list list, bool * bTruncated)
697 {
698 KVI_ASSERT(fmt);
699 KVI_ASSERT(buffer);
700 if(!(buffer && fmt))
701 return false;
702 char * p;
703 char * argString;
704 long argValue;
705 unsigned long argUValue;
706 char numberBuffer[64]; //enough ? 10 is enough for 32bit unsigned int...
707 char * pNumBuf;
708 unsigned int tmp;
709 *bTruncated = false;
710 int len = 512;
711
712 for(p = buffer; *fmt; ++fmt)
713 {
714 if(len < 3)
715 goto truncate;
716 //copy up to a '%'
717 if(*fmt != '%')
718 {
719 *p++ = *fmt;
720 --len;
721 continue;
722 }
723 ++fmt; //skip this '%'
724 switch(*fmt)
725 {
726 case 's': //string
727 argString = kvi_va_arg(list, char *);
728 if(!argString)
729 continue;
730 //check for space...
731 while(*argString)
732 {
733 *p++ = *argString++;
734 if(--len < 3)
735 goto truncate;
736 }
737 continue;
738 case 'Q': // QString! (this should almost never happen)
739 {
740 QString * s = kvi_va_arg(list, QString *);
741 QByteArray cs = (*s).toUtf8();
742 const char * t = cs.data();
743 if(!t)
744 continue; // nothing to do
745 while(*t)
746 {
747 *p++ = *t++;
748 if(--len < 3)
749 goto truncate;
750 }
751 continue;
752 }
753 case 'd': //signed integer
754 argValue = kvi_va_arg(list, int);
755 if(argValue < 0)
756 { //negative integer
757 *p++ = '-';
758 if(--len < 3)
759 goto truncate; //place just for CRLF
760 argValue = -argValue; //need to have it positive
761 if(argValue < 0)
762 argValue = 0; // -0 (hack the exception)
763 }
764 //write the number in a temporary buffer
765 pNumBuf = numberBuffer;
766 do
767 {
768 tmp = argValue / 10;
769 *pNumBuf++ = argValue - (tmp * 10) + '0';
770 } while((argValue = tmp));
771 //copy now....
772 do
773 {
774 *p++ = *--pNumBuf;
775 if(--len < 3)
776 goto truncate;
777 } while(pNumBuf != numberBuffer);
778 continue;
779 case 'u': //unsigned integer
780 argUValue = kvi_va_arg(list, unsigned int); //many implementations place int here
781 //write the number in a temporary buffer
782 pNumBuf = numberBuffer;
783 do
784 {
785 tmp = argUValue / 10;
786 *pNumBuf++ = argUValue - (tmp * 10) + '0';
787 } while((argUValue = tmp));
788 //copy now....
789 if(--len < 3)
790 goto truncate; //no place for digits
791 do
792 {
793 *p++ = *--pNumBuf;
794 if(--len < 3)
795 goto truncate;
796 } while(pNumBuf != numberBuffer);
797 continue;
798 case 'c': //char
799 *p++ = (char)kvi_va_arg(list, int);
800 --len;
801 continue;
802 default: //a normal percent
803 *p++ = '%'; //write it
804 if(--len < 3)
805 goto truncate; //not enough space for next char
806 if(*fmt)
807 { //this if is just in case that we have a % at the end of the string.
808 *p++ = *fmt; //and write this char
809 --len;
810 }
811 continue;
812 }
813 }
814 //successful finish
815 KVI_ASSERT(len >= 2);
816 *p++ = '\r';
817 *p = '\n';
818 return ((p - buffer) + 1);
819 truncate:
820 KVI_ASSERT(len >= 2);
821 *bTruncated = true;
822 *p++ = '\r';
823 *p = '\n';
824 return ((p - buffer) + 1);
825 }
826
827 #ifndef COMPILE_ix86_ASM
828
kvi_strEqualCS(const char * str1,const char * str2)829 bool kvi_strEqualCS(const char * str1, const char * str2)
830 {
831 KVI_ASSERT(str1);
832 KVI_ASSERT(str2);
833 if(!(str1 && str2))
834 return false;
835 unsigned char * s1 = (unsigned char *)str1;
836 unsigned char * s2 = (unsigned char *)str2;
837 while(*s1)
838 if(*s1++ != *s2++)
839 return false;
840 return (*s1 == *s2);
841 }
842
kvi_strEqualCSN(const char * str1,const char * str2,int len)843 bool kvi_strEqualCSN(const char * str1, const char * str2, int len)
844 {
845 KVI_ASSERT(str1);
846 KVI_ASSERT(str2);
847 KVI_ASSERT(len >= 0);
848 if(!(str1 && str2 && (len >= 0)))
849 return false;
850 unsigned char * s1 = (unsigned char *)str1;
851 unsigned char * s2 = (unsigned char *)str2;
852 while(len-- && *s1)
853 if(*s1++ != *s2++)
854 return false;
855 return (len < 0);
856 }
857
858 #endif
859
kvi_strEqualCIN(const char * str1,const char * str2,int len)860 bool kvi_strEqualCIN(const char * str1, const char * str2, int len)
861 {
862 KVI_ASSERT(str1);
863 KVI_ASSERT(str2);
864 KVI_ASSERT(len >= 0);
865 if(!(str1 && str2 && (len >= 0)))
866 return false;
867 unsigned char * s1 = (unsigned char *)str1;
868 unsigned char * s2 = (unsigned char *)str2;
869 while(len-- && *s1)
870 if(tolower(*s1++) != tolower(*s2++))
871 return false;
872 return (len < 0);
873 }
874
kvi_strEqualCI(const char * str1,const char * str2)875 bool kvi_strEqualCI(const char * str1, const char * str2)
876 {
877 KVI_ASSERT(str1);
878 KVI_ASSERT(str2);
879 if(!(str1 && str2))
880 return false;
881 unsigned char * s1 = (unsigned char *)str1;
882 unsigned char * s2 = (unsigned char *)str2;
883 while(*s1)
884 if(tolower(*s1++) != tolower(*s2++))
885 return false;
886 return (*s1 == *s2);
887 }
888
889 //
890 //note that greater here means that come AFTER in the alphabetic order
891 // return < 0 ---> str1 < str2
892 // return = 0 ---> str1 = str2
893 // return > 0 ---> str1 > str2
894 //
895
kvi_strcmpCI(const char * str1,const char * str2)896 int kvi_strcmpCI(const char * str1, const char * str2)
897 {
898 //abcd abce
899 KVI_ASSERT(str1);
900 KVI_ASSERT(str2);
901 if(!(str1 && str2))
902 return false;
903 unsigned char * s1 = (unsigned char *)str1;
904 unsigned char * s2 = (unsigned char *)str2;
905 int diff;
906 unsigned char rightchar;
907 while(!(diff = (rightchar = tolower(*s1++)) - tolower(*s2++)))
908 if(!rightchar)
909 break;
910 return diff; //diff is nonzero or end of both was reached (it is positive if *s2 > *s1
911 }
912
913 //
914 //note that greater here means that come AFTER in the alphabetic order
915 // return < 0 ---> str1 < str2
916 // return = 0 ---> str1 = str2
917 // return > 0 ---> str1 > str2
918 //int kvi_strcmpCIN(const char *str1,const char *str2,int len)
919 //
920
kvi_strcmpCS(const char * str1,const char * str2)921 int kvi_strcmpCS(const char * str1, const char * str2)
922 {
923 //abcd abce
924 KVI_ASSERT(str1);
925 KVI_ASSERT(str2);
926 if(!(str1 && str2))
927 return false;
928 unsigned char * s1 = (unsigned char *)str1;
929 unsigned char * s2 = (unsigned char *)str2;
930 int diff;
931 while(!(diff = (*s1) - (*s2++)))
932 if(!*s1++)
933 break;
934 return diff; //diff is nonzero or end of both was reached (it is positive if *s2 > *s1
935 }
936
kvi_strMatchRevCS(const char * str1,const char * str2,int index)937 int kvi_strMatchRevCS(const char * str1, const char * str2, int index)
938 {
939 KVI_ASSERT(str1);
940 KVI_ASSERT(str2);
941 if(!(str1 && str2))
942 return false;
943 char * s1 = (char *)str1;
944 char * s2 = (char *)str2;
945
946 int curlen = (int)strlen(str1);
947 int diff;
948
949 if(index < 0 || index >= curlen)
950 index = curlen - 1;
951
952 s1 += index;
953 while(*s2)
954 s2++;
955 s2--;
956
957 // now start comparing
958 while(true)
959 {
960 /* in this case, we have str1 = "lo" and str2 = "hello" */
961 if(s1 < str1 && !(s2 < str2))
962 return 256;
963 if(s2 < str2)
964 return 0;
965 if((diff = (*s1) - (*s2)))
966 return diff;
967 s1--;
968 s2--;
969 }
970 }
971
KviCString()972 KviCString::KviCString()
973 {
974 m_ptr = (char *)KviMemory::allocate(1);
975 *m_ptr = '\0';
976 m_len = 0;
977 }
978
KviCString(const char * str)979 KviCString::KviCString(const char * str)
980 {
981 //Deep copy constructor
982 if(str)
983 {
984 //Deep copy
985 m_len = (int)strlen(str);
986 m_ptr = (char *)KviMemory::allocate(m_len + 1);
987 KviMemory::copy(m_ptr, str, m_len + 1);
988 }
989 else
990 {
991 m_ptr = (char *)KviMemory::allocate(1);
992 *m_ptr = '\0';
993 m_len = 0;
994 }
995 }
996
KviCString(const QByteArray & str)997 KviCString::KviCString(const QByteArray & str)
998 {
999 //Deep copy constructor
1000 if(str.data())
1001 {
1002 //Deep copy
1003 m_len = str.length();
1004 m_ptr = (char *)KviMemory::allocate(m_len + 1);
1005 KviMemory::copy(m_ptr, str, m_len + 1);
1006 }
1007 else
1008 {
1009 m_ptr = (char *)KviMemory::allocate(1);
1010 *m_ptr = '\0';
1011 m_len = 0;
1012 }
1013 }
1014
KviCString(const char * str,int len)1015 KviCString::KviCString(const char * str, int len)
1016 {
1017 KVI_ASSERT(str);
1018 //KVI_ASSERT(len <= ((int)strlen(str))); <-- we trust the user here (and a strlen() call may run AFTER len if data is not null terminated)
1019 KVI_ASSERT(len >= 0);
1020 m_len = len;
1021 m_ptr = (char *)KviMemory::allocate(m_len + 1);
1022 KviMemory::copy(m_ptr, str, m_len);
1023 *(m_ptr + m_len) = '\0';
1024 }
1025
KviCString(const char * bg,const char * end)1026 KviCString::KviCString(const char * bg, const char * end)
1027 {
1028 KVI_ASSERT(bg);
1029 KVI_ASSERT(end);
1030 KVI_ASSERT(bg <= end);
1031 m_len = end - bg;
1032 m_ptr = (char *)KviMemory::allocate(m_len + 1);
1033 KviMemory::copy(m_ptr, bg, m_len);
1034 *(m_ptr + m_len) = '\0';
1035 }
1036
KviCString(KviFormatConstructorTag,const char * fmt,...)1037 KviCString::KviCString(KviFormatConstructorTag, const char * fmt, ...)
1038 {
1039 m_ptr = (char *)KviMemory::allocate(256);
1040 //First try
1041 kvi_va_list list;
1042 kvi_va_start(list, fmt);
1043 //print...with max 256 chars
1044 m_len = kvi_vsnprintf(m_ptr, 256, fmt, list);
1045 kvi_va_end(list);
1046
1047 //check if we failed
1048 if(m_len < 0)
1049 {
1050 //yes, failed....
1051 int dummy = 256;
1052 do
1053 { //we failed, so retry with 256 more chars
1054 dummy += 256;
1055 //realloc
1056 m_ptr = (char *)KviMemory::reallocate(m_ptr, dummy);
1057 //print...
1058 kvi_va_start(list, fmt);
1059 m_len = kvi_vsnprintf(m_ptr, dummy, fmt, list);
1060 kvi_va_end(list);
1061 } while(m_len < 0);
1062 }
1063 //done...
1064 //now m_len is the length of the written string not including the terminator...
1065 //perfect! :)
1066 m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
1067 }
1068
KviCString(const KviCString & str)1069 KviCString::KviCString(const KviCString & str)
1070 {
1071 KVI_ASSERT(str.m_ptr);
1072 m_len = str.m_len;
1073 m_ptr = (char *)KviMemory::allocate(m_len + 1);
1074 KviMemory::copy(m_ptr, str.m_ptr, m_len + 1);
1075 }
1076
KviCString(const QString & str)1077 KviCString::KviCString(const QString & str)
1078 {
1079 QByteArray sz = str.toUtf8();
1080 if(sz.length() > 0)
1081 {
1082 m_len = sz.length();
1083 m_ptr = (char *)KviMemory::allocate(m_len + 1);
1084 KviMemory::copy(m_ptr, sz.data(), m_len + 1);
1085 }
1086 else
1087 {
1088 m_ptr = (char *)KviMemory::allocate(1);
1089 *m_ptr = '\0';
1090 m_len = 0;
1091 }
1092 }
1093
KviCString(char c,int fillLen)1094 KviCString::KviCString(char c, int fillLen)
1095 {
1096 KVI_ASSERT(fillLen >= 0);
1097 m_len = fillLen;
1098 m_ptr = (char *)KviMemory::allocate(m_len + 1);
1099 char * p = m_ptr;
1100 while(fillLen--)
1101 *p++ = c;
1102 *p = '\0';
1103 }
1104
KviCString(const kvi_wchar_t * unicode)1105 KviCString::KviCString(const kvi_wchar_t * unicode)
1106 {
1107 if(!unicode)
1108 {
1109 m_len = 0;
1110 m_ptr = (char *)KviMemory::allocate(1);
1111 *m_ptr = 0;
1112 }
1113 else
1114 {
1115 m_len = kvi_wstrlen(unicode);
1116 m_ptr = (char *)KviMemory::allocate(m_len + 1);
1117 char * p = m_ptr;
1118 while(*unicode)
1119 *p++ = *unicode++;
1120 *p = 0;
1121 }
1122 }
1123
KviCString(const kvi_wchar_t * unicode,int len)1124 KviCString::KviCString(const kvi_wchar_t * unicode, int len)
1125 {
1126 m_len = len;
1127 m_ptr = (char *)KviMemory::allocate(m_len + 1);
1128 char * p = m_ptr;
1129 char * end = p + len;
1130 while(p != end)
1131 {
1132 *p++ = *unicode++;
1133 }
1134 *p = 0;
1135 }
1136
~KviCString()1137 KviCString::~KviCString()
1138 {
1139 KviMemory::free(m_ptr);
1140 }
1141
operator =(const KviCString & str)1142 KviCString & KviCString::operator=(const KviCString & str)
1143 {
1144 KVI_ASSERT(str.m_ptr);
1145 KVI_ASSERT(str.m_ptr != m_ptr);
1146 m_len = str.m_len;
1147 m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
1148 KviMemory::copy(m_ptr, str.m_ptr, m_len + 1);
1149 return (*this);
1150 }
1151
operator =(const QByteArray & str)1152 KviCString & KviCString::operator=(const QByteArray & str)
1153 {
1154 m_len = str.length();
1155 m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
1156 if(str.data())
1157 KviMemory::copy(m_ptr, str.data(), m_len + 1);
1158 else
1159 *m_ptr = 0;
1160 return (*this);
1161 }
1162
operator =(const char * str)1163 KviCString & KviCString::operator=(const char * str)
1164 {
1165 //KVI_ASSERT(str);
1166 if(str)
1167 {
1168 m_len = (int)strlen(str);
1169 m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
1170 KviMemory::move(m_ptr, str, m_len + 1);
1171 }
1172 else
1173 {
1174 m_ptr = (char *)KviMemory::reallocate(m_ptr, 1);
1175 *m_ptr = '\0';
1176 m_len = 0;
1177 }
1178 return (*this);
1179 }
1180
clear()1181 void KviCString::clear()
1182 {
1183 m_ptr = (char *)KviMemory::reallocate(m_ptr, 1);
1184 *m_ptr = '\0';
1185 m_len = 0;
1186 }
1187
hasNonWhiteSpaceData() const1188 bool KviCString::hasNonWhiteSpaceData() const
1189 {
1190 const char * aux = m_ptr;
1191 while(*aux)
1192 {
1193 if(((*aux) != ' ') && ((*aux) != '\t'))
1194 return true;
1195 aux++;
1196 }
1197 return false;
1198 }
1199
bufferToHex(const char * buffer,int len)1200 void KviCString::bufferToHex(const char * buffer, int len)
1201 {
1202 KVI_ASSERT(buffer);
1203 m_len = (len * 2);
1204 m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
1205 char * aux = m_ptr;
1206 while(len)
1207 {
1208 *aux = hexdigits[(unsigned int)(((unsigned char)(*buffer)) / 16)];
1209 aux++;
1210 *aux = hexdigits[(unsigned int)(((unsigned char)(*buffer)) % 16)];
1211 aux++;
1212 len--;
1213 buffer++;
1214 }
1215 *(m_ptr + m_len) = '\0';
1216 }
1217
get_decimal_from_hex_digit_char(char dgt)1218 static char get_decimal_from_hex_digit_char(char dgt)
1219 {
1220 if((dgt >= '0') && (dgt <= '9'))
1221 return (dgt - '0');
1222 if((dgt >= 'A') && (dgt <= 'F'))
1223 return (10 + (dgt - 'A'));
1224 if((dgt >= 'a') && (dgt <= 'f'))
1225 return (10 + (dgt - 'a'));
1226 return -1;
1227 }
1228
hexToBuffer(char ** buffer,bool bNullToNewlines)1229 int KviCString::hexToBuffer(char ** buffer, bool bNullToNewlines)
1230 {
1231 *buffer = nullptr;
1232 if((m_len == 0) || (m_len & 1))
1233 return -1; // this is an error
1234 int len = (m_len / 2);
1235 if(len < 1)
1236 return -1;
1237 *buffer = (char *)KviMemory::allocate(len);
1238
1239 char * ptr = *buffer;
1240 char * aux = m_ptr;
1241
1242 while(*aux)
1243 {
1244 char temp = get_decimal_from_hex_digit_char(*aux);
1245 if(temp == -1)
1246 {
1247 KviMemory::free(*buffer);
1248 *buffer = nullptr;
1249 return -1;
1250 }
1251 *ptr = temp * 16;
1252 aux++;
1253 temp = get_decimal_from_hex_digit_char(*aux);
1254 if(temp == -1)
1255 {
1256 KviMemory::free(*buffer);
1257 *buffer = nullptr;
1258 return -1;
1259 }
1260 *ptr += temp;
1261 aux++;
1262 if(bNullToNewlines)
1263 if(!(*ptr))
1264 *ptr = '\n';
1265 ptr++;
1266 }
1267 return len;
1268 }
1269
1270 static const char * base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
1271
bufferToBase64(const char * buffer,int len)1272 void KviCString::bufferToBase64(const char * buffer, int len)
1273 {
1274 m_len = (len / 3) << 2;
1275 if(len % 3)
1276 m_len += 4;
1277
1278 m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
1279
1280 unsigned char aux1, aux2, aux3;
1281 char * aux_ptr = m_ptr;
1282 while(len > 2)
1283 {
1284 aux1 = (unsigned char)*buffer++;
1285 aux2 = (unsigned char)*buffer++;
1286 aux3 = (unsigned char)*buffer++;
1287 *aux_ptr++ = base64_chars[(aux1 & 0xFC) >> 2];
1288 *aux_ptr++ = base64_chars[((aux1 & 0x03) << 4) | ((aux2 & 0xF0) >> 4)];
1289 *aux_ptr++ = base64_chars[((aux2 & 0x0F) << 2) | ((aux3 & 0xC0) >> 6)];
1290 *aux_ptr++ = base64_chars[(aux3 & 0x3F)];
1291 len -= 3;
1292 }
1293 switch(len)
1294 {
1295 case 2:
1296 aux1 = (unsigned char)*buffer++;
1297 aux2 = (unsigned char)*buffer++;
1298 *aux_ptr++ = base64_chars[(aux1 & 0xFC) >> 2];
1299 *aux_ptr++ = base64_chars[((aux1 & 0x03) << 4) | ((aux2 & 0xF0) >> 4)];
1300 *aux_ptr++ = base64_chars[((aux2 & 0x0F) << 2)];
1301 *aux_ptr++ = '=';
1302 break;
1303 case 1:
1304 aux1 = (unsigned char)*buffer++;
1305 aux2 = (unsigned char)*buffer++;
1306 *aux_ptr++ = base64_chars[(aux1 & 0xFC) >> 2];
1307 *aux_ptr++ = base64_chars[((aux1 & 0x03) << 4)];
1308 *aux_ptr++ = '=';
1309 *aux_ptr++ = '=';
1310 break;
1311 }
1312 *aux_ptr = 0;
1313 }
1314
get_base64_idx(char base64)1315 static unsigned char get_base64_idx(char base64)
1316 {
1317 if((base64 >= 'A') && (base64 <= 'Z'))
1318 return (base64 - 'A');
1319 if((base64 >= 'a') && (base64 <= 'z'))
1320 return ((base64 - 'a') + 26);
1321 if((base64 >= '0') && (base64 <= '9'))
1322 return ((base64 - '0') + 52);
1323 if(base64 == '+')
1324 return 62;
1325 if(base64 == '/')
1326 return 63;
1327 if(base64 == '=')
1328 return 64;
1329 return 65;
1330 }
1331
base64ToBuffer(char ** buffer,bool)1332 int KviCString::base64ToBuffer(char ** buffer, bool)
1333 {
1334 *buffer = nullptr;
1335 if((m_len == 0) || (m_len & 3))
1336 return -1; // this is an error
1337 int len = (m_len >> 2) * 3;
1338 *buffer = (char *)KviMemory::allocate(len);
1339
1340 char * auxBuf = *buffer;
1341
1342 unsigned char aux1, aux2, aux3, aux4;
1343 char * aux_ptr = m_ptr;
1344
1345 int newLen = len;
1346
1347 while(*aux_ptr)
1348 {
1349 if(newLen != len)
1350 {
1351 // ops... there was a padding and we still have chars after it
1352 // this is an error
1353 KviMemory::free(*buffer);
1354 *buffer = nullptr;
1355 return -1;
1356 }
1357 aux1 = get_base64_idx(*aux_ptr++);
1358 aux2 = get_base64_idx(*aux_ptr++);
1359 aux3 = get_base64_idx(*aux_ptr++);
1360 aux4 = get_base64_idx(*aux_ptr++);
1361 if((aux3 > 64) || (aux4 > 64))
1362 {
1363 // error
1364 KviMemory::free(*buffer);
1365 *buffer = nullptr;
1366 return -1;
1367 }
1368 if((aux1 | aux2) > 63)
1369 {
1370 // again error...impossible padding
1371 KviMemory::free(*buffer);
1372 *buffer = nullptr;
1373 return -1;
1374 }
1375 if(aux4 == 64)
1376 {
1377 if(aux3 == 64)
1378 {
1379 // Double padding, only one digit here
1380 *auxBuf++ = (char)((aux1 << 2) | (aux2 >> 4));
1381 newLen -= 2;
1382 }
1383 else
1384 {
1385 // Single padding, two digits here
1386 *auxBuf++ = (char)((aux1 << 2) | (aux2 >> 4)); // >> 4 is a shr, not a ror! :)
1387 *auxBuf++ = (char)((aux2 << 4) | (aux3 >> 2));
1388 newLen -= 1;
1389 }
1390 }
1391 else
1392 {
1393 if(aux3 == 64)
1394 {
1395 // error... impossible padding
1396 KviMemory::free(*buffer);
1397 *buffer = nullptr;
1398 return -1;
1399 }
1400 else
1401 {
1402 // Ok, no padding, three digits here
1403 *auxBuf++ = (char)((aux1 << 2) | (aux2 >> 4));
1404 *auxBuf++ = (char)((aux2 << 4) | (aux3 >> 2));
1405 *auxBuf++ = (char)((aux3 << 6) | aux4);
1406 }
1407 }
1408 }
1409
1410 if(newLen != len)
1411 *buffer = (char *)KviMemory::reallocate(*buffer, newLen);
1412 return newLen;
1413 }
1414
setStr(const char * str,int len)1415 KviCString & KviCString::setStr(const char * str, int len)
1416 {
1417 if(!str)
1418 {
1419 clear();
1420 return *this;
1421 }
1422 int alen = (int)strlen(str);
1423 if((len < 0) || (len > alen))
1424 m_len = alen;
1425 else
1426 m_len = len;
1427 m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
1428 KviMemory::move(m_ptr, str, m_len);
1429 *(m_ptr + m_len) = '\0';
1430 return (*this);
1431 }
1432
operator =(const QString & str)1433 KviCString & KviCString::operator=(const QString & str)
1434 {
1435 QByteArray sz = str.toUtf8();
1436 if(sz.length() > 0)
1437 {
1438 m_len = sz.length();
1439 m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
1440 KviMemory::copy(m_ptr, sz.data(), m_len + 1);
1441 }
1442 else
1443 {
1444 m_ptr = (char *)KviMemory::reallocate(m_ptr, 1);
1445 *m_ptr = '\0';
1446 m_len = 0;
1447 }
1448 return (*this);
1449 }
1450
operator =(char c)1451 KviCString & KviCString::operator=(char c)
1452 {
1453 m_len = 1;
1454 m_ptr = (char *)KviMemory::reallocate(m_ptr, 2);
1455 *m_ptr = c;
1456 *(m_ptr + 1) = '\0';
1457 return (*this);
1458 }
1459
append(char c)1460 void KviCString::append(char c)
1461 {
1462 m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 2);
1463 *(m_ptr + m_len) = c;
1464 m_len++;
1465 *(m_ptr + m_len) = '\0';
1466 }
1467
append(const KviCString & str)1468 void KviCString::append(const KviCString & str)
1469 {
1470 KVI_ASSERT(str.m_ptr);
1471 m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + str.m_len + 1);
1472 KviMemory::copy((m_ptr + m_len), str.m_ptr, str.m_len + 1);
1473 m_len += str.m_len;
1474 }
1475
append(const char * str)1476 void KviCString::append(const char * str)
1477 {
1478 if(!str)
1479 return;
1480 int len = (int)strlen(str);
1481 m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + len + 1);
1482 KviMemory::copy((m_ptr + m_len), str, len + 1);
1483 m_len += len;
1484 }
1485
append(const QString & str)1486 void KviCString::append(const QString & str)
1487 {
1488 QByteArray sz = str.toUtf8();
1489 if(sz.length() < 1)
1490 return;
1491 m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + sz.length() + 1);
1492 KviMemory::copy((m_ptr + m_len), sz.data(), sz.length() + 1);
1493 m_len += sz.length();
1494 }
1495
append(const char * str,int len)1496 void KviCString::append(const char * str, int len)
1497 {
1498 KVI_ASSERT(str);
1499 // KVI_ASSERT(len <= ((int)strlen(str)));
1500 KVI_ASSERT(len >= 0);
1501 m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + len + 1);
1502 KviMemory::copy((m_ptr + m_len), str, len);
1503 m_len += len;
1504 *(m_ptr + m_len) = '\0';
1505 }
1506
append(KviFormatConstructorTag,const char * fmt,...)1507 void KviCString::append(KviFormatConstructorTag, const char * fmt, ...)
1508 {
1509 int auxLen;
1510 m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 256);
1511 //First try
1512 kvi_va_list list;
1513 kvi_va_start(list, fmt);
1514 //print...with max 256 chars
1515 auxLen = kvi_vsnprintf(m_ptr + m_len, 256, fmt, list);
1516 kvi_va_end(list);
1517
1518 //check if we failed
1519 if(auxLen < 0)
1520 {
1521 //yes, failed....
1522 int dummy = 256;
1523 do
1524 { //we failed, so retry with 256 more chars
1525 dummy += 256;
1526 //realloc
1527 m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + dummy);
1528 //print...
1529 kvi_va_start(list, fmt);
1530 auxLen = kvi_vsnprintf(m_ptr + m_len, dummy, fmt, list);
1531 kvi_va_end(list);
1532 } while(auxLen < 0);
1533 }
1534 m_len += auxLen;
1535 //done...
1536 //now m_len is the length of the written string not including the terminator...
1537 //perfect! :)
1538 m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
1539 }
1540
extractFromString(const char * begin,const char * end)1541 void KviCString::extractFromString(const char * begin, const char * end)
1542 {
1543 KVI_ASSERT(begin);
1544 KVI_ASSERT(end);
1545 KVI_ASSERT(end >= begin);
1546 m_len = end - begin;
1547 m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
1548 KviMemory::copy(m_ptr, begin, m_len);
1549 *(m_ptr + m_len) = '\0';
1550 }
1551
prepend(const KviCString & str)1552 void KviCString::prepend(const KviCString & str)
1553 {
1554 KVI_ASSERT(str.m_ptr);
1555 KVI_ASSERT(str.m_ptr != m_ptr);
1556 m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + str.m_len + 1);
1557 KviMemory::move((m_ptr + str.m_len), m_ptr, m_len + 1); //move self
1558 KviMemory::copy(m_ptr, str.m_ptr, str.m_len);
1559 m_len += str.m_len;
1560 }
1561
prepend(const char * str)1562 void KviCString::prepend(const char * str)
1563 {
1564 if(!str)
1565 return;
1566 int len = (int)strlen(str);
1567 m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + len + 1);
1568 KviMemory::move((m_ptr + len), m_ptr, m_len + 1); //move self
1569 KviMemory::copy(m_ptr, str, len);
1570 m_len += len;
1571 }
1572
prepend(const char * str,int len)1573 void KviCString::prepend(const char * str, int len)
1574 {
1575 KVI_ASSERT(str);
1576 KVI_ASSERT(len <= ((int)strlen(str)));
1577 KVI_ASSERT(len >= 0);
1578 m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + len + 1);
1579 KviMemory::move((m_ptr + len), m_ptr, m_len + 1); //move self
1580 KviMemory::copy(m_ptr, str, len);
1581 m_len += len;
1582 }
1583
1584 unsigned char iso88591_toUpper_map[256] = {
1585 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1586 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
1587 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
1588 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
1589 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
1590 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
1591 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
1592 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
1593 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
1594 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
1595 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
1596 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
1597 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
1598 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
1599 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
1600 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
1601 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
1602 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
1603 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
1604 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
1605 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
1606 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
1607 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
1608 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
1609 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
1610 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
1611 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
1612 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
1613 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
1614 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
1615 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
1616 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
1617 };
1618
toUpperISO88591()1619 void KviCString::toUpperISO88591()
1620 {
1621 char * p = m_ptr;
1622 while(*p)
1623 {
1624 *p = (char)iso88591_toUpper_map[(unsigned char)*p];
1625 p++;
1626 }
1627 }
1628
toUpper()1629 void KviCString::toUpper()
1630 {
1631 char * p = m_ptr;
1632 while(*p)
1633 {
1634 *p = toupper(*p);
1635 p++;
1636 }
1637 }
1638
1639 unsigned char iso88591_toLower_map[256] = {
1640 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1641 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
1642 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
1643 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
1644 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
1645 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
1646 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
1647 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
1648 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
1649 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
1650 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
1651 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
1652 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
1653 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
1654 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
1655 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
1656 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
1657 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
1658 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
1659 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
1660 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
1661 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
1662 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
1663 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
1664 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
1665 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
1666 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
1667 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
1668 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
1669 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
1670 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
1671 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
1672 };
1673
toLowerISO88591()1674 void KviCString::toLowerISO88591()
1675 {
1676 char * p = m_ptr;
1677 while(*p)
1678 {
1679 *p = (char)iso88591_toLower_map[(unsigned char)*p];
1680 p++;
1681 }
1682 }
1683
toLower()1684 void KviCString::toLower()
1685 {
1686 char * p = m_ptr;
1687 while(*p)
1688 {
1689 *p = tolower(*p);
1690 p++;
1691 }
1692 }
1693
upper() const1694 KviCString KviCString::upper() const
1695 {
1696 KviCString tmp(*this);
1697 tmp.toUpper();
1698 return tmp;
1699 }
1700
upperISO88591() const1701 KviCString KviCString::upperISO88591() const
1702 {
1703 KviCString tmp(*this);
1704 tmp.toUpperISO88591();
1705 return tmp;
1706 }
1707
lower() const1708 KviCString KviCString::lower() const
1709 {
1710 KviCString tmp(*this);
1711 tmp.toLower();
1712 return tmp;
1713 }
1714
lowerISO88591() const1715 KviCString KviCString::lowerISO88591() const
1716 {
1717 KviCString tmp(*this);
1718 tmp.toLowerISO88591();
1719 return tmp;
1720 }
1721
left(int maxLen) const1722 KviCString KviCString::left(int maxLen) const
1723 {
1724 if(maxLen <= 0)
1725 {
1726 KviCString empty;
1727 return empty;
1728 }
1729 if(maxLen > m_len)
1730 maxLen = m_len;
1731 KviCString str(m_ptr, maxLen);
1732 return str;
1733 }
1734
right(int maxLen) const1735 KviCString KviCString::right(int maxLen) const
1736 {
1737 if(maxLen <= 0)
1738 {
1739 KviCString empty;
1740 return empty;
1741 }
1742 if(maxLen > m_len)
1743 maxLen = m_len;
1744 KviCString str((m_ptr + (m_len - maxLen)), maxLen);
1745 return str;
1746 }
1747
middle(int idx,int maxLen) const1748 KviCString KviCString::middle(int idx, int maxLen) const
1749 {
1750 KVI_ASSERT(maxLen >= 0);
1751 KVI_ASSERT(idx >= 0);
1752 if((maxLen <= 0) || (idx < 0))
1753 { //max len negative...invalid params
1754 KviCString ret;
1755 return ret;
1756 }
1757 if((maxLen + idx) <= m_len)
1758 { //valid params
1759 KviCString str(m_ptr + idx, maxLen);
1760 return str;
1761 }
1762 if(idx < m_len)
1763 { //string shorter than requested
1764 KviCString str(m_ptr + idx);
1765 return str;
1766 }
1767 // idx out of bounds
1768 KviCString ret;
1769 return ret;
1770 }
1771
splitToArray(char sep,int max,int * realCount) const1772 KviCString ** KviCString::splitToArray(char sep, int max, int * realCount) const
1773 {
1774 KviCString ** strings = (KviCString **)KviMemory::allocate(sizeof(KviCString *));
1775 int number = 0;
1776 char * ptr = m_ptr;
1777 char * last = ptr;
1778 while((max > 0) && *ptr)
1779 {
1780 strings = (KviCString **)KviMemory::reallocate((void *)strings, sizeof(KviCString *) * (number + 2));
1781 if(max > 1)
1782 {
1783 while(*ptr && (*ptr != sep))
1784 ptr++;
1785 strings[number] = new KviCString(last, ptr - last);
1786 }
1787 else
1788 {
1789 strings[number] = new KviCString(ptr);
1790 }
1791 number++;
1792 max--;
1793 if(*ptr)
1794 {
1795 ptr++;
1796 last = ptr;
1797 }
1798 }
1799 if(realCount)
1800 *realCount = number;
1801 strings[number] = nullptr;
1802 return strings;
1803 }
1804
freeArray(KviCString ** strings)1805 void KviCString::freeArray(KviCString ** strings)
1806 {
1807 if(!strings)
1808 return;
1809 KviCString ** aux = strings;
1810 while(*aux)
1811 {
1812 delete(*aux); // delete (KviCString *)
1813 aux++;
1814 }
1815 KviMemory::free(strings);
1816 }
1817
freeBuffer(char * buffer)1818 void KviCString::freeBuffer(char * buffer)
1819 {
1820 if(!buffer)
1821 return;
1822 KviMemory::free(buffer);
1823 }
1824
joinFromArray(KviCString ** strings,const char * sep,bool bLastSep)1825 void KviCString::joinFromArray(KviCString ** strings, const char * sep, bool bLastSep)
1826 {
1827 setLen(0);
1828 if(!strings)
1829 return;
1830
1831 while(*strings)
1832 {
1833 append(*(*strings));
1834 strings++;
1835 if(*strings)
1836 {
1837 if(sep)
1838 append(sep);
1839 }
1840 else
1841 {
1842 if(sep && bLastSep)
1843 append(sep);
1844 }
1845 }
1846 }
1847
insert(int idx,const char * data)1848 KviCString & KviCString::insert(int idx, const char * data)
1849 {
1850 KVI_ASSERT(data);
1851 if(idx <= m_len)
1852 {
1853 int len = (int)strlen(data);
1854 m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + len + 1);
1855 KviMemory::move(m_ptr + idx + len, m_ptr + idx, (m_len - idx) + 1);
1856 KviMemory::copy(m_ptr + idx, data, len);
1857 m_len += len;
1858 }
1859 return (*this);
1860 }
1861
insert(int idx,char c)1862 KviCString & KviCString::insert(int idx, char c)
1863 {
1864 if(idx <= m_len)
1865 {
1866 m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 2);
1867 KviMemory::move(m_ptr + idx + 1, m_ptr + idx, (m_len - idx) + 1);
1868 m_len++;
1869 *(m_ptr + idx) = c;
1870 }
1871 return (*this);
1872 }
1873
1874 // FIXME: #warning "Double check the following two functions !!!"
1875
hexEncodeWithTable(const unsigned char table[256])1876 KviCString & KviCString::hexEncodeWithTable(const unsigned char table[256])
1877 {
1878 char * aux = m_ptr;
1879 char * begin = m_ptr;
1880
1881 char * n = nullptr;
1882 int curSize = 0;
1883
1884 while(*aux)
1885 {
1886 if(table[*((unsigned char *)aux)] || (*aux == '%'))
1887 {
1888 int len = aux - begin;
1889 n = (char *)KviMemory::reallocate(n, curSize + len + 3);
1890 KviMemory::move(n + curSize, begin, len);
1891 curSize += len;
1892
1893 n[curSize] = '%';
1894 curSize++;
1895 n[curSize] = hexdigits[(unsigned int)(((unsigned char)(*aux)) / 16)];
1896 curSize++;
1897 n[curSize] = hexdigits[(unsigned int)(((unsigned char)(*aux)) % 16)];
1898 curSize++;
1899
1900 aux++;
1901 begin = aux;
1902 }
1903 else
1904 aux++;
1905 }
1906
1907 int len = aux - begin;
1908 n = (char *)KviMemory::reallocate(n, curSize + len + 1);
1909 KviMemory::move(n + curSize, begin, len);
1910 curSize += len;
1911
1912 n[curSize] = '\0';
1913
1914 KviMemory::free((void *)m_ptr);
1915 m_ptr = n;
1916 m_len = curSize;
1917
1918 return (*this);
1919 }
1920
hexEncodeWhiteSpace()1921 KviCString & KviCString::hexEncodeWhiteSpace()
1922 {
1923 static unsigned char ascii_jump_table[256] = {
1924 // clang-format off
1925 // 000 001 002 003 004 005 006 007 008 009 010 011 012 013 014 015
1926 // NUL SOH STX ETX EOT ENQ ACK BEL BS HT LF VT FF CR SO SI
1927 1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,
1928 // 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031
1929 // DLE DC1 DC2 DC3 DC4 NAK SYN ETB CAN EM SUB ESC FS GS RS US
1930 1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,
1931 // 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047
1932 // ! " # $ % & ' ( ) * + , - . /
1933 1 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,
1934 // 048 049 050 051 052 053 054 055 056 057 058 059 060 061 062 063
1935 // 0 1 2 3 4 5 6 7 8 9 : ; < = > ?
1936 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,
1937 // 064 065 066 067 068 069 070 071 072 073 074 075 076 077 078 079
1938 // @ A B C D E F G H I J K L M N O
1939 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,
1940 // 080 081 082 083 084 085 086 087 088 089 090 091 092 093 094 095
1941 // P Q R S T U V W X Y Z [ \ ] ^ _
1942 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,
1943 // 096 097 098 099 100 101 102 103 104 105 106 107 108 109 110 111
1944 // ` a b c d e f g h i j k l m n o
1945 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,
1946 // 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
1947 // p q r s t u v w x y z { | } ~
1948 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,
1949 // 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
1950 //
1951 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,
1952 // 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
1953 //
1954 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,
1955 // 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
1956 //
1957 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,
1958 // 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
1959 //
1960 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,
1961 // 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
1962 // � � � � � � � � � � � � � � � �
1963 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,
1964 // 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223
1965 // � � � � � � � � � � � � � � � �
1966 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,
1967 // 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239
1968 // � � � � � � � � � � � � � � � �
1969 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,
1970 // 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255
1971 // � � � � � � � �
1972 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0
1973 // clang-format on
1974 };
1975
1976 return hexEncodeWithTable(ascii_jump_table);
1977 }
1978
hexDecode(const char * pFrom)1979 KviCString & KviCString::hexDecode(const char * pFrom)
1980 {
1981 // WARNING: pFrom can be also m_ptr here!
1982 const char * aux = pFrom;
1983 const char * begin = pFrom;
1984
1985 char * n = nullptr;
1986 int curSize = 0;
1987
1988 while(*aux)
1989 {
1990 if(*aux == '%')
1991 {
1992 // move last block
1993 int len = aux - begin;
1994 n = (char *)KviMemory::reallocate(n, curSize + len + 1);
1995 KviMemory::move(n + curSize, begin, len);
1996 curSize += len;
1997
1998 // get the hex code
1999 aux++;
2000
2001 char theChar = get_decimal_from_hex_digit_char(*aux);
2002 if(theChar < 0)
2003 {
2004 n[curSize] = '%'; // wrong code...just a '%'
2005 curSize++;
2006 }
2007 else
2008 {
2009 aux++;
2010 char theChar2 = get_decimal_from_hex_digit_char(*aux);
2011 if(theChar2 < 0)
2012 {
2013 // wrong code...just a '%' and step back
2014 n[curSize] = '%';
2015 curSize++;
2016 aux--;
2017 }
2018 else
2019 {
2020 n[curSize] = (theChar * 16) + theChar2;
2021 curSize++;
2022 aux++;
2023 }
2024 }
2025
2026 begin = aux;
2027 }
2028 else
2029 aux++;
2030 }
2031
2032 int len = aux - begin;
2033 n = (char *)KviMemory::reallocate(n, curSize + len + 2);
2034 KviMemory::move(n + curSize, begin, len);
2035 curSize += len;
2036 n[curSize] = '\0';
2037
2038 KviMemory::free((void *)m_ptr);
2039 m_ptr = n;
2040 m_len = curSize;
2041
2042 return (*this);
2043 }
2044
replaceAll(const char c,const char * str)2045 KviCString & KviCString::replaceAll(const char c, const char * str)
2046 {
2047 int idx = findFirstIdx(c);
2048 KviCString tmp;
2049 while(idx >= 0)
2050 {
2051 if(idx > 0)
2052 tmp += left(idx);
2053 cutLeft(idx + 1);
2054 tmp.append(str);
2055 idx = findFirstIdx(c);
2056 }
2057 tmp.append(*this);
2058 // Now copy
2059 m_len = tmp.m_len;
2060 m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
2061 KviMemory::copy(m_ptr, tmp.m_ptr, m_len + 1);
2062 return (*this);
2063 }
2064
replaceAll(const char * toFind,const char * str,bool bCaseS)2065 KviCString & KviCString::replaceAll(const char * toFind, const char * str, bool bCaseS)
2066 {
2067 int len = (int)strlen(toFind);
2068 int idx = findFirstIdx(toFind, bCaseS);
2069 KviCString tmp;
2070 while(idx >= 0)
2071 {
2072 if(idx > 0)
2073 tmp += left(idx);
2074 cutLeft(idx + len);
2075 tmp.append(str);
2076 idx = findFirstIdx(toFind, bCaseS);
2077 }
2078 tmp.append(*this);
2079 // Now copy
2080 m_len = tmp.m_len;
2081 m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
2082 KviMemory::copy(m_ptr, tmp.m_ptr, m_len + 1);
2083 return (*this);
2084 }
2085
transliterate(const char * szToFind,const char * szReplacement)2086 KviCString & KviCString::transliterate(const char * szToFind, const char * szReplacement)
2087 {
2088 while(*szToFind && *szReplacement)
2089 {
2090 char * p = m_ptr;
2091 while(*p)
2092 {
2093 if(*p == *szToFind)
2094 *p = *szReplacement;
2095 ++p;
2096 }
2097 ++szToFind;
2098 ++szReplacement;
2099 }
2100 return (*this);
2101 }
2102
occurrences(char c,bool caseS) const2103 int KviCString::occurrences(char c, bool caseS) const
2104 {
2105 char * p = m_ptr;
2106 int cnt = 0;
2107 if(caseS)
2108 {
2109 while(*p)
2110 {
2111 if(*p == c)
2112 cnt++;
2113 p++;
2114 }
2115 }
2116 else
2117 {
2118 char b = tolower(c);
2119 while(*p)
2120 {
2121 if(tolower(*p) == b)
2122 cnt++;
2123 p++;
2124 }
2125 }
2126 return cnt;
2127 }
2128
occurrences(const char * str,bool caseS) const2129 int KviCString::occurrences(const char * str, bool caseS) const
2130 {
2131 KVI_ASSERT(str);
2132 char * p = m_ptr;
2133 int cnt = 0;
2134 int len = (int)strlen(str);
2135 if(caseS)
2136 {
2137 while(*p)
2138 {
2139 if(*p == *str)
2140 {
2141 if(kvi_strEqualCSN(p, str, len))
2142 cnt++;
2143 }
2144 p++;
2145 }
2146 }
2147 else
2148 {
2149 while(*p)
2150 {
2151 char c = tolower(*str);
2152 if(tolower(*p) == c)
2153 {
2154 if(kvi_strEqualCIN(p, str, len))
2155 cnt++;
2156 }
2157 p++;
2158 }
2159 }
2160 return cnt;
2161 }
2162
contains(char c,bool caseS) const2163 bool KviCString::contains(char c, bool caseS) const
2164 {
2165 char * p = m_ptr;
2166 if(caseS)
2167 {
2168 while(*p)
2169 {
2170 if(*p == c)
2171 return true;
2172 p++;
2173 }
2174 }
2175 else
2176 {
2177 char b = tolower(c);
2178 while(*p)
2179 {
2180 if(tolower(*p) == b)
2181 return true;
2182 p++;
2183 }
2184 }
2185 return false;
2186 }
2187
contains(const char * str,bool caseS) const2188 bool KviCString::contains(const char * str, bool caseS) const
2189 {
2190 KVI_ASSERT(str);
2191 char * p = m_ptr;
2192 int len = (int)strlen(str);
2193 if(caseS)
2194 {
2195 while(*p)
2196 {
2197 if(*p == *str)
2198 {
2199 if(kvi_strEqualCSN(p, str, len))
2200 return true;
2201 }
2202 p++;
2203 }
2204 }
2205 else
2206 {
2207 while(*p)
2208 {
2209 char c = tolower(*str);
2210 if(tolower(*p) == c)
2211 {
2212 if(kvi_strEqualCIN(p, str, len))
2213 return true;
2214 }
2215 p++;
2216 }
2217 }
2218 return false;
2219 }
2220
setNum(long num)2221 KviCString & KviCString::setNum(long num)
2222 {
2223 char numberBuffer[30];
2224 bool bNegative = false;
2225 long tmp;
2226 char * p;
2227 char * pNumBuf = numberBuffer;
2228
2229 // somebody can explain to me why -(-2147483648) = -2147483648 ? (2^31)
2230 // it is like signed char x = 128 ---> 10000000 that is signed -0 (!?)
2231 // mmmmh...or it is assumed to be -128 (a number representation exception)
2232 // at least on my machine it happens...
2233
2234 // found the solution by myself today...
2235 //
2236 // ABS(3) Linux Programmer's Manual ABS(3)
2237 // NAME
2238 // abs - computes the absolute value of an integer.
2239 // ...
2240 // DESCRIPTION
2241 // The abs() function computes the absolute value of the integer argument j.
2242 // RETURN VALUE
2243 // Returns the absolute value of the integer argument.
2244 // CONFORMING TO
2245 // SVID 3, POSIX, BSD 4.3, ISO 9899
2246 // NOTE ##################################################################################
2247 // Trying to take the absolute value of the most negative integer is not defined.
2248 // #######################################################################################
2249
2250 // so should i use temporaneous doubles to make calculations ?
2251
2252 if(num < 0)
2253 { //negative integer
2254 bNegative = true;
2255 num = -num; //need to have it positive
2256 if(num < 0)
2257 { // 2^31 exception
2258 // We need to avoid absurd responses like ".(./),." :)
2259 num = 0; // we get a negative zero here...it is still an exception
2260 }
2261 }
2262
2263 //write the number in a temporary buffer (at least '0')
2264 do
2265 {
2266 tmp = num / 10;
2267 *pNumBuf++ = num - (tmp * 10) + '0';
2268 } while((num = tmp));
2269
2270 //copy now....
2271 m_len = pNumBuf - numberBuffer; //length of the number string
2272 if(bNegative)
2273 {
2274 m_len++;
2275 m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
2276 p = m_ptr;
2277 *p++ = '-';
2278 }
2279 else
2280 {
2281 m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
2282 p = m_ptr;
2283 }
2284 do
2285 {
2286 *p++ = *--pNumBuf;
2287 } while(pNumBuf != numberBuffer);
2288 *(m_ptr + m_len) = '\0';
2289 return (*this);
2290 }
2291
setNum(unsigned long num)2292 KviCString & KviCString::setNum(unsigned long num)
2293 {
2294 char numberBuffer[30];
2295 unsigned long tmp;
2296 char * p;
2297 char * pNumBuf = numberBuffer;
2298
2299 //write the number in a temporary buffer (at least '0')
2300 do
2301 {
2302 tmp = num / 10;
2303 *pNumBuf++ = num - (tmp * 10) + '0';
2304 } while((num = tmp));
2305
2306 //copy now....
2307 m_len = pNumBuf - numberBuffer; //length of the number string
2308 m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
2309 p = m_ptr;
2310 do
2311 {
2312 *p++ = *--pNumBuf;
2313 } while(pNumBuf != numberBuffer);
2314 *(m_ptr + m_len) = '\0';
2315 return (*this);
2316 }
2317
toLongLong(bool * bOk) const2318 long long KviCString::toLongLong(bool * bOk) const
2319 {
2320 long long result = 0;
2321 if(bOk)
2322 *bOk = false;
2323 char * p = m_ptr;
2324 bool bNeg = false;
2325 while(isspace(*p))
2326 p++; //skip spaces
2327 if(*p == '-')
2328 {
2329 bNeg = true;
2330 p++;
2331 }
2332 else
2333 {
2334 if(*p == '+')
2335 p++;
2336 }
2337 if(isdigit(*p))
2338 { //point to something interesting ?
2339 do
2340 {
2341 result = (result * 10) + (*p - '0');
2342 p++;
2343 } while(isdigit(*p));
2344 if(bNeg)
2345 result = -result;
2346 while(isspace(*p))
2347 p++; //skip trailing spaces
2348 if(*p)
2349 return 0; //if this is not the end...die.
2350 if(bOk)
2351 *bOk = true;
2352 return result;
2353 }
2354 return 0;
2355 }
2356
toULongLong(bool * bOk) const2357 unsigned long long KviCString::toULongLong(bool * bOk) const
2358 {
2359 unsigned long long result = 0;
2360 if(bOk)
2361 *bOk = false;
2362 char * p = m_ptr;
2363 while(isspace(*p))
2364 p++; //skip spaces
2365 if(isdigit(*p))
2366 { //point to something interesting ?
2367 do
2368 {
2369 result = (result * 10) + (*p - '0');
2370 p++;
2371 } while(isdigit(*p));
2372 while(isspace(*p))
2373 p++; //skip trailing spaces
2374 if(*p)
2375 return 0; //if this is not the end...die.
2376 if(bOk)
2377 *bOk = true;
2378 return result;
2379 }
2380 return 0;
2381 }
2382
toLong(bool * bOk) const2383 long KviCString::toLong(bool * bOk) const
2384 {
2385 long result = 0;
2386 if(bOk)
2387 *bOk = false;
2388 char * p = m_ptr;
2389 bool bNeg = false;
2390 while(isspace(*p))
2391 p++; //skip spaces
2392 if(*p == '-')
2393 {
2394 bNeg = true;
2395 p++;
2396 }
2397 else
2398 {
2399 if(*p == '+')
2400 p++;
2401 }
2402 if(isdigit(*p))
2403 { //point to something interesting ?
2404 do
2405 {
2406 result = (result * 10) + (*p - '0');
2407 p++;
2408 } while(isdigit(*p));
2409 if(bNeg)
2410 result = -result;
2411 while(isspace(*p))
2412 p++; //skip trailing spaces
2413 if(*p)
2414 return 0; //if this is not the end...die.
2415 if(bOk)
2416 *bOk = true;
2417 return result;
2418 }
2419 return 0;
2420 }
2421
toULong(bool * bOk) const2422 unsigned long KviCString::toULong(bool * bOk) const
2423 {
2424 unsigned long result = 0;
2425 if(bOk)
2426 *bOk = false;
2427 char * p = m_ptr;
2428 while(isspace(*p))
2429 p++; //skip spaces
2430 if(isdigit(*p))
2431 { //point to something interesting ?
2432 do
2433 {
2434 result = (result * 10) + (*p - '0');
2435 p++;
2436 } while(isdigit(*p));
2437 while(isspace(*p))
2438 p++; //skip trailing spaces
2439 if(*p)
2440 return 0; //if this is not the end...die.
2441 if(bOk)
2442 *bOk = true;
2443 return result;
2444 }
2445 return 0;
2446 }
2447
toLongExt(bool * bOk,int base)2448 long KviCString::toLongExt(bool * bOk, int base)
2449 {
2450 if(m_len == 0)
2451 {
2452 if(bOk)
2453 *bOk = false;
2454 return 0;
2455 }
2456 char * endptr;
2457 long result = strtol(m_ptr, &endptr, base);
2458 if(*endptr)
2459 {
2460 // must be whitespaces, otherwise there is trailing garbage inside
2461 while(isspace(*endptr) && (*endptr))
2462 endptr++;
2463 if(*endptr)
2464 {
2465 // still not at the end
2466 // trailing garbage not allowed
2467 if(bOk)
2468 *bOk = false;
2469 return result;
2470 }
2471 }
2472 if(bOk)
2473 *bOk = true;
2474 return result;
2475 }
2476
cutLeft(int len)2477 KviCString & KviCString::cutLeft(int len)
2478 {
2479 KVI_ASSERT(len >= 0);
2480 if(len <= m_len)
2481 {
2482 m_len -= len;
2483 KviMemory::move(m_ptr, m_ptr + len, m_len + 1);
2484 m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
2485 }
2486 else
2487 {
2488 m_ptr = (char *)KviMemory::reallocate(m_ptr, 1);
2489 *m_ptr = '\0';
2490 m_len = 0;
2491 }
2492 return (*this);
2493 }
2494
cutRight(int len)2495 KviCString & KviCString::cutRight(int len)
2496 {
2497 KVI_ASSERT(len >= 0);
2498 if(len <= m_len)
2499 {
2500 m_len -= len;
2501 m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
2502 *(m_ptr + m_len) = '\0';
2503 }
2504 else
2505 {
2506 m_ptr = (char *)KviMemory::reallocate(m_ptr, 1);
2507 *m_ptr = '\0';
2508 m_len = 0;
2509 }
2510 return (*this);
2511 }
2512
cut(int idx,int len)2513 KviCString & KviCString::cut(int idx, int len)
2514 {
2515 KVI_ASSERT(idx >= 0);
2516 KVI_ASSERT(len >= 0);
2517 if(idx < m_len)
2518 {
2519 // idx = 3 len = 3 m_len = 10
2520 // 0123456789
2521 // abcdefghij
2522 // ^ ^
2523 // p1 p2
2524 char * p1 = m_ptr + idx;
2525 if(len + idx > m_len)
2526 len = m_len - idx;
2527 char * p2 = p1 + len;
2528 KviMemory::move(p1, p2, (m_len - (len + idx)) + 1);
2529 m_len -= len;
2530 m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
2531 }
2532 return (*this);
2533 }
2534
cutToFirst(char c,bool bIncluded)2535 KviCString & KviCString::cutToFirst(char c, bool bIncluded)
2536 {
2537 int idx = findFirstIdx(c);
2538 if(idx != -1)
2539 cutLeft(bIncluded ? idx + 1 : idx);
2540 return (*this);
2541 }
2542
leftToFirst(char c,bool bIncluded) const2543 KviCString KviCString::leftToFirst(char c, bool bIncluded) const
2544 {
2545 int idx = findFirstIdx(c);
2546 if(idx == -1)
2547 return KviCString(*this);
2548 return KviCString(m_ptr, bIncluded ? idx + 1 : idx);
2549 }
2550
leftToLast(char c,bool bIncluded) const2551 KviCString KviCString::leftToLast(char c, bool bIncluded) const
2552 {
2553 int idx = findLastIdx(c);
2554 return KviCString(m_ptr, bIncluded ? idx + 1 : idx);
2555 }
2556
cutFromFirst(char c,bool bIncluded)2557 KviCString & KviCString::cutFromFirst(char c, bool bIncluded)
2558 {
2559 int idx = findFirstIdx(c);
2560 if(idx != -1)
2561 cutRight(bIncluded ? (m_len - idx) : (m_len - (idx + 1)));
2562 return (*this);
2563 }
2564
cutToLast(char c,bool bIncluded)2565 KviCString & KviCString::cutToLast(char c, bool bIncluded)
2566 {
2567 int idx = findLastIdx(c);
2568 if(idx != -1)
2569 cutLeft(bIncluded ? idx + 1 : idx);
2570 return (*this);
2571 }
2572
cutFromLast(char c,bool bIncluded)2573 KviCString & KviCString::cutFromLast(char c, bool bIncluded)
2574 {
2575 int idx = findLastIdx(c);
2576 if(idx != -1)
2577 cutRight(bIncluded ? (m_len - idx) : (m_len - (idx + 1)));
2578 return (*this);
2579 }
2580
cutToFirst(const char * c,bool bIncluded)2581 KviCString & KviCString::cutToFirst(const char * c, bool bIncluded)
2582 {
2583 int len = (int)strlen(c);
2584 int idx = findFirstIdx(c);
2585 if(idx != -1)
2586 cutLeft(bIncluded ? idx + len : idx);
2587 return (*this);
2588 }
2589
cutFromFirst(const char * c,bool bIncluded)2590 KviCString & KviCString::cutFromFirst(const char * c, bool bIncluded)
2591 {
2592 int len = (int)strlen(c);
2593 int idx = findFirstIdx(c);
2594 if(idx != -1)
2595 cutRight(bIncluded ? (m_len - idx) : (m_len - (idx + len)));
2596 return (*this);
2597 }
2598
cutToLast(const char * c,bool bIncluded)2599 KviCString & KviCString::cutToLast(const char * c, bool bIncluded)
2600 {
2601 int len = (int)strlen(c);
2602 int idx = findLastIdx(c);
2603 if(idx != -1)
2604 cutLeft(bIncluded ? idx + len : idx);
2605 return (*this);
2606 }
2607
cutFromLast(const char * c,bool bIncluded)2608 KviCString & KviCString::cutFromLast(const char * c, bool bIncluded)
2609 {
2610 int len = (int)strlen(c);
2611 int idx = findLastIdx(c);
2612 if(idx != -1)
2613 cutRight(bIncluded ? (m_len - idx) : (m_len - (idx + len)));
2614 return (*this);
2615 }
2616
setLen(int iLen)2617 KviCString & KviCString::setLen(int iLen)
2618 {
2619 KVI_ASSERT(iLen >= 0);
2620 m_len = iLen;
2621 m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
2622 *(m_ptr + m_len) = '\0';
2623 return (*this);
2624 }
2625
padRight(int iLen,const char c)2626 KviCString & KviCString::padRight(int iLen, const char c)
2627 {
2628 KVI_ASSERT(iLen >= 0);
2629 m_ptr = (char *)KviMemory::reallocate(m_ptr, iLen + 1);
2630 *(m_ptr + iLen) = '\0';
2631 if(iLen > m_len)
2632 KviMemory::set(m_ptr + m_len, c, iLen - m_len);
2633 m_len = iLen;
2634 return (*this);
2635 }
2636
stripLeftWhiteSpace()2637 KviCString & KviCString::stripLeftWhiteSpace()
2638 {
2639 char * p = m_ptr;
2640 while(isspace(*p))
2641 p++;
2642 m_len -= (p - m_ptr);
2643 KviMemory::move(m_ptr, p, m_len + 1);
2644 m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
2645 return (*this);
2646 }
2647
stripLeft(char c)2648 KviCString & KviCString::stripLeft(char c)
2649 {
2650 KVI_ASSERT(c != '\0');
2651 char * p = m_ptr;
2652 while(*p == c)
2653 p++;
2654 m_len -= (p - m_ptr);
2655 KviMemory::move(m_ptr, p, m_len + 1);
2656 m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
2657 return (*this);
2658 }
2659
getToken(KviCString & str,char sep)2660 bool KviCString::getToken(KviCString & str, char sep)
2661 {
2662 KVI_ASSERT(str.m_ptr);
2663 KVI_ASSERT(str.m_ptr != m_ptr);
2664 char * p = m_ptr;
2665 //skip to the end
2666 while(*p && (*p != sep))
2667 p++;
2668 //0123456789
2669 //abcd xyz
2670 //^ ^
2671 str.m_len = p - m_ptr;
2672 str.m_ptr = (char *)KviMemory::reallocate(str.m_ptr, str.m_len + 1);
2673 KviMemory::copy(str.m_ptr, m_ptr, str.m_len);
2674 *(str.m_ptr + str.m_len) = '\0';
2675 while(*p && (*p == sep))
2676 p++;
2677 cutLeft(p - m_ptr);
2678 return (m_len != 0);
2679 }
2680
getLine(KviCString & str)2681 bool KviCString::getLine(KviCString & str)
2682 {
2683 KVI_ASSERT(str.m_ptr);
2684 KVI_ASSERT(str.m_ptr != m_ptr);
2685 if(m_len == 0)
2686 return false;
2687 char * p = m_ptr;
2688 //skip to the end
2689 while(*p && (*p != '\n'))
2690 p++;
2691 //0123456789
2692 //abcd xyz
2693 //^ ^
2694 str.m_len = p - m_ptr;
2695 str.m_ptr = (char *)KviMemory::reallocate(str.m_ptr, str.m_len + 1);
2696 KviMemory::copy(str.m_ptr, m_ptr, str.m_len);
2697 *(str.m_ptr + str.m_len) = '\0';
2698 p++;
2699 cutLeft(p - m_ptr);
2700 return true;
2701 }
2702
getToken(char sep)2703 KviCString KviCString::getToken(char sep)
2704 {
2705 char * p = m_ptr;
2706 while(*p && (*p != sep))
2707 p++;
2708 KviCString ret(m_ptr, p);
2709 while(*p && (*p == sep))
2710 p++;
2711 cutLeft(p - m_ptr);
2712 return ret;
2713 }
2714
vsprintf(const char * fmt,kvi_va_list list)2715 KviCString & KviCString::vsprintf(const char * fmt, kvi_va_list list)
2716 {
2717 kvi_va_list save;
2718 kvi_va_copy(save, list);
2719
2720 m_ptr = (char *)KviMemory::reallocate(m_ptr, 256);
2721 //First try
2722 //print...with max 256 chars
2723 m_len = kvi_vsnprintf(m_ptr, 256, fmt, list);
2724
2725 //check if we failed
2726 if(m_len < 0)
2727 {
2728 //yes, failed....
2729 int dummy = 256;
2730 do
2731 { //we failed, so retry with 256 more chars
2732 dummy += 256;
2733 //realloc
2734 m_ptr = (char *)KviMemory::reallocate(m_ptr, dummy);
2735 //print...
2736 kvi_va_copy(list, save);
2737 m_len = kvi_vsnprintf(m_ptr, dummy, fmt, list);
2738 } while(m_len < 0);
2739 }
2740 //done...
2741 //now m_len is the length of the written string not including the terminator...
2742 //perfect! :)
2743 m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
2744 kvi_va_end(save);
2745 return (*this);
2746 }
2747
sprintf(const char * fmt,...)2748 KviCString & KviCString::sprintf(const char * fmt, ...)
2749 {
2750 m_ptr = (char *)KviMemory::reallocate(m_ptr, 256);
2751 //First try
2752 kvi_va_list list;
2753 kvi_va_start(list, fmt);
2754 //print...with max 256 chars
2755 m_len = kvi_vsnprintf(m_ptr, 256, fmt, list);
2756 kvi_va_end(list);
2757
2758 //check if we failed
2759 if(m_len < 0)
2760 {
2761 //yes, failed....
2762 int dummy = 256;
2763 do
2764 { //we failed, so retry with 256 more chars
2765 dummy += 256;
2766 //realloc
2767 m_ptr = (char *)KviMemory::reallocate(m_ptr, dummy);
2768 //print...
2769 kvi_va_start(list, fmt);
2770 m_len = kvi_vsnprintf(m_ptr, dummy, fmt, list);
2771 kvi_va_end(list);
2772 } while(m_len < 0);
2773 }
2774 //done...
2775 //now m_len is the length of the written string not including the terminator...
2776 //perfect! :)
2777 m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
2778 return (*this);
2779 }
2780
find(const char * str,int idx,bool caseS) const2781 int KviCString::find(const char * str, int idx, bool caseS) const
2782 {
2783 if(idx >= m_len)
2784 return -1;
2785 char * p = m_ptr + idx;
2786 int len = (int)strlen(str);
2787 if(caseS)
2788 {
2789 for(;;)
2790 {
2791 while(*p && (*p != *str))
2792 p++;
2793 if(*p)
2794 {
2795 if(kvi_strEqualCSN(str, p, len))
2796 return (p - m_ptr);
2797 else
2798 p++;
2799 }
2800 else
2801 return -1;
2802 }
2803 }
2804 else
2805 {
2806 for(;;)
2807 {
2808 char tmp = toupper(*str);
2809 while(*p && (toupper(*p) != tmp))
2810 p++;
2811 if(*p)
2812 {
2813 if(kvi_strEqualCIN(str, p, len))
2814 return (p - m_ptr);
2815 else
2816 p++;
2817 }
2818 else
2819 return -1;
2820 }
2821 }
2822 }
2823
find(char c,int idx) const2824 int KviCString::find(char c, int idx) const
2825 {
2826 if(idx >= m_len)
2827 return -1;
2828 char * p = m_ptr + idx;
2829 while(*p && (*p != c))
2830 p++;
2831 return (*p ? p - m_ptr : -1);
2832 }
2833
findRev(const char * str,int idx,bool caseS) const2834 int KviCString::findRev(const char * str, int idx, bool caseS) const
2835 {
2836 if((m_len + idx) < 0)
2837 return -1;
2838 char * p = m_ptr + m_len + idx;
2839 int len = (int)strlen(str);
2840 if(caseS)
2841 {
2842 for(;;)
2843 {
2844 while((p >= m_ptr) && (*p != *str))
2845 p--;
2846 if(p >= m_ptr)
2847 {
2848 if(kvi_strEqualCSN(str, p, len))
2849 return (p - m_ptr);
2850 else
2851 p--;
2852 }
2853 else
2854 return -1;
2855 }
2856 }
2857 else
2858 {
2859 for(;;)
2860 {
2861 char tmp = toupper(*str);
2862 while((p >= m_ptr) && (toupper(*p) != tmp))
2863 p--;
2864 if(p >= m_ptr)
2865 {
2866 if(kvi_strEqualCIN(str, p, len))
2867 return (p - m_ptr);
2868 else
2869 p--;
2870 }
2871 else
2872 return -1;
2873 }
2874 }
2875 }
2876
findFirstIdx(char c) const2877 int KviCString::findFirstIdx(char c) const
2878 {
2879 char * p = m_ptr;
2880 while(*p && (*p != c))
2881 p++;
2882 return (*p ? p - m_ptr : -1);
2883 }
2884
findFirstIdx(const char * str,bool caseS) const2885 int KviCString::findFirstIdx(const char * str, bool caseS) const
2886 {
2887 // This function can't be used to search inside
2888 // multibyte encoded strings... convert your
2889 // code to QString and use QString::findRev().
2890 // We must throw away KviCString at all in this case...
2891
2892 // return QString(m_ptr).find(QString(str),0,caseS);
2893
2894 // Both this KviCString and the const char * str are assumed
2895 // to be in the proper (and same) encoding.
2896 // If KviCString is in encoding A then QString(m_ptr) might
2897 // or not be decoded correctly.
2898 // Also if KviCString is in UTF-8 (for example), then
2899 // a position in QString() does not map to the position in the char array
2900 // since a single UNICODE char may use one or more bytes...
2901
2902 KVI_ASSERT(str);
2903 char * p = m_ptr;
2904 int len = (int)strlen(str);
2905 if(caseS)
2906 {
2907 for(;;)
2908 {
2909 while(*p && (*p != *str))
2910 p++;
2911 if(*p)
2912 {
2913 if(kvi_strEqualCSN(str, p, len))
2914 return (p - m_ptr);
2915 else
2916 p++;
2917 }
2918 else
2919 return -1;
2920 }
2921 }
2922 else
2923 {
2924 // this will NOT work for strings that aren't in the current system encoding :(
2925 for(;;)
2926 {
2927 char tmp = toupper(*str);
2928 while(*p && (toupper(*p) != tmp))
2929 p++;
2930 if(*p)
2931 {
2932 if(kvi_strEqualCIN(str, p, len))
2933 return (p - m_ptr);
2934 else
2935 p++;
2936 }
2937 else
2938 return -1;
2939 }
2940 }
2941 }
2942
findLastIdx(char c) const2943 int KviCString::findLastIdx(char c) const
2944 {
2945 //Empty string ?
2946 if(m_len < 1)
2947 return -1;
2948 //p points to the last character in the string
2949 char * p = ((m_ptr + m_len) - 1);
2950 //go back until we find a match or we run to the first char in the string.
2951 while((*p != c) && (p > m_ptr))
2952 p--;
2953 //if *p == c --> matched, else we are at the beginning of the string.
2954 return ((*p == c) ? p - m_ptr : -1);
2955 }
2956
findLastIdx(const char * str,bool caseS) const2957 int KviCString::findLastIdx(const char * str, bool caseS) const
2958 {
2959 // This function can't be used to search inside
2960 // multibyte encoded strings... convert your
2961 // code to QString and use QString::findRev().
2962 // We must throw away KviCString at all in this case...
2963
2964 // return QString(m_ptr).findRev(QString(str),-1,caseS);
2965
2966 KVI_ASSERT(str);
2967 //Calc the len of the searched string
2968 int len = (int)strlen(str);
2969 //Too long ?
2970 if(m_len < len)
2971 return -1;
2972 //p points to the last character in the string
2973 char * p = ((m_ptr + m_len) - 1);
2974 if(caseS)
2975 {
2976 for(;;)
2977 {
2978 //go back until we find a character that mathes or we run to the first char.
2979 while((*p != *str) && (p > m_ptr))
2980 p--;
2981 if(*p == *str)
2982 {
2983 //maybe occurrence....
2984 if(kvi_strEqualCSN(str, p, len))
2985 return (p - m_ptr);
2986 else
2987 {
2988 //Nope...continue if there is more data to check...
2989 if(p == m_ptr)
2990 return -1;
2991 p--;
2992 }
2993 }
2994 else
2995 return -1; //Beginning of the string
2996 }
2997 }
2998 else
2999 {
3000 // case insensitive
3001 for(;;)
3002 {
3003 //go back until we find a character that mathes or we run to the first char.
3004 char tmp = toupper(*str);
3005 while((toupper(*p) != tmp) && (p > m_ptr))
3006 p--;
3007 if(toupper(*p) == tmp)
3008 {
3009 //maybe occurrence....
3010 if(kvi_strEqualCIN(str, p, len))
3011 return (p - m_ptr);
3012 else
3013 {
3014 //Nope...continue if there is more data to check...
3015 if(p == m_ptr)
3016 return -1;
3017 p--;
3018 }
3019 }
3020 else
3021 return -1; //Beginning of the string
3022 }
3023 }
3024 }
3025
trim()3026 KviCString & KviCString::trim()
3027 {
3028 // 0123456789
3029 // abcd 0
3030 // ^ ^
3031 // left right
3032 char * left = m_ptr;
3033 char * right = m_ptr + m_len - 1;
3034 // skip initial spaces
3035 while(isspace(*left))
3036 left++;
3037 if(*left)
3038 {
3039 // valid string, left points to first non-space
3040 while((right >= left) && isspace(*right))
3041 right--;
3042 // 0123456789
3043 // abcd 0
3044 // ^ ^
3045 // left right
3046 m_len = (right - left) + 1;
3047 KviMemory::move(m_ptr, left, m_len);
3048 m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
3049 *(m_ptr + m_len) = '\0';
3050 }
3051 else
3052 {
3053 m_ptr = (char *)KviMemory::reallocate(m_ptr, 1);
3054 *m_ptr = '\0';
3055 m_len = 0;
3056 }
3057 return (*this);
3058 }
3059
stripRightWhiteSpace()3060 KviCString & KviCString::stripRightWhiteSpace()
3061 {
3062 if(*m_ptr)
3063 {
3064 char * right = m_ptr + m_len - 1;
3065 const char * start = right;
3066 //isspace accepts 0..255 values in MSVC
3067 while((right >= m_ptr) && ((unsigned)(*right + 1) <= 256) && isspace(*right))
3068 right--;
3069 if(right != start)
3070 {
3071 m_len = (right - m_ptr) + 1;
3072 m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
3073 *(m_ptr + m_len) = '\0';
3074 }
3075 }
3076 return (*this);
3077 }
3078
stripRight(char c)3079 KviCString & KviCString::stripRight(char c)
3080 {
3081 if(*m_ptr)
3082 {
3083 char * right = m_ptr + m_len - 1;
3084 const char * start = right;
3085 while((right >= m_ptr) && (*right == c))
3086 right--;
3087 if(right != start)
3088 {
3089 m_len = (right - m_ptr) + 1;
3090 m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
3091 *(m_ptr + m_len) = '\0';
3092 }
3093 }
3094 return (*this);
3095 }
3096
stripSpace()3097 KviCString & KviCString::stripSpace()
3098 {
3099 // 0123456789
3100 // abcd 0
3101 // ^ ^
3102 // left right
3103 char * left = m_ptr;
3104 char * right = m_ptr + m_len - 1;
3105 // skip initial spaces
3106 while((*left == ' ') || (*left == '\t'))
3107 left++;
3108 if(*left)
3109 {
3110 // valid string, left points to first non-space
3111 while((right >= left) && ((*right == ' ') || (*right == '\t')))
3112 right--;
3113 // 0123456789
3114 // abcd 0
3115 // ^ ^
3116 // left right
3117 m_len = (right - left) + 1;
3118 KviMemory::move(m_ptr, left, m_len);
3119 m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
3120 *(m_ptr + m_len) = '\0';
3121 }
3122 else
3123 {
3124 m_ptr = (char *)KviMemory::reallocate(m_ptr, 1);
3125 *m_ptr = '\0';
3126 m_len = 0;
3127 }
3128 return (*this);
3129 }
3130
isNum() const3131 bool KviCString::isNum() const
3132 {
3133 char * p = m_ptr;
3134 while(isspace(*p))
3135 p++;
3136 if(*p == '-')
3137 p++;
3138 if(!isdigit(*p))
3139 return false;
3140 while(isdigit(*p))
3141 p++;
3142 while(isspace(*p))
3143 p++;
3144 return (*p == '\0');
3145 }
3146
isUnsignedNum() const3147 bool KviCString::isUnsignedNum() const
3148 {
3149 char * p = m_ptr;
3150 while(isspace(*p))
3151 p++;
3152 if(!isdigit(*p))
3153 return false;
3154 while(isdigit(*p))
3155 p++;
3156 while(isspace(*p))
3157 p++;
3158 return (*p == '\0');
3159 }
3160
3161 static KviCString g_szApplicationWideEmptyString;
3162
emptyString()3163 KviCString & KviCString::emptyString()
3164 {
3165 return g_szApplicationWideEmptyString;
3166 }
3167
ext_contains(const char * data,const char * item,bool caseS)3168 bool KviCString::ext_contains(const char * data, const char * item, bool caseS)
3169 {
3170 if(item && data)
3171 {
3172 int len = (int)strlen(item);
3173 char c = tolower(*item);
3174 if(caseS)
3175 {
3176 while(*data)
3177 {
3178 while(*data && (tolower(*data) != c))
3179 data++;
3180 if(*data)
3181 {
3182 if(kvi_strEqualCSN(item, data, len))
3183 return true;
3184 else
3185 data++;
3186 }
3187 }
3188 }
3189 else
3190 {
3191 while(*data)
3192 {
3193 while(*data && (tolower(*data) != c))
3194 data++;
3195 if(*data)
3196 {
3197 if(kvi_strEqualCIN(item, data, len))
3198 return true;
3199 else
3200 data++;
3201 }
3202 }
3203 }
3204 }
3205 return false;
3206 }
3207