1 /*
2 * contain.cxx
3 *
4 * Container Classes
5 *
6 * Portable Windows Library
7 *
8 * Copyright (c) 1993-1998 Equivalence Pty. Ltd.
9 *
10 * The contents of this file are subject to the Mozilla Public License
11 * Version 1.0 (the "License"); you may not use this file except in
12 * compliance with the License. You may obtain a copy of the License at
13 * http://www.mozilla.org/MPL/
14 *
15 * Software distributed under the License is distributed on an "AS IS"
16 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
17 * the License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * The Original Code is Portable Windows Library.
21 *
22 * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
23 *
24 * Portions are Copyright (C) 1993 Free Software Foundation, Inc.
25 * All Rights Reserved.
26 *
27 * Contributor(s): ______________________________________.
28 *
29 * $Revision: 28045 $
30 * $Author: rjongbloed $
31 * $Date: 2012-07-17 02:31:23 -0500 (Tue, 17 Jul 2012) $
32 */
33
34 #include <ptlib.h>
35 #include <ctype.h>
36
37
38 #ifdef __NUCLEUS_PLUS__
39 extern "C" int vsprintf(char *, const char *, va_list);
40 #endif
41
42 #if P_REGEX
43 #include <regex.h>
44 #else
45 #include "regex/regex.h"
46 #endif
47
48 #define regexpression() ((regex_t *)expression)
49
50 #if !P_USE_INLINES
51 #include "ptlib/contain.inl"
52 #endif
53
54
55 PDEFINE_POOL_ALLOCATOR(PContainerReference);
56
57
58 #define new PNEW
59 #undef __CLASS__
60 #define __CLASS__ GetClass()
61
62
63 ///////////////////////////////////////////////////////////////////////////////
64
PContainer(PINDEX initialSize)65 PContainer::PContainer(PINDEX initialSize)
66 {
67 reference = new PContainerReference(initialSize);
68 PAssert(reference != NULL, POutOfMemory);
69 }
70
71
PContainer(int,const PContainer * cont)72 PContainer::PContainer(int, const PContainer * cont)
73 {
74 if (cont == this)
75 return;
76
77 PAssert(cont != NULL, PInvalidParameter);
78 PAssert2(cont->reference != NULL, cont->GetClass(), "Clone of deleted container");
79
80 reference = new PContainerReference(*cont->reference);
81 PAssert(reference != NULL, POutOfMemory);
82 }
83
84
PContainer(const PContainer & cont)85 PContainer::PContainer(const PContainer & cont)
86 {
87 if (&cont == this)
88 return;
89
90 PAssert2(cont.reference != NULL, cont.GetClass(), "Copy of deleted container");
91
92 ++cont.reference->count;
93 reference = cont.reference; // copy the reference pointer
94 }
95
96
PContainer(PContainerReference & ref)97 PContainer::PContainer(PContainerReference & ref)
98 : reference(&ref)
99 {
100 }
101
102
AssignContents(const PContainer & cont)103 void PContainer::AssignContents(const PContainer & cont)
104 {
105 if(cont.reference == NULL){
106 PAssertAlways("container reference is null");
107 return;
108 }
109 if(cont.GetClass() == NULL){
110 PAssertAlways("container class is null");
111 return;
112 }
113
114 if (reference == cont.reference)
115 return;
116
117 if (--reference->count == 0) {
118 DestroyContents();
119 DestroyReference();
120 }
121
122 PAssert(++cont.reference->count > 1, "Assignment of container that was deleted");
123 reference = cont.reference;
124 }
125
126
Destruct()127 void PContainer::Destruct()
128 {
129 if (reference != NULL) {
130 if (--reference->count <= 0) {
131 DestroyContents();
132 DestroyReference();
133 }
134 reference = NULL;
135 }
136 }
137
138
DestroyReference()139 void PContainer::DestroyReference()
140 {
141 delete reference;
142 }
143
144
SetMinSize(PINDEX minSize)145 PBoolean PContainer::SetMinSize(PINDEX minSize)
146 {
147 PASSERTINDEX(minSize);
148 if (minSize < 0)
149 minSize = 0;
150 if (minSize < GetSize())
151 minSize = GetSize();
152 return SetSize(minSize);
153 }
154
155
MakeUnique()156 PBoolean PContainer::MakeUnique()
157 {
158 if (IsUnique())
159 return PTrue;
160
161 PContainerReference * oldReference = reference;
162 reference = new PContainerReference(*reference);
163 --oldReference->count;
164
165 return PFalse;
166 }
167
168
169 ///////////////////////////////////////////////////////////////////////////////
170
171 static PVariablePoolAllocator<char> PAbstractArray_allocator;
172
PAbstractArray(PINDEX elementSizeInBytes,PINDEX initialSize)173 PAbstractArray::PAbstractArray(PINDEX elementSizeInBytes, PINDEX initialSize)
174 : PContainer(initialSize)
175 {
176 elementSize = elementSizeInBytes;
177 PAssert(elementSize != 0, PInvalidParameter);
178
179 if (GetSize() == 0)
180 theArray = NULL;
181 else {
182 theArray = PAbstractArray_allocator.allocate(GetSize() * elementSize);
183 PAssert(theArray != NULL, POutOfMemory);
184 memset(theArray, 0, GetSize() * elementSize);
185 }
186
187 allocatedDynamically = PTrue;
188 }
189
190
PAbstractArray(PINDEX elementSizeInBytes,const void * buffer,PINDEX bufferSizeInElements,PBoolean dynamicAllocation)191 PAbstractArray::PAbstractArray(PINDEX elementSizeInBytes,
192 const void *buffer,
193 PINDEX bufferSizeInElements,
194 PBoolean dynamicAllocation)
195 : PContainer(bufferSizeInElements)
196 {
197 elementSize = elementSizeInBytes;
198 PAssert(elementSize != 0, PInvalidParameter);
199
200 allocatedDynamically = dynamicAllocation;
201
202 if (GetSize() == 0)
203 theArray = NULL;
204 else if (dynamicAllocation) {
205 PINDEX sizebytes = elementSize*GetSize();
206 theArray = PAbstractArray_allocator.allocate(sizebytes);
207 PAssert(theArray != NULL, POutOfMemory);
208 memcpy(theArray, PAssertNULL(buffer), sizebytes);
209 }
210 else
211 theArray = (char *)buffer;
212 }
213
214
PAbstractArray(PContainerReference & reference,PINDEX elementSizeInBytes)215 PAbstractArray::PAbstractArray(PContainerReference & reference, PINDEX elementSizeInBytes)
216 : PContainer(reference)
217 , elementSize(elementSizeInBytes)
218 , theArray(NULL)
219 , allocatedDynamically(false)
220 {
221 }
222
223
DestroyContents()224 void PAbstractArray::DestroyContents()
225 {
226 if (theArray != NULL) {
227 if (allocatedDynamically)
228 PAbstractArray_allocator.deallocate(theArray, elementSize*GetSize());
229 theArray = NULL;
230 }
231 }
232
233
CopyContents(const PAbstractArray & array)234 void PAbstractArray::CopyContents(const PAbstractArray & array)
235 {
236 elementSize = array.elementSize;
237 theArray = array.theArray;
238 allocatedDynamically = array.allocatedDynamically;
239
240 if (reference->constObject)
241 MakeUnique();
242 }
243
244
CloneContents(const PAbstractArray * array)245 void PAbstractArray::CloneContents(const PAbstractArray * array)
246 {
247 elementSize = array->elementSize;
248 PINDEX sizebytes = elementSize*GetSize();
249 char * newArray = PAbstractArray_allocator.allocate(sizebytes);
250 if (newArray == NULL)
251 reference->size = 0;
252 else
253 memcpy(newArray, array->theArray, sizebytes);
254 theArray = newArray;
255 allocatedDynamically = PTrue;
256 }
257
258
PrintOn(ostream & strm) const259 void PAbstractArray::PrintOn(ostream & strm) const
260 {
261 char separator = strm.fill();
262 int width = (int)strm.width();
263 for (PINDEX i = 0; i < GetSize(); i++) {
264 if (i > 0 && separator != '\0')
265 strm << separator;
266 strm.width(width);
267 PrintElementOn(strm, i);
268 }
269 if (separator == '\n')
270 strm << '\n';
271 }
272
273
ReadFrom(istream & strm)274 void PAbstractArray::ReadFrom(istream & strm)
275 {
276 PINDEX i = 0;
277 while (strm.good()) {
278 ReadElementFrom(strm, i);
279 if (!strm.fail())
280 i++;
281 }
282 SetSize(i);
283 }
284
285
Compare(const PObject & obj) const286 PObject::Comparison PAbstractArray::Compare(const PObject & obj) const
287 {
288 PAssert(PIsDescendant(&obj, PAbstractArray), PInvalidCast);
289 const PAbstractArray & other = (const PAbstractArray &)obj;
290
291 char * otherArray = other.theArray;
292 if (theArray == otherArray)
293 return EqualTo;
294
295 if (elementSize < other.elementSize)
296 return LessThan;
297
298 if (elementSize > other.elementSize)
299 return GreaterThan;
300
301 PINDEX thisSize = GetSize();
302 PINDEX otherSize = other.GetSize();
303
304 if (thisSize < otherSize)
305 return LessThan;
306
307 if (thisSize > otherSize)
308 return GreaterThan;
309
310 if (thisSize == 0)
311 return EqualTo;
312
313 int retval = memcmp(theArray, otherArray, elementSize*thisSize);
314 if (retval < 0)
315 return LessThan;
316 if (retval > 0)
317 return GreaterThan;
318 return EqualTo;
319 }
320
321
SetSize(PINDEX newSize)322 PBoolean PAbstractArray::SetSize(PINDEX newSize)
323 {
324 return InternalSetSize(newSize, PFalse);
325 }
326
327
InternalSetSize(PINDEX newSize,PBoolean force)328 PBoolean PAbstractArray::InternalSetSize(PINDEX newSize, PBoolean force)
329 {
330 if (newSize < 0)
331 newSize = 0;
332
333 PINDEX newsizebytes = elementSize*newSize;
334 PINDEX oldsizebytes = elementSize*GetSize();
335
336 if (!force && (newsizebytes == oldsizebytes))
337 return PTrue;
338
339 char * newArray;
340
341 if (!IsUnique()) {
342
343 if (newsizebytes == 0)
344 newArray = NULL;
345 else {
346 if ((newArray = PAbstractArray_allocator.allocate(newsizebytes)) == NULL)
347 return PFalse;
348
349 allocatedDynamically = true;
350
351 if (theArray != NULL)
352 memcpy(newArray, theArray, PMIN(oldsizebytes, newsizebytes));
353 }
354
355 --reference->count;
356 reference = new PContainerReference(newSize);
357
358 } else {
359
360 if (theArray != NULL) {
361 if (newsizebytes == 0) {
362 if (allocatedDynamically)
363 PAbstractArray_allocator.deallocate(theArray, oldsizebytes);
364 newArray = NULL;
365 }
366 else {
367 if ((newArray = PAbstractArray_allocator.allocate(newsizebytes)) == NULL)
368 return false;
369 memcpy(newArray, theArray, PMIN(newsizebytes, oldsizebytes));
370 if (allocatedDynamically)
371 PAbstractArray_allocator.deallocate(theArray, oldsizebytes);
372 allocatedDynamically = true;
373 }
374 }
375 else if (newsizebytes != 0) {
376 if ((newArray = PAbstractArray_allocator.allocate(newsizebytes)) == NULL)
377 return PFalse;
378 }
379 else
380 newArray = NULL;
381
382 reference->size = newSize;
383 }
384
385 if (newsizebytes > oldsizebytes)
386 memset(newArray+oldsizebytes, 0, newsizebytes-oldsizebytes);
387
388 theArray = newArray;
389 return PTrue;
390 }
391
Attach(const void * buffer,PINDEX bufferSize)392 void PAbstractArray::Attach(const void *buffer, PINDEX bufferSize)
393 {
394 if (allocatedDynamically && theArray != NULL)
395 PAbstractArray_allocator.deallocate(theArray, elementSize*GetSize());
396
397 theArray = (char *)buffer;
398 reference->size = bufferSize;
399 allocatedDynamically = PFalse;
400 }
401
402
GetPointer(PINDEX minSize)403 void * PAbstractArray::GetPointer(PINDEX minSize)
404 {
405 PAssert(SetMinSize(minSize), POutOfMemory);
406 return theArray;
407 }
408
409
Concatenate(const PAbstractArray & array)410 PBoolean PAbstractArray::Concatenate(const PAbstractArray & array)
411 {
412 if (!allocatedDynamically || array.elementSize != elementSize)
413 return PFalse;
414
415 PINDEX oldLen = GetSize();
416 PINDEX addLen = array.GetSize();
417
418 if (!SetSize(oldLen + addLen))
419 return PFalse;
420
421 memcpy(theArray+oldLen*elementSize, array.theArray, addLen*elementSize);
422 return PTrue;
423 }
424
425
PrintElementOn(ostream &,PINDEX) const426 void PAbstractArray::PrintElementOn(ostream & /*stream*/, PINDEX /*index*/) const
427 {
428 }
429
430
ReadElementFrom(istream &,PINDEX)431 void PAbstractArray::ReadElementFrom(istream & /*stream*/, PINDEX /*index*/)
432 {
433 }
434
435
436 ///////////////////////////////////////////////////////////////////////////////
437
PrintOn(ostream & strm) const438 void PCharArray::PrintOn(ostream & strm) const
439 {
440 PINDEX width = (int)strm.width();
441 if (width > GetSize())
442 width -= GetSize();
443 else
444 width = 0;
445
446 PBoolean left = (strm.flags()&ios::adjustfield) == ios::left;
447 if (left)
448 strm.write(theArray, GetSize());
449
450 while (width-- > 0)
451 strm << (char)strm.fill();
452
453 if (!left)
454 strm.write(theArray, GetSize());
455 }
456
457
ReadFrom(istream & strm)458 void PCharArray::ReadFrom(istream &strm)
459 {
460 PINDEX size = 0;
461 SetSize(size+100);
462
463 while (strm.good()) {
464 strm >> theArray[size++];
465 if (size >= GetSize())
466 SetSize(size+100);
467 }
468
469 SetSize(size);
470 }
471
472
PrintOn(ostream & strm) const473 void PBYTEArray::PrintOn(ostream & strm) const
474 {
475 PINDEX line_width = (int)strm.width();
476 if (line_width == 0)
477 line_width = 16;
478 strm.width(0);
479
480 PINDEX indent = (int)strm.precision();
481
482 PINDEX val_width = ((strm.flags()&ios::basefield) == ios::hex) ? 2 : 3;
483
484 PINDEX i = 0;
485 while (i < GetSize()) {
486 if (i > 0)
487 strm << '\n';
488 PINDEX j;
489 for (j = 0; j < indent; j++)
490 strm << ' ';
491 for (j = 0; j < line_width; j++) {
492 if (j == line_width/2)
493 strm << ' ';
494 if (i+j < GetSize())
495 strm << setw(val_width) << (theArray[i+j]&0xff);
496 else {
497 PINDEX k;
498 for (k = 0; k < val_width; k++)
499 strm << ' ';
500 }
501 strm << ' ';
502 }
503 if ((strm.flags()&ios::floatfield) != ios::fixed) {
504 strm << " ";
505 for (j = 0; j < line_width; j++) {
506 if (i+j < GetSize()) {
507 unsigned val = theArray[i+j]&0xff;
508 if (isprint(val))
509 strm << (char)val;
510 else
511 strm << '.';
512 }
513 }
514 }
515 i += line_width;
516 }
517 }
518
519
ReadFrom(istream & strm)520 void PBYTEArray::ReadFrom(istream &strm)
521 {
522 PINDEX size = 0;
523 SetSize(size+100);
524
525 while (strm.good()) {
526 unsigned v;
527 strm >> v;
528 theArray[size] = (BYTE)v;
529 if (!strm.fail()) {
530 size++;
531 if (size >= GetSize())
532 SetSize(size+100);
533 }
534 }
535
536 SetSize(size);
537 }
538
539
540 ///////////////////////////////////////////////////////////////////////////////
541
PBitArray(PINDEX initialSize)542 PBitArray::PBitArray(PINDEX initialSize)
543 : PBYTEArray((initialSize+7)>>3)
544 {
545 }
546
547
PBitArray(const void * buffer,PINDEX length,PBoolean dynamic)548 PBitArray::PBitArray(const void * buffer,
549 PINDEX length,
550 PBoolean dynamic)
551 : PBYTEArray((const BYTE *)buffer, (length+7)>>3, dynamic)
552 {
553 }
554
555
Clone() const556 PObject * PBitArray::Clone() const
557 {
558 return new PBitArray(*this);
559 }
560
561
GetSize() const562 PINDEX PBitArray::GetSize() const
563 {
564 return PBYTEArray::GetSize()<<3;
565 }
566
567
SetSize(PINDEX newSize)568 PBoolean PBitArray::SetSize(PINDEX newSize)
569 {
570 return PBYTEArray::SetSize((newSize+7)>>3);
571 }
572
573
SetAt(PINDEX index,PBoolean val)574 PBoolean PBitArray::SetAt(PINDEX index, PBoolean val)
575 {
576 if (!SetMinSize(index+1))
577 return PFalse;
578
579 if (val)
580 theArray[index>>3] |= (1 << (index&7));
581 else
582 theArray[index>>3] &= ~(1 << (index&7));
583 return PTrue;
584 }
585
586
GetAt(PINDEX index) const587 PBoolean PBitArray::GetAt(PINDEX index) const
588 {
589 PASSERTINDEX(index);
590 if (index >= GetSize())
591 return PFalse;
592
593 return (theArray[index>>3]&(1 << (index&7))) != 0;
594 }
595
596
Attach(const void * buffer,PINDEX bufferSize)597 void PBitArray::Attach(const void * buffer, PINDEX bufferSize)
598 {
599 PBYTEArray::Attach((const BYTE *)buffer, (bufferSize+7)>>3);
600 }
601
602
GetPointer(PINDEX minSize)603 BYTE * PBitArray::GetPointer(PINDEX minSize)
604 {
605 return PBYTEArray::GetPointer((minSize+7)>>3);
606 }
607
608
Concatenate(const PBitArray & array)609 PBoolean PBitArray::Concatenate(const PBitArray & array)
610 {
611 return PAbstractArray::Concatenate(array);
612 }
613
614
615 ///////////////////////////////////////////////////////////////////////////////
616
PString(const char * cstr)617 PString::PString(const char * cstr)
618 : PCharArray(cstr != NULL ? (int)strlen(cstr)+1 : 1)
619 {
620 if (cstr != NULL)
621 memcpy(theArray, cstr, GetSize());
622 }
623
624
PString(const wchar_t * ustr)625 PString::PString(const wchar_t * ustr)
626 {
627 if (ustr == NULL)
628 SetSize(1);
629 else {
630 PINDEX len = 0;
631 while (ustr[len] != 0)
632 len++;
633 InternalFromUCS2(ustr, len);
634 }
635 }
636
637
PString(const char * cstr,PINDEX len)638 PString::PString(const char * cstr, PINDEX len)
639 : PCharArray(len+1)
640 {
641 if (len > 0)
642 memcpy(theArray, PAssertNULL(cstr), len);
643 }
644
645
PString(const wchar_t * ustr,PINDEX len)646 PString::PString(const wchar_t * ustr, PINDEX len)
647 : PCharArray(len+1)
648 {
649 InternalFromUCS2(ustr, len);
650 }
651
652
PString(const PWCharArray & ustr)653 PString::PString(const PWCharArray & ustr)
654 {
655 PINDEX size = ustr.GetSize();
656 if (size > 0 && ustr[size-1] == 0) // Stip off trailing NULL if present
657 size--;
658 InternalFromUCS2(ustr, size);
659 }
660
661
TranslateHex(char x)662 static int TranslateHex(char x)
663 {
664 if (x >= 'a')
665 return x - 'a' + 10;
666
667 if (x >= 'A')
668 return x - 'A' + '\x0a';
669
670 return x - '0';
671 }
672
673
674 static const unsigned char PStringEscapeCode[] = { 'a', 'b', 'f', 'n', 'r', 't', 'v' };
675 static const unsigned char PStringEscapeValue[] = { '\a', '\b', '\f', '\n', '\r', '\t', '\v' };
676
TranslateEscapes(const char * src,char * dst)677 static void TranslateEscapes(const char * src, char * dst)
678 {
679 bool hadLeadingQuote = *src == '"';
680 if (hadLeadingQuote)
681 src++;
682
683 while (*src != '\0') {
684 int c = *src++ & 0xff;
685 if (c == '"' && hadLeadingQuote) {
686 *dst = '\0'; // Trailing '"' and remaining string is ignored
687 break;
688 }
689
690 if (c == '\\') {
691 c = *src++ & 0xff;
692 for (PINDEX i = 0; i < PARRAYSIZE(PStringEscapeCode); i++) {
693 if (c == PStringEscapeCode[i])
694 c = PStringEscapeValue[i];
695 }
696
697 if (c == 'x' && isxdigit(*src & 0xff)) {
698 c = TranslateHex(*src++);
699 if (isxdigit(*src & 0xff))
700 c = (c << 4) + TranslateHex(*src++);
701 }
702 else if (c >= '0' && c <= '7') {
703 int count = c <= '3' ? 3 : 2;
704 src--;
705 c = 0;
706 do {
707 c = (c << 3) + *src++ - '0';
708 } while (--count > 0 && *src >= '0' && *src <= '7');
709 }
710 }
711
712 *dst++ = (char)c;
713 }
714 }
715
716
PString(ConversionType type,const char * str,...)717 PString::PString(ConversionType type, const char * str, ...)
718 {
719 switch (type) {
720 case Pascal :
721 if (*str != '\0') {
722 PINDEX len = *str & 0xff;
723 PAssert(SetSize(len+1), POutOfMemory);
724 memcpy(theArray, str+1, len);
725 }
726 break;
727
728 case Basic :
729 if (str[0] != '\0' && str[1] != '\0') {
730 PINDEX len = (str[0] & 0xff) | ((str[1] & 0xff) << 8);
731 PAssert(SetSize(len+1), POutOfMemory);
732 memcpy(theArray, str+2, len);
733 }
734 break;
735
736 case Literal :
737 PAssert(SetSize(strlen(str)+1), POutOfMemory);
738 TranslateEscapes(str, theArray);
739 PAssert(MakeMinimumSize(), POutOfMemory);
740 break;
741
742 case Printf : {
743 va_list args;
744 va_start(args, str);
745 vsprintf(str, args);
746 va_end(args);
747 break;
748 }
749
750 default :
751 PAssertAlways(PInvalidParameter);
752 }
753 }
754
755
p_unsigned2string(T value,T base,char * str)756 template <class T> char * p_unsigned2string(T value, T base, char * str)
757 {
758 if (value >= base)
759 str = p_unsigned2string<T>(value/base, base, str);
760 value %= base;
761 if (value < 10)
762 *str = (char)(value + '0');
763 else
764 *str = (char)(value + 'A'-10);
765 return str+1;
766 }
767
768
p_signed2string(T value,T base,char * str)769 template <class T> char * p_signed2string(T value, T base, char * str)
770 {
771 if (value >= 0)
772 return p_unsigned2string<T>(value, base, str);
773
774 *str = '-';
775 return p_unsigned2string<T>(-value, base, str+1);
776 }
777
778
PString(short n)779 PString::PString(short n)
780 : PCharArray(sizeof(short)*3+1)
781 {
782 p_signed2string<int>(n, 10, theArray);
783 MakeMinimumSize();
784 }
785
786
PString(unsigned short n)787 PString::PString(unsigned short n)
788 : PCharArray(sizeof(unsigned short)*3+1)
789 {
790 p_unsigned2string<unsigned int>(n, 10, theArray);
791 MakeMinimumSize();
792 }
793
794
PString(int n)795 PString::PString(int n)
796 : PCharArray(sizeof(int)*3+1)
797 {
798 p_signed2string<int>(n, 10, theArray);
799 MakeMinimumSize();
800 }
801
802
PString(unsigned int n)803 PString::PString(unsigned int n)
804 : PCharArray(sizeof(unsigned int)*3+1)
805 {
806 p_unsigned2string<unsigned int>(n, 10, theArray);
807 MakeMinimumSize();
808 }
809
810
PString(long n)811 PString::PString(long n)
812 : PCharArray(sizeof(long)*3+1)
813 {
814 p_signed2string<long>(n, 10, theArray);
815 MakeMinimumSize();
816 }
817
818
PString(unsigned long n)819 PString::PString(unsigned long n)
820 : PCharArray(sizeof(unsigned long)*3+1)
821 {
822 p_unsigned2string<unsigned long>(n, 10, theArray);
823 MakeMinimumSize();
824 }
825
826
PString(PInt64 n)827 PString::PString(PInt64 n)
828 : PCharArray(sizeof(PInt64)*3+1)
829 {
830 p_signed2string<PInt64>(n, 10, theArray);
831 MakeMinimumSize();
832 }
833
834
PString(PUInt64 n)835 PString::PString(PUInt64 n)
836 : PCharArray(sizeof(PUInt64)*3+1)
837 {
838 p_unsigned2string<PUInt64>(n, 10, theArray);
839 MakeMinimumSize();
840 }
841
842
PString(ConversionType type,long value,unsigned base)843 PString::PString(ConversionType type, long value, unsigned base)
844 : PCharArray(sizeof(long)*3+1)
845 {
846 PAssert(base >= 2 && base <= 36, PInvalidParameter);
847 switch (type) {
848 case Signed :
849 p_signed2string<long>(value, base, theArray);
850 break;
851
852 case Unsigned :
853 p_unsigned2string<unsigned long>(value, base, theArray);
854 break;
855
856 default :
857 PAssertAlways(PInvalidParameter);
858 }
859 MakeMinimumSize();
860 }
861
862
PString(ConversionType type,double value,unsigned places)863 PString::PString(ConversionType type, double value, unsigned places)
864 {
865 switch (type) {
866 case Decimal :
867 sprintf("%0.*f", (int)places, value);
868 break;
869
870 case Exponent :
871 sprintf("%0.*e", (int)places, value);
872 break;
873
874 default :
875 PAssertAlways(PInvalidParameter);
876 }
877 }
878
879
operator =(short n)880 PString & PString::operator=(short n)
881 {
882 SetMinSize(sizeof(short)*3+1);
883 p_signed2string<int>(n, 10, theArray);
884 MakeMinimumSize();
885 return *this;
886 }
887
888
operator =(unsigned short n)889 PString & PString::operator=(unsigned short n)
890 {
891 SetMinSize(sizeof(unsigned short)*3+1);
892 p_unsigned2string<unsigned int>(n, 10, theArray);
893 MakeMinimumSize();
894 return *this;
895 }
896
897
operator =(int n)898 PString & PString::operator=(int n)
899 {
900 SetMinSize(sizeof(int)*3+1);
901 p_signed2string<int>(n, 10, theArray);
902 MakeMinimumSize();
903 return *this;
904 }
905
906
operator =(unsigned int n)907 PString & PString::operator=(unsigned int n)
908 {
909 SetMinSize(sizeof(unsigned int)*3+1);
910 p_unsigned2string<unsigned int>(n, 10, theArray);
911 MakeMinimumSize();
912 return *this;
913 }
914
915
operator =(long n)916 PString & PString::operator=(long n)
917 {
918 SetMinSize(sizeof(long)*3+1);
919 p_signed2string<long>(n, 10, theArray);
920 MakeMinimumSize();
921 return *this;
922 }
923
924
operator =(unsigned long n)925 PString & PString::operator=(unsigned long n)
926 {
927 SetMinSize(sizeof(unsigned long)*3+1);
928 p_unsigned2string<unsigned long>(n, 10, theArray);
929 MakeMinimumSize();
930 return *this;
931 }
932
933
operator =(PInt64 n)934 PString & PString::operator=(PInt64 n)
935 {
936 SetMinSize(sizeof(PInt64)*3+1);
937 p_signed2string<PInt64>(n, 10, theArray);
938 MakeMinimumSize();
939 return *this;
940 }
941
942
operator =(PUInt64 n)943 PString & PString::operator=(PUInt64 n)
944 {
945 SetMinSize(sizeof(PUInt64)*3+1);
946 p_unsigned2string<PUInt64>(n, 10, theArray);
947 MakeMinimumSize();
948 return *this;
949 }
950
951
MakeEmpty()952 PString & PString::MakeEmpty()
953 {
954 SetSize(1);
955 *theArray = '\0';
956 return *this;
957 }
958
959
Clone() const960 PObject * PString::Clone() const
961 {
962 return new PString(*this);
963 }
964
965
PrintOn(ostream & strm) const966 void PString::PrintOn(ostream &strm) const
967 {
968 strm << theArray;
969 }
970
971
ReadFrom(istream & strm)972 void PString::ReadFrom(istream &strm)
973 {
974 PINDEX bump = 16;
975 PINDEX len = 0;
976 do {
977 if (!SetMinSize(len + (bump *= 2))) {
978 strm.setstate(ios::badbit);
979 return;
980 }
981
982 strm.clear();
983 strm.getline(theArray + len, GetSize() - len);
984 len += (PINDEX)strm.gcount();
985 } while (strm.fail() && !strm.eof());
986
987 if (len > 0 && !strm.eof())
988 --len; // Allow for extracted '\n'
989
990 if (len > 0 && theArray[len-1] == '\r')
991 theArray[len-1] = '\0';
992
993 PAssert(MakeMinimumSize(), POutOfMemory);
994 }
995
996
Compare(const PObject & obj) const997 PObject::Comparison PString::Compare(const PObject & obj) const
998 {
999 PAssert(PIsDescendant(&obj, PString), PInvalidCast);
1000 return InternalCompare(0, P_MAX_INDEX, ((const PString &)obj).theArray);
1001 }
1002
1003
HashFunction() const1004 PINDEX PString::HashFunction() const
1005 {
1006 // Hash function from "Data Structures and Algorithm Analysis in C++" by
1007 // Mark Allen Weiss, with limit of only executing over first 8 characters to
1008 // increase speed when dealing with large strings.
1009
1010 PINDEX hash = 0;
1011 for (PINDEX i = 0; i < 8 && theArray[i] != 0; i++)
1012 hash = (hash << 5) ^ tolower(theArray[i] & 0xff) ^ hash;
1013 return PABSINDEX(hash)%127;
1014 }
1015
1016
IsEmpty() const1017 PBoolean PString::IsEmpty() const
1018 {
1019 return (theArray == NULL) || (*theArray == '\0');
1020 }
1021
1022
SetSize(PINDEX newSize)1023 PBoolean PString::SetSize(PINDEX newSize)
1024 {
1025 if (newSize < 1)
1026 newSize = 1;
1027 if (!InternalSetSize(newSize, true))
1028 return false;
1029 theArray[newSize-1] = '\0';
1030 return true;
1031 }
1032
1033
MakeUnique()1034 PBoolean PString::MakeUnique()
1035 {
1036 if (IsUnique())
1037 return PTrue;
1038
1039 InternalSetSize(GetSize(), PTrue);
1040 return PFalse;
1041 }
1042
1043
operator +(const char * cstr) const1044 PString PString::operator+(const char * cstr) const
1045 {
1046 if (cstr == NULL)
1047 return *this;
1048
1049 PINDEX olen = GetLength();
1050 PINDEX alen = strlen(cstr)+1;
1051 PString str;
1052 str.SetSize(olen+alen);
1053 memmove(str.theArray, theArray, olen);
1054 memcpy(str.theArray+olen, cstr, alen);
1055 return str;
1056 }
1057
1058
operator +(char c) const1059 PString PString::operator+(char c) const
1060 {
1061 PINDEX olen = GetLength();
1062 PString str;
1063 str.SetSize(olen+2);
1064 memmove(str.theArray, theArray, olen);
1065 str.theArray[olen] = c;
1066 return str;
1067 }
1068
1069
operator +=(const char * cstr)1070 PString & PString::operator+=(const char * cstr)
1071 {
1072 if (cstr == NULL)
1073 return *this;
1074
1075 PINDEX olen = GetLength();
1076 PINDEX alen = strlen(cstr)+1;
1077 SetSize(olen+alen);
1078 memcpy(theArray+olen, cstr, alen);
1079 return *this;
1080 }
1081
1082
operator +=(char ch)1083 PString & PString::operator+=(char ch)
1084 {
1085 PINDEX olen = GetLength();
1086 SetSize(olen+2);
1087 theArray[olen] = ch;
1088 return *this;
1089 }
1090
1091
operator &(const char * cstr) const1092 PString PString::operator&(const char * cstr) const
1093 {
1094 if (cstr == NULL)
1095 return *this;
1096
1097 PINDEX alen = strlen(cstr)+1;
1098 if (alen == 1)
1099 return *this;
1100
1101 PINDEX olen = GetLength();
1102 PString str;
1103 PINDEX space = olen > 0 && theArray[olen-1]!=' ' && *cstr!=' ' ? 1 : 0;
1104 str.SetSize(olen+alen+space);
1105 memmove(str.theArray, theArray, olen);
1106 if (space != 0)
1107 str.theArray[olen] = ' ';
1108 memcpy(str.theArray+olen+space, cstr, alen);
1109 return str;
1110 }
1111
1112
operator &(char c) const1113 PString PString::operator&(char c) const
1114 {
1115 PINDEX olen = GetLength();
1116 PString str;
1117 PINDEX space = olen > 0 && theArray[olen-1] != ' ' && c != ' ' ? 1 : 0;
1118 str.SetSize(olen+2+space);
1119 memmove(str.theArray, theArray, olen);
1120 if (space != 0)
1121 str.theArray[olen] = ' ';
1122 str.theArray[olen+space] = c;
1123 return str;
1124 }
1125
1126
operator &=(const char * cstr)1127 PString & PString::operator&=(const char * cstr)
1128 {
1129 if (cstr == NULL)
1130 return *this;
1131
1132 PINDEX alen = strlen(cstr)+1;
1133 if (alen == 1)
1134 return *this;
1135 PINDEX olen = GetLength();
1136 PINDEX space = olen > 0 && theArray[olen-1]!=' ' && *cstr!=' ' ? 1 : 0;
1137 SetSize(olen+alen+space);
1138 if (space != 0)
1139 theArray[olen] = ' ';
1140 memcpy(theArray+olen+space, cstr, alen);
1141 return *this;
1142 }
1143
1144
operator &=(char ch)1145 PString & PString::operator&=(char ch)
1146 {
1147 PINDEX olen = GetLength();
1148 PINDEX space = olen > 0 && theArray[olen-1] != ' ' && ch != ' ' ? 1 : 0;
1149 SetSize(olen+2+space);
1150 if (space != 0)
1151 theArray[olen] = ' ';
1152 theArray[olen+space] = ch;
1153 return *this;
1154 }
1155
1156
Delete(PINDEX start,PINDEX len)1157 void PString::Delete(PINDEX start, PINDEX len)
1158 {
1159 if (start < 0 || len < 0)
1160 return;
1161
1162 MakeUnique();
1163
1164 register PINDEX slen = GetLength();
1165 if (start > slen)
1166 return;
1167
1168 if (len > slen - start)
1169 SetAt(start, '\0');
1170 else
1171 memmove(theArray+start, theArray+start+len, slen-start-len+1);
1172 MakeMinimumSize();
1173 }
1174
1175
operator ()(PINDEX start,PINDEX end) const1176 PString PString::operator()(PINDEX start, PINDEX end) const
1177 {
1178 if (end < 0 || start < 0 || end < start)
1179 return Empty();
1180
1181 register PINDEX len = GetLength();
1182 if (start > len)
1183 return Empty();
1184
1185 if (end >= len) {
1186 if (start == 0)
1187 return *this;
1188 end = len-1;
1189 }
1190 len = end - start + 1;
1191
1192 return PString(theArray+start, len);
1193 }
1194
1195
Left(PINDEX len) const1196 PString PString::Left(PINDEX len) const
1197 {
1198 if (len <= 0)
1199 return Empty();
1200
1201 if (len >= GetLength())
1202 return *this;
1203
1204 return PString(theArray, len);
1205 }
1206
1207
Right(PINDEX len) const1208 PString PString::Right(PINDEX len) const
1209 {
1210 if (len <= 0)
1211 return Empty();
1212
1213 PINDEX srclen = GetLength();
1214 if (len >= srclen)
1215 return *this;
1216
1217 return PString(theArray+srclen-len, len);
1218 }
1219
1220
Mid(PINDEX start,PINDEX len) const1221 PString PString::Mid(PINDEX start, PINDEX len) const
1222 {
1223 if (len <= 0 || start < 0)
1224 return Empty();
1225
1226 if (start+len < start) // Beware of wraparound
1227 return operator()(start, P_MAX_INDEX);
1228 else
1229 return operator()(start, start+len-1);
1230 }
1231
1232
operator *=(const char * cstr) const1233 bool PString::operator*=(const char * cstr) const
1234 {
1235 if (cstr == NULL)
1236 return IsEmpty() != PFalse;
1237
1238 const char * pstr = theArray;
1239 while (*pstr != '\0' && *cstr != '\0') {
1240 if (toupper(*pstr & 0xff) != toupper(*cstr & 0xff))
1241 return PFalse;
1242 pstr++;
1243 cstr++;
1244 }
1245 return *pstr == *cstr;
1246 }
1247
1248
NumCompare(const PString & str,PINDEX count,PINDEX offset) const1249 PObject::Comparison PString::NumCompare(const PString & str, PINDEX count, PINDEX offset) const
1250 {
1251 if (offset < 0 || count < 0)
1252 return LessThan;
1253 PINDEX len = str.GetLength();
1254 if (count > len)
1255 count = len;
1256 return InternalCompare(offset, count, str);
1257 }
1258
1259
NumCompare(const char * cstr,PINDEX count,PINDEX offset) const1260 PObject::Comparison PString::NumCompare(const char * cstr, PINDEX count, PINDEX offset) const
1261 {
1262 if (offset < 0 || count < 0)
1263 return LessThan;
1264 PINDEX len = ::strlen(cstr);
1265 if (count > len)
1266 count = len;
1267 return InternalCompare(offset, count, cstr);
1268 }
1269
1270
InternalCompare(PINDEX offset,char c) const1271 PObject::Comparison PString::InternalCompare(PINDEX offset, char c) const
1272 {
1273 if (offset < 0)
1274 return LessThan;
1275 const int ch = theArray[offset] & 0xff;
1276 if (ch < (c & 0xff))
1277 return LessThan;
1278 if (ch > (c & 0xff))
1279 return GreaterThan;
1280 return EqualTo;
1281 }
1282
1283
InternalCompare(PINDEX offset,PINDEX length,const char * cstr) const1284 PObject::Comparison PString::InternalCompare(
1285 PINDEX offset, PINDEX length, const char * cstr) const
1286 {
1287 if (offset < 0 || length < 0)
1288 return LessThan;
1289
1290 if (offset == 0 && theArray == cstr)
1291 return EqualTo;
1292
1293 if (offset < 0 || cstr == NULL)
1294 return IsEmpty() ? EqualTo : LessThan;
1295
1296 int retval;
1297 if (length == P_MAX_INDEX)
1298 retval = strcmp(theArray+offset, cstr);
1299 else
1300 retval = strncmp(theArray+offset, cstr, length);
1301
1302 if (retval < 0)
1303 return LessThan;
1304
1305 if (retval > 0)
1306 return GreaterThan;
1307
1308 return EqualTo;
1309 }
1310
1311
Find(char ch,PINDEX offset) const1312 PINDEX PString::Find(char ch, PINDEX offset) const
1313 {
1314 if (offset < 0)
1315 return P_MAX_INDEX;
1316
1317 register PINDEX len = GetLength();
1318 while (offset < len) {
1319 if (InternalCompare(offset, ch) == EqualTo)
1320 return offset;
1321 offset++;
1322 }
1323 return P_MAX_INDEX;
1324 }
1325
1326
Find(const char * cstr,PINDEX offset) const1327 PINDEX PString::Find(const char * cstr, PINDEX offset) const
1328 {
1329 if (cstr == NULL || *cstr == '\0' || offset < 0)
1330 return P_MAX_INDEX;
1331
1332 PINDEX len = GetLength();
1333 PINDEX clen = strlen(cstr);
1334 if (clen > len)
1335 return P_MAX_INDEX;
1336
1337 if (offset > len - clen)
1338 return P_MAX_INDEX;
1339
1340 if (len - clen < 10) {
1341 while (offset+clen <= len) {
1342 if (InternalCompare(offset, clen, cstr) == EqualTo)
1343 return offset;
1344 offset++;
1345 }
1346 return P_MAX_INDEX;
1347 }
1348
1349 int strSum = 0;
1350 int cstrSum = 0;
1351 for (PINDEX i = 0; i < clen; i++) {
1352 strSum += toupper(theArray[offset+i] & 0xff);
1353 cstrSum += toupper(cstr[i] & 0xff);
1354 }
1355
1356 // search for a matching substring
1357 while (offset+clen <= len) {
1358 if (strSum == cstrSum && InternalCompare(offset, clen, cstr) == EqualTo)
1359 return offset;
1360 strSum += toupper(theArray[offset+clen] & 0xff);
1361 strSum -= toupper(theArray[offset] & 0xff);
1362 offset++;
1363 }
1364
1365 return P_MAX_INDEX;
1366 }
1367
1368
FindLast(char ch,PINDEX offset) const1369 PINDEX PString::FindLast(char ch, PINDEX offset) const
1370 {
1371 PINDEX len = GetLength();
1372 if (len == 0 || offset < 0)
1373 return P_MAX_INDEX;
1374 if (offset >= len)
1375 offset = len-1;
1376
1377 while (InternalCompare(offset, ch) != EqualTo) {
1378 if (offset == 0)
1379 return P_MAX_INDEX;
1380 offset--;
1381 }
1382
1383 return offset;
1384 }
1385
1386
FindLast(const char * cstr,PINDEX offset) const1387 PINDEX PString::FindLast(const char * cstr, PINDEX offset) const
1388 {
1389 if (cstr == NULL || *cstr == '\0' || offset < 0)
1390 return P_MAX_INDEX;
1391
1392 PINDEX len = GetLength();
1393 PINDEX clen = strlen(cstr);
1394 if (clen > len)
1395 return P_MAX_INDEX;
1396
1397 if (offset > len - clen)
1398 offset = len - clen;
1399
1400 int strSum = 0;
1401 int cstrSum = 0;
1402 for (PINDEX i = 0; i < clen; i++) {
1403 strSum += toupper(theArray[offset+i] & 0xff);
1404 cstrSum += toupper(cstr[i] & 0xff);
1405 }
1406
1407 // search for a matching substring
1408 while (strSum != cstrSum || InternalCompare(offset, clen, cstr) != EqualTo) {
1409 if (offset == 0)
1410 return P_MAX_INDEX;
1411 --offset;
1412 strSum += toupper(theArray[offset] & 0xff);
1413 strSum -= toupper(theArray[offset+clen] & 0xff);
1414 }
1415
1416 return offset;
1417 }
1418
1419
FindOneOf(const char * cset,PINDEX offset) const1420 PINDEX PString::FindOneOf(const char * cset, PINDEX offset) const
1421 {
1422 if (cset == NULL || *cset == '\0' || offset < 0)
1423 return P_MAX_INDEX;
1424
1425 PINDEX len = GetLength();
1426 while (offset < len) {
1427 const char * p = cset;
1428 while (*p != '\0') {
1429 if (InternalCompare(offset, *p) == EqualTo)
1430 return offset;
1431 p++;
1432 }
1433 offset++;
1434 }
1435 return P_MAX_INDEX;
1436 }
1437
1438
FindSpan(const char * cset,PINDEX offset) const1439 PINDEX PString::FindSpan(const char * cset, PINDEX offset) const
1440 {
1441 if (cset == NULL || *cset == '\0' || offset < 0)
1442 return P_MAX_INDEX;
1443
1444 PINDEX len = GetLength();
1445 while (offset < len) {
1446 const char * p = cset;
1447 while (InternalCompare(offset, *p) != EqualTo) {
1448 if (*++p == '\0')
1449 return offset;
1450 }
1451 offset++;
1452 }
1453 return P_MAX_INDEX;
1454 }
1455
1456
FindRegEx(const PRegularExpression & regex,PINDEX offset) const1457 PINDEX PString::FindRegEx(const PRegularExpression & regex, PINDEX offset) const
1458 {
1459 if (offset < 0)
1460 return P_MAX_INDEX;
1461
1462 PINDEX pos = 0;
1463 PINDEX len = 0;
1464 if (FindRegEx(regex, pos, len, offset))
1465 return pos;
1466
1467 return P_MAX_INDEX;
1468 }
1469
1470
FindRegEx(const PRegularExpression & regex,PINDEX & pos,PINDEX & len,PINDEX offset,PINDEX maxPos) const1471 PBoolean PString::FindRegEx(const PRegularExpression & regex,
1472 PINDEX & pos,
1473 PINDEX & len,
1474 PINDEX offset,
1475 PINDEX maxPos) const
1476 {
1477 if (offset < 0 || maxPos < 0 || offset > GetLength())
1478 return false;
1479
1480 if (offset == GetLength()) {
1481 if (!regex.Execute("", pos, len, 0))
1482 return false;
1483 }
1484 else {
1485 if (!regex.Execute(&theArray[offset], pos, len, 0))
1486 return PFalse;
1487 }
1488
1489 pos += offset;
1490 if (pos+len > maxPos)
1491 return PFalse;
1492
1493 return PTrue;
1494 }
1495
MatchesRegEx(const PRegularExpression & regex) const1496 PBoolean PString::MatchesRegEx(const PRegularExpression & regex) const
1497 {
1498 PINDEX pos = 0;
1499 PINDEX len = 0;
1500
1501 if (!regex.Execute(theArray, pos, len, 0))
1502 return PFalse;
1503
1504 return (pos == 0) && (len == GetLength());
1505 }
1506
Replace(const PString & target,const PString & subs,PBoolean all,PINDEX offset)1507 void PString::Replace(const PString & target,
1508 const PString & subs,
1509 PBoolean all, PINDEX offset)
1510 {
1511 if (offset < 0)
1512 return;
1513
1514 MakeUnique();
1515
1516 PINDEX tlen = target.GetLength();
1517 PINDEX slen = subs.GetLength();
1518 do {
1519 PINDEX pos = Find(target, offset);
1520 if (pos == P_MAX_INDEX)
1521 return;
1522 Splice(subs, pos, tlen);
1523 offset = pos + slen;
1524 } while (all);
1525 }
1526
1527
Splice(const char * cstr,PINDEX pos,PINDEX len)1528 void PString::Splice(const char * cstr, PINDEX pos, PINDEX len)
1529 {
1530 if (len < 0 || pos < 0)
1531 return;
1532
1533 register PINDEX slen = GetLength();
1534 if (pos >= slen)
1535 operator+=(cstr);
1536 else {
1537 MakeUnique();
1538 if (len > slen-pos)
1539 len = slen-pos;
1540 PINDEX clen = cstr != NULL ? strlen(cstr) : 0;
1541 PINDEX newlen = slen-len+clen;
1542 if (clen > len)
1543 SetSize(newlen+1);
1544 if (pos+len < slen)
1545 memmove(theArray+pos+clen, theArray+pos+len, slen-pos-len+1);
1546 if (clen > 0)
1547 memcpy(theArray+pos, cstr, clen);
1548 theArray[newlen] = '\0';
1549 }
1550 }
1551
1552
1553 PStringArray
Tokenise(const char * separators,PBoolean onePerSeparator) const1554 PString::Tokenise(const char * separators, PBoolean onePerSeparator) const
1555 {
1556 PStringArray tokens;
1557
1558 if (separators == NULL || IsEmpty()) // No tokens
1559 return tokens;
1560
1561 PINDEX token = 0;
1562 PINDEX p1 = 0;
1563 PINDEX p2 = FindOneOf(separators);
1564
1565 if (p2 == 0) {
1566 if (onePerSeparator) { // first character is a token separator
1567 tokens[token] = Empty();
1568 token++; // make first string in array empty
1569 p1 = 1;
1570 p2 = FindOneOf(separators, 1);
1571 }
1572 else {
1573 do {
1574 p1 = p2 + 1;
1575 } while ((p2 = FindOneOf(separators, p1)) == p1);
1576 }
1577 }
1578
1579 while (p2 != P_MAX_INDEX) {
1580 if (p2 > p1)
1581 tokens[token] = operator()(p1, p2-1);
1582 else
1583 tokens[token] = Empty();
1584 token++;
1585
1586 // Get next separator. If not one token per separator then continue
1587 // around loop to skip over all the consecutive separators.
1588 do {
1589 p1 = p2 + 1;
1590 } while ((p2 = FindOneOf(separators, p1)) == p1 && !onePerSeparator);
1591 }
1592
1593 tokens[token] = operator()(p1, P_MAX_INDEX);
1594
1595 return tokens;
1596 }
1597
1598
Lines() const1599 PStringArray PString::Lines() const
1600 {
1601 PStringArray lines;
1602
1603 if (IsEmpty())
1604 return lines;
1605
1606 PINDEX line = 0;
1607 PINDEX p1 = 0;
1608 PINDEX p2;
1609 while ((p2 = FindOneOf("\r\n", p1)) != P_MAX_INDEX) {
1610 lines[line++] = operator()(p1, p2-1);
1611 p1 = p2 + 1;
1612 if (theArray[p2] == '\r' && theArray[p1] == '\n') // CR LF pair
1613 p1++;
1614 }
1615 if (p1 < GetLength())
1616 lines[line] = operator()(p1, P_MAX_INDEX);
1617 return lines;
1618 }
1619
operator +=(const PStringArray & v)1620 PStringArray & PStringArray::operator += (const PStringArray & v)
1621 {
1622 PINDEX i;
1623 for (i = 0; i < v.GetSize(); i++)
1624 AppendString(v[i]);
1625
1626 return *this;
1627 }
1628
LeftTrim() const1629 PString PString::LeftTrim() const
1630 {
1631 const char * lpos = theArray;
1632 while (isspace(*lpos & 0xff))
1633 lpos++;
1634 return PString(lpos);
1635 }
1636
1637
RightTrim() const1638 PString PString::RightTrim() const
1639 {
1640 char * rpos = theArray+GetLength()-1;
1641 if (!isspace(*rpos & 0xff))
1642 return *this;
1643
1644 while (isspace(*rpos & 0xff)) {
1645 if (rpos == theArray)
1646 return Empty();
1647 rpos--;
1648 }
1649
1650 // make Apple & Tornado gnu compiler happy
1651 PString retval(theArray, rpos - theArray + 1);
1652 return retval;
1653 }
1654
1655
Trim() const1656 PString PString::Trim() const
1657 {
1658 const char * lpos = theArray;
1659 while (isspace(*lpos & 0xff))
1660 lpos++;
1661 if (*lpos == '\0')
1662 return Empty();
1663
1664 const char * rpos = theArray+GetLength()-1;
1665 if (!isspace(*rpos & 0xff)) {
1666 if (lpos == theArray)
1667 return *this;
1668 else
1669 return PString(lpos);
1670 }
1671
1672 while (isspace(*rpos & 0xff))
1673 rpos--;
1674 return PString(lpos, rpos - lpos + 1);
1675 }
1676
1677
ToLower() const1678 PString PString::ToLower() const
1679 {
1680 PString newStr(theArray);
1681 for (char *cpos = newStr.theArray; *cpos != '\0'; cpos++) {
1682 if (isupper(*cpos & 0xff))
1683 *cpos = (char)tolower(*cpos & 0xff);
1684 }
1685 return newStr;
1686 }
1687
1688
ToUpper() const1689 PString PString::ToUpper() const
1690 {
1691 PString newStr(theArray);
1692 for (char *cpos = newStr.theArray; *cpos != '\0'; cpos++) {
1693 if (islower(*cpos & 0xff))
1694 *cpos = (char)toupper(*cpos & 0xff);
1695 }
1696 return newStr;
1697 }
1698
1699
AsInteger(unsigned base) const1700 long PString::AsInteger(unsigned base) const
1701 {
1702 PAssert(base >= 2 && base <= 36, PInvalidParameter);
1703 char * dummy;
1704 return strtol(theArray, &dummy, base);
1705 }
1706
1707
AsUnsigned(unsigned base) const1708 DWORD PString::AsUnsigned(unsigned base) const
1709 {
1710 PAssert(base >= 2 && base <= 36, PInvalidParameter);
1711 char * dummy;
1712 return strtoul(theArray, &dummy, base);
1713 }
1714
1715
AsReal() const1716 double PString::AsReal() const
1717 {
1718 #ifndef __HAS_NO_FLOAT
1719 char * dummy;
1720 return strtod(theArray, &dummy);
1721 #else
1722 return 0.0;
1723 #endif
1724 }
1725
1726
AsUCS2() const1727 PWCharArray PString::AsUCS2() const
1728 {
1729 PWCharArray ucs2(1); // Null terminated empty string
1730
1731 if (IsEmpty())
1732 return ucs2;
1733
1734 #ifdef P_HAS_G_CONVERT
1735
1736 gsize g_len = 0;
1737 gchar * g_ucs2 = g_convert(theArray, GetSize()-1, "UCS-2", "UTF-8", 0, &g_len, 0);
1738 if (g_ucs2 != NULL) {
1739 if (ucs2.SetSize(g_len+1))
1740 memcpy(ucs2.GetPointer(), g_ucs2, g_len*2);
1741 g_free(g_ucs2);
1742 return ucs2;
1743 }
1744
1745 PTRACE(1, "PTLib\tg_convert failed with error " << errno);
1746
1747 #elif defined(_WIN32)
1748
1749 // Note that MB_ERR_INVALID_CHARS is the only dwFlags value supported by Code page 65001 (UTF-8). Windows XP and later.
1750 PINDEX length = GetLength();
1751 PINDEX count = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, theArray, length, NULL, 0);
1752 if (count > 0 && ucs2.SetSize(count+1)) { // Allow for trailing NULL
1753 MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, theArray, length, ucs2.GetPointer(), ucs2.GetSize());
1754 return ucs2;
1755 }
1756
1757 #if PTRACING
1758 if (GetLastError() == ERROR_NO_UNICODE_TRANSLATION)
1759 PTRACE(1, "PTLib\tMultiByteToWideChar failed on non legal UTF-8 \"" << theArray << '"');
1760 else
1761 PTRACE(1, "PTLib\tMultiByteToWideChar failed with error " << ::GetLastError());
1762 #endif
1763
1764 #endif
1765
1766 if (ucs2.SetSize(GetSize())) { // Will be at least this big
1767 PINDEX count = 0;
1768 PINDEX i = 0;
1769 PINDEX length = GetSize(); // Include the trailing '\0'
1770 while (i < length) {
1771 int c = theArray[i];
1772 if ((c&0x80) == 0)
1773 ucs2[count++] = (BYTE)theArray[i++];
1774 else if ((c&0xe0) == 0xc0) {
1775 if (i < length-1)
1776 ucs2[count++] = (WORD)(((theArray[i ]&0x1f)<<6)|
1777 (theArray[i+1]&0x3f));
1778 i += 2;
1779 }
1780 else if ((c&0xf0) == 0xe0) {
1781 if (i < length-2)
1782 ucs2[count++] = (WORD)(((theArray[i ]&0x0f)<<12)|
1783 ((theArray[i+1]&0x3f)<< 6)|
1784 (theArray[i+2]&0x3f));
1785 i += 3;
1786 }
1787 else {
1788 if ((c&0xf8) == 0xf0)
1789 i += 4;
1790 else if ((c&0xfc) == 0xf8)
1791 i += 5;
1792 else
1793 i += 6;
1794 if (i <= length)
1795 ucs2[count++] = 0xffff;
1796 }
1797 }
1798
1799 ucs2.SetSize(count); // Final size
1800 }
1801
1802 return ucs2;
1803 }
1804
1805
InternalFromUCS2(const wchar_t * ptr,PINDEX len)1806 void PString::InternalFromUCS2(const wchar_t * ptr, PINDEX len)
1807 {
1808 if (ptr == NULL || len <= 0) {
1809 *this = Empty();
1810 return;
1811 }
1812
1813 #ifdef P_HAS_G_CONVERT
1814
1815 gsize g_len = 0;
1816 gchar * g_utf8 = g_convert(ptr, len, "UTF-8", "UCS-2", 0, &g_len, 0);
1817 if (g_utf8 == NULL) {
1818 *this = Empty();
1819 return;
1820 }
1821
1822 if (SetSize(&g_len))
1823 memcpy(theArray, g_char, g_len);
1824 g_free(g_utf8);
1825
1826 #elif defined(_WIN32)
1827
1828 PINDEX count = WideCharToMultiByte(CP_UTF8, 0, ptr, len, NULL, 0, NULL, NULL);
1829 if (SetSize(count+1))
1830 WideCharToMultiByte(CP_UTF8, 0, ptr, len, GetPointer(), GetSize(), NULL, NULL);
1831
1832 #else
1833
1834 PINDEX i;
1835 PINDEX count = 1;
1836 for (i = 0; i < len; i++) {
1837 if (ptr[i] < 0x80)
1838 count++;
1839 else if (ptr[i] < 0x800)
1840 count += 2;
1841 else
1842 count += 3;
1843 }
1844 if (SetSize(count)) {
1845 count = 0;
1846 for (i = 0; i < len; i++) {
1847 unsigned v = *ptr++;
1848 if (v < 0x80)
1849 theArray[count++] = (char)v;
1850 else if (v < 0x800) {
1851 theArray[count++] = (char)(0xc0+(v>>6));
1852 theArray[count++] = (char)(0x80+(v&0x3f));
1853 }
1854 else {
1855 theArray[count++] = (char)(0xd0+(v>>12));
1856 theArray[count++] = (char)(0x80+((v>>6)&0x3f));
1857 theArray[count++] = (char)(0x80+(v&0x3f));
1858 }
1859 }
1860 }
1861
1862 #endif
1863 }
1864
1865
ToPascal() const1866 PBYTEArray PString::ToPascal() const
1867 {
1868 PINDEX len = GetLength();
1869 PAssert(len < 256, "Cannot convert to PASCAL string");
1870 BYTE buf[256];
1871 buf[0] = (BYTE)len;
1872 memcpy(&buf[1], theArray, len);
1873 return PBYTEArray(buf, len+1);
1874 }
1875
1876
ToLiteral() const1877 PString PString::ToLiteral() const
1878 {
1879 PString str('"');
1880 for (char * p = theArray; *p != '\0'; p++) {
1881 if (*p == '"')
1882 str += "\\\"";
1883 else if (*p == '\\')
1884 str += "\\\\";
1885 else if (isprint(*p & 0xff))
1886 str += *p;
1887 else {
1888 PINDEX i;
1889 for (i = 0; i < PARRAYSIZE(PStringEscapeValue); i++) {
1890 if (*p == PStringEscapeValue[i]) {
1891 str += PString('\\') + (char)PStringEscapeCode[i];
1892 break;
1893 }
1894 }
1895 if (i >= PARRAYSIZE(PStringEscapeValue))
1896 str.sprintf("\\%03o", *p & 0xff);
1897 }
1898 }
1899 return str + '"';
1900 }
1901
1902
sprintf(const char * fmt,...)1903 PString & PString::sprintf(const char * fmt, ...)
1904 {
1905 va_list args;
1906 va_start(args, fmt);
1907 return vsprintf(fmt, args);
1908 }
1909
1910 #if defined(__GNUC__) || defined(__SUNPRO_CC)
1911 #define _vsnprintf vsnprintf
1912 #endif
1913
vsprintf(const char * fmt,va_list arg)1914 PString & PString::vsprintf(const char * fmt, va_list arg)
1915 {
1916 PINDEX len = theArray != NULL ? GetLength() : 0;
1917 #ifdef P_VXWORKS
1918 // The library provided with tornado 2.0 does not have the implementation
1919 // for vsnprintf
1920 // as workaround, just use a array size of 2000
1921 PAssert(SetSize(2000), POutOfMemory);
1922 ::vsprintf(theArray+len, fmt, arg);
1923 #else
1924 PINDEX providedSpace = 0;
1925 int requiredSpace;
1926 do {
1927 providedSpace += 1000;
1928 PAssert(SetSize(providedSpace+len), POutOfMemory);
1929 requiredSpace = _vsnprintf(theArray+len, providedSpace, fmt, arg);
1930 } while (requiredSpace == -1 || requiredSpace >= providedSpace);
1931 #endif // P_VXWORKS
1932
1933 PAssert(MakeMinimumSize(), POutOfMemory);
1934 return *this;
1935 }
1936
1937
psprintf(const char * fmt,...)1938 PString psprintf(const char * fmt, ...)
1939 {
1940 PString str;
1941 va_list args;
1942 va_start(args, fmt);
1943 return str.vsprintf(fmt, args);
1944 }
1945
1946
pvsprintf(const char * fmt,va_list arg)1947 PString pvsprintf(const char * fmt, va_list arg)
1948 {
1949 PString str;
1950 return str.vsprintf(fmt, arg);
1951 }
1952
1953
1954 ///////////////////////////////////////////////////////////////////////////////
1955
Clone() const1956 PObject * PCaselessString::Clone() const
1957 {
1958 return new PCaselessString(*this);
1959 }
1960
1961
InternalCompare(PINDEX offset,char c) const1962 PObject::Comparison PCaselessString::InternalCompare(PINDEX offset, char c) const
1963 {
1964 if (offset < 0)
1965 return LessThan;
1966
1967 int c1 = toupper(theArray[offset] & 0xff);
1968 int c2 = toupper(c & 0xff);
1969 if (c1 < c2)
1970 return LessThan;
1971 if (c1 > c2)
1972 return GreaterThan;
1973 return EqualTo;
1974 }
1975
1976
InternalCompare(PINDEX offset,PINDEX length,const char * cstr) const1977 PObject::Comparison PCaselessString::InternalCompare(
1978 PINDEX offset, PINDEX length, const char * cstr) const
1979 {
1980 if (offset < 0 || length < 0)
1981 return LessThan;
1982
1983 if (cstr == NULL)
1984 return IsEmpty() ? EqualTo : LessThan;
1985
1986 while (length-- > 0 && (theArray[offset] != '\0' || *cstr != '\0')) {
1987 Comparison c = PCaselessString::InternalCompare(offset++, *cstr++);
1988 if (c != EqualTo)
1989 return c;
1990 }
1991 return EqualTo;
1992 }
1993
1994
1995
1996 ///////////////////////////////////////////////////////////////////////////////
1997
Buffer(PStringStream & str,PINDEX size)1998 PStringStream::Buffer::Buffer(PStringStream & str, PINDEX size)
1999 : string(str),
2000 fixedBufferSize(size != 0)
2001 {
2002 string.SetMinSize(size > 0 ? size : 256);
2003 sync();
2004 }
2005
2006
overflow(int_type c)2007 streambuf::int_type PStringStream::Buffer::overflow(int_type c)
2008 {
2009 if (pptr() >= epptr()) {
2010 if (fixedBufferSize)
2011 return EOF;
2012
2013 int gpos = gptr() - eback();
2014 int ppos = pptr() - pbase();
2015 char * newptr = string.GetPointer(string.GetSize() + 32);
2016 setp(newptr, newptr + string.GetSize() - 1);
2017 pbump(ppos);
2018 setg(newptr, newptr + gpos, newptr + ppos);
2019 }
2020
2021 if (c != EOF) {
2022 *pptr() = (char)c;
2023 pbump(1);
2024 }
2025
2026 return 0;
2027 }
2028
2029
underflow()2030 streambuf::int_type PStringStream::Buffer::underflow()
2031 {
2032 return gptr() >= egptr() ? EOF : *gptr();
2033 }
2034
2035
sync()2036 int PStringStream::Buffer::sync()
2037 {
2038 char * base = string.GetPointer();
2039 PINDEX len = string.GetLength();
2040 setg(base, base, base + len);
2041 setp(base, base + string.GetSize() - 1);
2042 pbump(len);
2043 return 0;
2044 }
2045
seekoff(off_type off,ios_base::seekdir dir,ios_base::openmode mode)2046 streambuf::pos_type PStringStream::Buffer::seekoff(off_type off, ios_base::seekdir dir, ios_base::openmode mode)
2047 {
2048 int len = string.GetLength();
2049 int gpos = gptr() - eback();
2050 int ppos = pptr() - pbase();
2051 char * newgptr;
2052 char * newpptr;
2053 switch (dir) {
2054 case ios::beg :
2055 if (off < 0)
2056 newpptr = newgptr = eback();
2057 else if (off >= len)
2058 newpptr = newgptr = egptr();
2059 else
2060 newpptr = newgptr = eback()+off;
2061 break;
2062
2063 case ios::cur :
2064 if (off < -ppos)
2065 newpptr = eback();
2066 else if (off >= len-ppos)
2067 newpptr = epptr();
2068 else
2069 newpptr = pptr()+off;
2070 if (off < -gpos)
2071 newgptr = eback();
2072 else if (off >= len-gpos)
2073 newgptr = egptr();
2074 else
2075 newgptr = gptr()+off;
2076 break;
2077
2078 case ios::end :
2079 if (off < -len)
2080 newpptr = newgptr = eback();
2081 else if (off >= 0)
2082 newpptr = newgptr = egptr();
2083 else
2084 newpptr = newgptr = egptr()+off;
2085 break;
2086
2087 default:
2088 PAssertAlways2(string.GetClass(), PInvalidParameter);
2089 newgptr = gptr();
2090 newpptr = pptr();
2091 }
2092
2093 if ((mode&ios::in) != 0)
2094 setg(eback(), newgptr, egptr());
2095
2096 if ((mode&ios::out) != 0)
2097 setp(newpptr, epptr());
2098
2099 return gptr() - eback();
2100 }
2101
2102
seekpos(pos_type pos,ios_base::openmode mode)2103 PStringStream::Buffer::pos_type PStringStream::Buffer::seekpos(pos_type pos, ios_base::openmode mode)
2104 {
2105 return seekoff(pos, ios_base::beg, mode);
2106 }
2107
2108
2109 #ifdef _MSC_VER
2110 #pragma warning(disable:4355)
2111 #endif
2112
PStringStream()2113 PStringStream::PStringStream()
2114 : iostream(new PStringStream::Buffer(*this, 0))
2115 {
2116 }
2117
2118
PStringStream(PINDEX fixedBufferSize)2119 PStringStream::PStringStream(PINDEX fixedBufferSize)
2120 : iostream(new PStringStream::Buffer(*this, fixedBufferSize))
2121 {
2122 }
2123
2124
PStringStream(const PString & str)2125 PStringStream::PStringStream(const PString & str)
2126 : PString(str),
2127 iostream(new PStringStream::Buffer(*this, 0))
2128 {
2129 }
2130
2131
PStringStream(const char * cstr)2132 PStringStream::PStringStream(const char * cstr)
2133 : PString(cstr),
2134 iostream(new PStringStream::Buffer(*this, 0))
2135 {
2136 }
2137
2138 #ifdef _MSC_VER
2139 #pragma warning(default:4355)
2140 #endif
2141
2142
~PStringStream()2143 PStringStream::~PStringStream()
2144 {
2145 delete (PStringStream::Buffer *)rdbuf();
2146 #ifndef _WIN32
2147 init(NULL);
2148 #endif
2149 }
2150
2151
MakeEmpty()2152 PString & PStringStream::MakeEmpty()
2153 {
2154 memset(theArray, 0, GetSize());
2155 flush();
2156 return *this;
2157 }
2158
2159
AssignContents(const PContainer & cont)2160 void PStringStream::AssignContents(const PContainer & cont)
2161 {
2162 PString::AssignContents(cont);
2163 flush();
2164 }
2165
2166
2167 ///////////////////////////////////////////////////////////////////////////////
2168
PStringArray(PINDEX count,char const * const * strarr,PBoolean caseless)2169 PStringArray::PStringArray(PINDEX count, char const * const * strarr, PBoolean caseless)
2170 {
2171 if (count == 0)
2172 return;
2173
2174 if (PAssertNULL(strarr) == NULL)
2175 return;
2176
2177 if (count == P_MAX_INDEX) {
2178 count = 0;
2179 while (strarr[count] != NULL)
2180 count++;
2181 }
2182
2183 SetSize(count);
2184 for (PINDEX i = 0; i < count; i++) {
2185 PString * newString;
2186 if (caseless)
2187 newString = new PCaselessString(strarr[i]);
2188 else
2189 newString = new PString(strarr[i]);
2190 SetAt(i, newString);
2191 }
2192 }
2193
2194
PStringArray(const PString & str)2195 PStringArray::PStringArray(const PString & str)
2196 {
2197 SetSize(1);
2198 (*theArray)[0] = new PString(str);
2199 }
2200
2201
PStringArray(const PStringList & list)2202 PStringArray::PStringArray(const PStringList & list)
2203 {
2204 SetSize(list.GetSize());
2205 PINDEX count = 0;
2206 for (PStringList::const_iterator i = list.begin(); i != list.end(); i++)
2207 (*theArray)[count++] = new PString(*i);
2208 }
2209
2210
PStringArray(const PSortedStringList & list)2211 PStringArray::PStringArray(const PSortedStringList & list)
2212 {
2213 SetSize(list.GetSize());
2214 for (PINDEX i = 0; i < list.GetSize(); i++)
2215 (*theArray)[i] = new PString(list[i]);
2216 }
2217
2218
ReadFrom(istream & strm)2219 void PStringArray::ReadFrom(istream & strm)
2220 {
2221 while (strm.good()) {
2222 PString str;
2223 strm >> str;
2224 AppendString(str);
2225 }
2226 }
2227
2228
operator [](PINDEX index) const2229 PString PStringArray::operator[](PINDEX index) const
2230 {
2231 PASSERTINDEX(index);
2232 if (index < GetSize() && (*theArray)[index] != NULL)
2233 return *(PString *)(*theArray)[index];
2234 return PString::Empty();
2235 }
2236
2237
operator [](PINDEX index)2238 PString & PStringArray::operator[](PINDEX index)
2239 {
2240 PASSERTINDEX(index);
2241 PAssert(SetMinSize(index+1), POutOfMemory);
2242 if ((*theArray)[index] == NULL)
2243 (*theArray)[index] = new PString;
2244 return *(PString *)(*theArray)[index];
2245 }
2246
2247
strcpy_with_increment(char * & strPtr,const PString & str)2248 static void strcpy_with_increment(char * & strPtr, const PString & str)
2249 {
2250 PINDEX len = str.GetLength()+1;
2251 memcpy(strPtr, (const char *)str, len);
2252 strPtr += len;
2253 }
2254
ToCharArray(PCharArray * storage) const2255 char ** PStringArray::ToCharArray(PCharArray * storage) const
2256 {
2257 PINDEX i;
2258
2259 PINDEX mySize = GetSize();
2260 PINDEX storageSize = (mySize+1)*sizeof(char *);
2261 for (i = 0; i < mySize; i++)
2262 storageSize += (*this)[i].GetLength()+1;
2263
2264 char ** storagePtr;
2265 if (storage != NULL)
2266 storagePtr = (char **)storage->GetPointer(storageSize);
2267 else
2268 storagePtr = (char **)malloc(storageSize);
2269
2270 if (storagePtr == NULL)
2271 return NULL;
2272
2273 char * strPtr = (char *)&storagePtr[mySize+1];
2274
2275 for (i = 0; i < mySize; i++) {
2276 storagePtr[i] = strPtr;
2277 strcpy_with_increment(strPtr, (*this)[i]);
2278 }
2279
2280 storagePtr[i] = NULL;
2281
2282 return storagePtr;
2283 }
2284
2285
2286 ///////////////////////////////////////////////////////////////////////////////
2287
PStringList(PINDEX count,char const * const * strarr,PBoolean caseless)2288 PStringList::PStringList(PINDEX count, char const * const * strarr, PBoolean caseless)
2289 {
2290 if (count == 0)
2291 return;
2292
2293 if (PAssertNULL(strarr) == NULL)
2294 return;
2295
2296 for (PINDEX i = 0; i < count; i++) {
2297 PString * newString;
2298 if (caseless)
2299 newString = new PCaselessString(strarr[i]);
2300 else
2301 newString = new PString(strarr[i]);
2302 Append(newString);
2303 }
2304 }
2305
2306
PStringList(const PString & str)2307 PStringList::PStringList(const PString & str)
2308 {
2309 AppendString(str);
2310 }
2311
2312
PStringList(const PStringArray & array)2313 PStringList::PStringList(const PStringArray & array)
2314 {
2315 for (PINDEX i = 0; i < array.GetSize(); i++)
2316 AppendString(array[i]);
2317 }
2318
2319
PStringList(const PSortedStringList & list)2320 PStringList::PStringList(const PSortedStringList & list)
2321 {
2322 for (PINDEX i = 0; i < list.GetSize(); i++)
2323 AppendString(list[i]);
2324 }
2325
operator +=(const PStringList & v)2326 PStringList & PStringList::operator += (const PStringList & v)
2327 {
2328 for (PStringList::const_iterator i = v.begin(); i != v.end(); i++)
2329 AppendString(*i);
2330
2331 return *this;
2332 }
2333
2334
ReadFrom(istream & strm)2335 void PStringList::ReadFrom(istream & strm)
2336 {
2337 while (strm.good()) {
2338 PString str;
2339 strm >> str;
2340 AppendString(str);
2341 }
2342 }
2343
2344
2345 ///////////////////////////////////////////////////////////////////////////////
2346
PSortedStringList(PINDEX count,char const * const * strarr,PBoolean caseless)2347 PSortedStringList::PSortedStringList(PINDEX count,
2348 char const * const * strarr,
2349 PBoolean caseless)
2350 {
2351 if (count == 0)
2352 return;
2353
2354 if (PAssertNULL(strarr) == NULL)
2355 return;
2356
2357 for (PINDEX i = 0; i < count; i++) {
2358 PString * newString;
2359 if (caseless)
2360 newString = new PCaselessString(strarr[i]);
2361 else
2362 newString = new PString(strarr[i]);
2363 Append(newString);
2364 }
2365 }
2366
2367
PSortedStringList(const PString & str)2368 PSortedStringList::PSortedStringList(const PString & str)
2369 {
2370 AppendString(str);
2371 }
2372
2373
PSortedStringList(const PStringArray & array)2374 PSortedStringList::PSortedStringList(const PStringArray & array)
2375 {
2376 for (PINDEX i = 0; i < array.GetSize(); i++)
2377 AppendString(array[i]);
2378 }
2379
2380
PSortedStringList(const PStringList & list)2381 PSortedStringList::PSortedStringList(const PStringList & list)
2382 {
2383 for (PStringList::const_iterator i = list.begin(); i != list.end(); i++)
2384 AppendString(*i);
2385 }
2386
2387
2388
ReadFrom(istream & strm)2389 void PSortedStringList::ReadFrom(istream & strm)
2390 {
2391 while (strm.good()) {
2392 PString str;
2393 strm >> str;
2394 AppendString(str);
2395 }
2396 }
2397
2398
GetNextStringsIndex(const PString & str) const2399 PINDEX PSortedStringList::GetNextStringsIndex(const PString & str) const
2400 {
2401 PINDEX len = str.GetLength();
2402 Element * lastElement;
2403 PINDEX lastIndex = InternalStringSelect(str, len, info->root, lastElement);
2404
2405 if (lastIndex != 0) {
2406 Element * prev;
2407 while ((prev = info->Predecessor(lastElement)) != &info->nil &&
2408 ((PString *)prev->data)->NumCompare(str, len) >= EqualTo) {
2409 lastElement = prev;
2410 lastIndex--;
2411 }
2412 }
2413
2414 return lastIndex;
2415 }
2416
2417
InternalStringSelect(const char * str,PINDEX len,Element * thisElement,Element * & lastElement) const2418 PINDEX PSortedStringList::InternalStringSelect(const char * str,
2419 PINDEX len,
2420 Element * thisElement,
2421 Element * & lastElement) const
2422 {
2423 if (thisElement == &info->nil)
2424 return 0;
2425
2426 switch (((PString *)thisElement->data)->NumCompare(str, len)) {
2427 case PObject::LessThan :
2428 {
2429 PINDEX index = InternalStringSelect(str, len, thisElement->right, lastElement);
2430 return thisElement->left->subTreeSize + index + 1;
2431 }
2432
2433 case PObject::GreaterThan :
2434 return InternalStringSelect(str, len, thisElement->left, lastElement);
2435
2436 default :
2437 lastElement = thisElement;
2438 return thisElement->left->subTreeSize;
2439 }
2440 }
2441
2442
2443 ///////////////////////////////////////////////////////////////////////////////
2444
PStringSet(PINDEX count,char const * const * strarr,PBoolean caseless)2445 PStringSet::PStringSet(PINDEX count, char const * const * strarr, PBoolean caseless)
2446 : BaseClass(true)
2447 {
2448 if (count == 0)
2449 return;
2450
2451 if (PAssertNULL(strarr) == NULL)
2452 return;
2453
2454 for (PINDEX i = 0; i < count; i++) {
2455 if (caseless)
2456 Include(PCaselessString(strarr[i]));
2457 else
2458 Include(PString(strarr[i]));
2459 }
2460 }
2461
2462
PStringSet(const PString & str)2463 PStringSet::PStringSet(const PString & str)
2464 : BaseClass(true)
2465 {
2466 Include(str);
2467 }
2468
2469
PStringSet(const PStringArray & strArray)2470 PStringSet::PStringSet(const PStringArray & strArray)
2471 : BaseClass(true)
2472 {
2473 for (PINDEX i = 0; i < strArray.GetSize(); ++i)
2474 Include(strArray[i]);
2475 }
2476
2477
PStringSet(const PStringList & strList)2478 PStringSet::PStringSet(const PStringList & strList)
2479 : BaseClass(true)
2480 {
2481 for (PStringList::const_iterator it = strList.begin(); it != strList.end(); ++it)
2482 Include(*it);
2483 }
2484
2485
ReadFrom(istream & strm)2486 void PStringSet::ReadFrom(istream & strm)
2487 {
2488 while (strm.good()) {
2489 PString str;
2490 strm >> str;
2491 Include(str);
2492 }
2493 }
2494
2495
2496 ///////////////////////////////////////////////////////////////////////////////
2497
POrdinalToString(PINDEX count,const Initialiser * init)2498 POrdinalToString::POrdinalToString(PINDEX count, const Initialiser * init)
2499 {
2500 while (count-- > 0) {
2501 SetAt(init->key, init->value);
2502 init++;
2503 }
2504 }
2505
2506
ReadFrom(istream & strm)2507 void POrdinalToString::ReadFrom(istream & strm)
2508 {
2509 while (strm.good()) {
2510 POrdinalKey key;
2511 char equal;
2512 PString str;
2513 strm >> key >> ws >> equal >> str;
2514 if (equal != '=')
2515 SetAt(key, PString::Empty());
2516 else
2517 SetAt(key, str.Mid(equal+1));
2518 }
2519 }
2520
2521
2522 ///////////////////////////////////////////////////////////////////////////////
2523
PStringToOrdinal(PINDEX count,const Initialiser * init,PBoolean caseless)2524 PStringToOrdinal::PStringToOrdinal(PINDEX count,
2525 const Initialiser * init,
2526 PBoolean caseless)
2527 {
2528 while (count-- > 0) {
2529 if (caseless)
2530 SetAt(PCaselessString(init->key), init->value);
2531 else
2532 SetAt(init->key, init->value);
2533 init++;
2534 }
2535 }
2536
2537
ReadFrom(istream & strm)2538 void PStringToOrdinal::ReadFrom(istream & strm)
2539 {
2540 while (strm.good()) {
2541 PString str;
2542 strm >> str;
2543 PINDEX equal = str.FindLast('=');
2544 if (equal == P_MAX_INDEX)
2545 SetAt(str, 0);
2546 else
2547 SetAt(str.Left(equal), str.Mid(equal+1).AsInteger());
2548 }
2549 }
2550
2551
2552 ///////////////////////////////////////////////////////////////////////////////
2553
PStringToString(PINDEX count,const Initialiser * init,PBoolean caselessKeys,PBoolean caselessValues)2554 PStringToString::PStringToString(PINDEX count,
2555 const Initialiser * init,
2556 PBoolean caselessKeys,
2557 PBoolean caselessValues)
2558 {
2559 while (count-- > 0) {
2560 if (caselessValues)
2561 if (caselessKeys)
2562 SetAt(PCaselessString(init->key), PCaselessString(init->value));
2563 else
2564 SetAt(init->key, PCaselessString(init->value));
2565 else
2566 if (caselessKeys)
2567 SetAt(PCaselessString(init->key), init->value);
2568 else
2569 SetAt(init->key, init->value);
2570 init++;
2571 }
2572 }
2573
2574
ReadFrom(istream & strm)2575 void PStringToString::ReadFrom(istream & strm)
2576 {
2577 while (strm.good()) {
2578 PString str;
2579 strm >> str;
2580 PINDEX equal = str.Find('=');
2581 if (equal == P_MAX_INDEX)
2582 SetAt(str, PString::Empty());
2583 else
2584 SetAt(str.Left(equal), str.Mid(equal+1));
2585 }
2586 }
2587
2588
ToCharArray(bool withEqualSign,PCharArray * storage) const2589 char ** PStringToString::ToCharArray(bool withEqualSign, PCharArray * storage) const
2590 {
2591 PINDEX i;
2592
2593 PINDEX mySize = GetSize();
2594 PINDEX numPointers = mySize*(withEqualSign ? 1 : 2) + 1;
2595 PINDEX storageSize = numPointers*sizeof(char *);
2596 for (i = 0; i < mySize; i++)
2597 storageSize += GetKeyAt(i).GetLength()+1 + GetDataAt(i).GetLength()+1;
2598
2599 char ** storagePtr;
2600 if (storage != NULL)
2601 storagePtr = (char **)storage->GetPointer(storageSize);
2602 else
2603 storagePtr = (char **)malloc(storageSize);
2604
2605 if (storagePtr == NULL)
2606 return NULL;
2607
2608 char * strPtr = (char *)&storagePtr[numPointers];
2609 PINDEX strIndex = 0;
2610
2611 for (i = 0; i < mySize; i++) {
2612 storagePtr[strIndex++] = strPtr;
2613 if (withEqualSign)
2614 strcpy_with_increment(strPtr, GetKeyAt(i) + '=' + GetDataAt(i));
2615 else {
2616 strcpy_with_increment(strPtr, GetKeyAt(i));
2617 storagePtr[strIndex++] = strPtr;
2618 strcpy_with_increment(strPtr, GetDataAt(i));
2619 }
2620 }
2621
2622 storagePtr[strIndex] = NULL;
2623
2624 return storagePtr;
2625 }
2626
2627
2628 ///////////////////////////////////////////////////////////////////////////////
2629
2630
GetString(const PCaselessString & key,const char * dflt) const2631 PString PStringOptions::GetString(const PCaselessString & key, const char * dflt) const
2632 {
2633 PString * str = PStringToString::GetAt(key);
2634 return str != NULL ? *str : PString(dflt);
2635 }
2636
2637
GetBoolean(const PCaselessString & key,bool dflt) const2638 bool PStringOptions::GetBoolean(const PCaselessString & key, bool dflt) const
2639 {
2640 PString * str = PStringToString::GetAt(key);
2641 if (str == NULL)
2642 return dflt;
2643
2644 if (str->IsEmpty() || str->AsUnsigned() != 0)
2645 return true;
2646
2647 PCaselessString test(*str);
2648 return test.NumCompare("t") == EqualTo || test.NumCompare("y") == EqualTo;
2649 }
2650
2651
GetInteger(const PCaselessString & key,long dflt) const2652 long PStringOptions::GetInteger(const PCaselessString & key, long dflt) const
2653 {
2654 PString * str = PStringToString::GetAt(key);
2655 return str != NULL ? str->AsInteger() : dflt;
2656 }
2657
2658
SetInteger(const PCaselessString & key,long value)2659 void PStringOptions::SetInteger(const PCaselessString & key, long value)
2660 {
2661 PStringToString::SetAt(key, PString(PString::Signed, value));
2662 }
2663
2664
GetReal(const PCaselessString & key,double dflt) const2665 double PStringOptions::GetReal(const PCaselessString & key, double dflt) const
2666 {
2667 PString * str = PStringToString::GetAt(key);
2668 return str != NULL ? str->AsReal() : dflt;
2669 }
2670
2671
SetReal(const PCaselessString & key,double value,int decimals)2672 void PStringOptions::SetReal(const PCaselessString & key, double value, int decimals)
2673 {
2674 PStringToString::SetAt(key, PString(decimals < 0 ? PString::Exponent : PString::Decimal, value, decimals));
2675 }
2676
2677
2678 ///////////////////////////////////////////////////////////////////////////////
2679
PRegularExpression()2680 PRegularExpression::PRegularExpression()
2681 {
2682 lastError = NotCompiled;
2683 expression = NULL;
2684 flagsSaved = IgnoreCase;
2685 }
2686
2687
PRegularExpression(const PString & pattern,int flags)2688 PRegularExpression::PRegularExpression(const PString & pattern, int flags)
2689 {
2690 expression = NULL;
2691 bool b = Compile(pattern, flags);
2692 PAssert(b, PString("regular expression compile failed : " + GetErrorText()));
2693 }
2694
2695
PRegularExpression(const char * pattern,int flags)2696 PRegularExpression::PRegularExpression(const char * pattern, int flags)
2697 {
2698 expression = NULL;
2699 bool b = Compile(pattern, flags);
2700 PAssert(b, PString("regular expression compile failed : " + GetErrorText()));
2701 }
2702
PRegularExpression(const PRegularExpression & from)2703 PRegularExpression::PRegularExpression(const PRegularExpression & from)
2704 {
2705 expression = NULL;
2706 bool b = Compile(from.patternSaved, from.flagsSaved);
2707 PAssert(b, PString("regular expression compile failed : " + GetErrorText()));
2708 }
2709
operator =(const PRegularExpression & from)2710 PRegularExpression & PRegularExpression::operator =(const PRegularExpression & from)
2711 {
2712 if (expression != from.expression) {
2713 if (expression != NULL && expression != from.expression) {
2714 regfree(regexpression());
2715 delete regexpression();
2716 }
2717 expression = NULL;
2718 }
2719 Compile(from.patternSaved, from.flagsSaved);
2720 return *this;
2721 }
2722
~PRegularExpression()2723 PRegularExpression::~PRegularExpression()
2724 {
2725 if (expression != NULL) {
2726 regfree(regexpression());
2727 delete regexpression();
2728 }
2729 }
2730
2731
PrintOn(ostream & strm) const2732 void PRegularExpression::PrintOn(ostream &strm) const
2733 {
2734 strm << patternSaved;
2735 }
2736
2737
GetErrorCode() const2738 PRegularExpression::ErrorCodes PRegularExpression::GetErrorCode() const
2739 {
2740 return lastError;
2741 }
2742
2743
GetErrorText() const2744 PString PRegularExpression::GetErrorText() const
2745 {
2746 PString str;
2747 regerror(lastError, regexpression(), str.GetPointer(256), 256);
2748 return str;
2749 }
2750
2751
Compile(const PString & pattern,int flags)2752 PBoolean PRegularExpression::Compile(const PString & pattern, int flags)
2753 {
2754 return Compile((const char *)pattern, flags);
2755 }
2756
2757
Compile(const char * pattern,int flags)2758 PBoolean PRegularExpression::Compile(const char * pattern, int flags)
2759 {
2760 patternSaved = pattern;
2761 flagsSaved = flags;
2762
2763 if (expression != NULL) {
2764 regfree(regexpression());
2765 delete regexpression();
2766 expression = NULL;
2767 }
2768 if (pattern == NULL || *pattern == '\0')
2769 lastError = BadPattern;
2770 else {
2771 expression = new regex_t;
2772 lastError = (ErrorCodes)regcomp(regexpression(), pattern, flags);
2773 }
2774 return lastError == NoError;
2775 }
2776
2777
Execute(const PString & str,PINDEX & start,int flags) const2778 PBoolean PRegularExpression::Execute(const PString & str, PINDEX & start, int flags) const
2779 {
2780 PINDEX dummy;
2781 return Execute((const char *)str, start, dummy, flags);
2782 }
2783
2784
Execute(const PString & str,PINDEX & start,PINDEX & len,int flags) const2785 PBoolean PRegularExpression::Execute(const PString & str, PINDEX & start, PINDEX & len, int flags) const
2786 {
2787 return Execute((const char *)str, start, len, flags);
2788 }
2789
2790
Execute(const char * cstr,PINDEX & start,int flags) const2791 PBoolean PRegularExpression::Execute(const char * cstr, PINDEX & start, int flags) const
2792 {
2793 PINDEX dummy;
2794 return Execute(cstr, start, dummy, flags);
2795 }
2796
2797
Execute(const char * cstr,PINDEX & start,PINDEX & len,int flags) const2798 PBoolean PRegularExpression::Execute(const char * cstr, PINDEX & start, PINDEX & len, int flags) const
2799 {
2800 if (expression == NULL) {
2801 lastError = NotCompiled;
2802 return PFalse;
2803 }
2804
2805 if (lastError != NoError && lastError != NoMatch)
2806 return PFalse;
2807
2808 regmatch_t match;
2809
2810 lastError = (ErrorCodes)regexec(regexpression(), cstr, 1, &match, flags);
2811 if (lastError != NoError)
2812 return PFalse;
2813
2814 start = match.rm_so;
2815 len = match.rm_eo - start;
2816 return PTrue;
2817 }
2818
2819
Execute(const PString & str,PIntArray & starts,int flags) const2820 PBoolean PRegularExpression::Execute(const PString & str, PIntArray & starts, int flags) const
2821 {
2822 PIntArray dummy;
2823 return Execute((const char *)str, starts, dummy, flags);
2824 }
2825
2826
Execute(const PString & str,PIntArray & starts,PIntArray & ends,int flags) const2827 PBoolean PRegularExpression::Execute(const PString & str,
2828 PIntArray & starts,
2829 PIntArray & ends,
2830 int flags) const
2831 {
2832 return Execute((const char *)str, starts, ends, flags);
2833 }
2834
2835
Execute(const char * cstr,PIntArray & starts,int flags) const2836 PBoolean PRegularExpression::Execute(const char * cstr, PIntArray & starts, int flags) const
2837 {
2838 PIntArray dummy;
2839 return Execute(cstr, starts, dummy, flags);
2840 }
2841
2842
Execute(const char * cstr,PIntArray & starts,PIntArray & ends,int flags) const2843 PBoolean PRegularExpression::Execute(const char * cstr,
2844 PIntArray & starts,
2845 PIntArray & ends,
2846 int flags) const
2847 {
2848 if (expression == NULL) {
2849 lastError = NotCompiled;
2850 return PFalse;
2851 }
2852
2853 PINDEX count = starts.GetSize();
2854 if (count == 0) {
2855 starts.SetSize(1);
2856 count = 1;
2857 }
2858 ends.SetSize(count);
2859
2860 regmatch_t * matches = new regmatch_t[count];
2861
2862 lastError = (ErrorCodes)::regexec(regexpression(), cstr, count, matches, flags);
2863 if (lastError == NoError) {
2864 for (PINDEX i = 0; i < count; i++) {
2865 starts[i] = matches[i].rm_so;
2866 ends[i] = matches[i].rm_eo;
2867 }
2868 }
2869
2870 delete [] matches;
2871
2872 return lastError == NoError;
2873 }
2874
2875
Execute(const char * cstr,PStringArray & substring,int flags) const2876 PBoolean PRegularExpression::Execute(const char * cstr, PStringArray & substring, int flags) const
2877 {
2878 if (expression == NULL) {
2879 lastError = NotCompiled;
2880 return PFalse;
2881 }
2882
2883 PINDEX count = substring.GetSize();
2884 if (count == 0) {
2885 substring.SetSize(1);
2886 count = 1;
2887 }
2888
2889 regmatch_t * matches = new regmatch_t[count];
2890
2891 lastError = (ErrorCodes)::regexec(regexpression(), cstr, count, matches, flags);
2892 if (lastError == NoError) {
2893 for (PINDEX i = 0; i < count; i++)
2894 substring[i] = PString(cstr+matches[i].rm_so, matches[i].rm_eo-matches[i].rm_so);
2895 }
2896
2897 delete [] matches;
2898
2899 return lastError == NoError;
2900 }
2901
2902
EscapeString(const PString & str)2903 PString PRegularExpression::EscapeString(const PString & str)
2904 {
2905 PString translated = str;
2906
2907 PINDEX lastPos = 0;
2908 PINDEX nextPos;
2909 while ((nextPos = translated.FindOneOf("\\^$+?*.[]()|{}", lastPos)) != P_MAX_INDEX) {
2910 translated.Splice("\\", nextPos);
2911 lastPos = nextPos+2;
2912 }
2913
2914 return translated;
2915 }
2916
2917
2918 // End Of File ///////////////////////////////////////////////////////////////
2919