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