Fixed typo flagged as warning by gcc 3.5-20040704
[pwlib.git] / src / ptlib / common / contain.cxx
blobdafadab907204bf0e01c6afb2fe45f5f1aaae45a
1 /*
2 * contain.cxx
4 * Container Classes
6 * Portable Windows Library
8 * Copyright (c) 1993-1998 Equivalence Pty. Ltd.
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/
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.
20 * The Original Code is Portable Windows Library.
22 * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
24 * Portions are Copyright (C) 1993 Free Software Foundation, Inc.
25 * All Rights Reserved.
27 * Contributor(s): ______________________________________.
29 * $Log$
30 * Revision 1.164 2004/07/19 13:55:00 csoutheren
31 * Fixed typo flagged as warning by gcc 3.5-20040704
33 * Revision 1.163 2004/07/11 07:56:36 csoutheren
34 * Applied jumbo VxWorks patch, thanks to Eize Slange
36 * Revision 1.162 2004/06/08 01:31:07 csoutheren
37 * Make the test sense correct for the init(NULL)
39 * Revision 1.161 2004/06/08 01:29:00 csoutheren
40 * Removed memory leak on VS.net caused by unobvious iostream allocation
42 * Revision 1.160 2004/05/28 23:59:23 csoutheren
43 * Added guards for negative offsets and lengths in various PString functions
45 * Revision 1.159 2004/05/13 14:52:32 csoutheren
46 * Allow PString::IsEmpty to return TRUE when theArray is NULL
48 * Revision 1.158 2004/05/04 11:10:37 rjongbloed
49 * Fixed usage of MakeEmpty() with PStringStream.
51 * Revision 1.157 2004/04/24 06:27:56 rjongbloed
52 * Fixed GCC 3.4.0 warnings about PAssertNULL and improved recoverability on
53 * NULL pointer usage in various bits of code.
55 * Revision 1.156 2004/04/18 04:33:37 rjongbloed
56 * Changed all operators that return BOOL to return standard type bool. This is primarily
57 * for improved compatibility with std STL usage removing many warnings.
59 * Revision 1.155 2004/04/15 03:50:35 csoutheren
60 * Fixed problem with MakeUnique
62 * Revision 1.154 2004/04/14 23:34:52 csoutheren
63 * Added plugin for data access
65 * Revision 1.153 2004/04/12 00:36:05 csoutheren
66 * Added new class PAtomicInteger and added Windows implementation
68 * Revision 1.152 2004/04/11 06:15:36 csoutheren
69 * Modified to use Atomic_word if available
71 * Revision 1.151 2004/04/11 02:55:18 csoutheren
72 * Added PCriticalSection for Windows
73 * Added compile time option for PContainer to use critical sections to provide thread safety under some circumstances
75 * Revision 1.150 2004/04/09 06:38:11 rjongbloed
76 * Fixed compatibility with STL based streams, eg as used by VC++2003
78 * Revision 1.149 2004/04/03 23:53:09 csoutheren
79 * Added various changes to improce compatibility with the Sun Forte compiler
80 * Thanks to Brian Cameron
81 * Added detection of readdir_r version
83 * Revision 1.148 2004/04/03 08:22:21 csoutheren
84 * Remove pseudo-RTTI and replaced with real RTTI
86 * Revision 1.147 2004/04/03 06:54:25 rjongbloed
87 * Many and various changes to support new Visual C++ 2003
89 * Revision 1.146 2004/03/20 04:20:34 rjongbloed
90 * Fixed some VxWorks port issues especially underrrun memory access in
91 * the PString::FindLast function,, thanks Eize Slange
93 * Revision 1.145 2004/02/23 00:44:38 csoutheren
94 * A completely different, other regex include hack to avoid requiring
95 * the sources when using a header-file only environment
97 * Revision 1.144 2004/02/23 00:26:05 csoutheren
98 * Finally, a generic and elegant fix for the regex include hacks. Thanks to Roger Hardiman
100 * Revision 1.143 2004/02/15 03:04:52 rjongbloed
101 * Fixed problem with PSortedList nil variable and assignment between instances,
102 * pointed out by Ben Lear.
104 * Revision 1.142 2004/02/11 05:09:14 csoutheren
105 * Fixed problems with regex libraries on Solaris, and with host OS numbering
106 * being a quoted string rather than a number. Thanks to Chad Attermann
107 * Fixed problems SSL detection problems thanks to Michal Zygmuntowicz
109 * Revision 1.141 2004/02/08 11:13:20 rjongbloed
110 * Fixed crash in heavily loaded multi-threaded systems using simultaneous sorted
111 * lists, Thanks Federico Pinna, Fabrizio Ammollo and the gang at Reitek S.p.A.
113 * Revision 1.140 2004/01/17 17:28:25 csoutheren
114 * Changed PString::Empty to be inline in header file
116 * Revision 1.139 2004/01/16 13:24:38 csoutheren
117 * Changed PString::Empty to be thread-safe
118 * Fixed PContainer::SetMinSize and PAbstractArray::SetSize, thanks to 123@call2ua.com
119 * Fixed PString::FindLast, thanks to Andreas Sikkema
121 * Revision 1.138 2003/12/14 01:12:00 csoutheren
122 * Added return value to PRegularExpression::operator = again (Doh!)
124 * Revision 1.137 2003/12/13 23:08:46 csoutheren
125 * Changed PRegularExpression to allow a copy constructor and operator =
127 * Revision 1.136 2003/12/04 13:12:41 csoutheren
128 * Fixed error in PRegularExpression that caused double delete when incorrect regular expression used
130 * Revision 1.135 2003/09/17 09:02:13 csoutheren
131 * Removed memory leak detection code
133 * Revision 1.134 2003/07/28 18:44:01 dsandras
134 * Make use of the libc regex on Linux.
136 * Revision 1.133 2003/05/14 00:48:33 rjongbloed
137 * Added constructor to string lists/arrays etc that takes a single PString.
138 * Fixed bug in doing a MakeUnique on a container, it would lose the
139 * DisallowDeleteObjects flag.
141 * Revision 1.132 2003/04/28 09:14:14 robertj
142 * Fixed bad sign extension problem in PBYTEArray output
144 * Revision 1.131 2003/04/15 07:08:37 robertj
145 * Changed read and write from streams for base array classes so operates in
146 * the same way for both PIntArray and PArray<int> etc
148 * Revision 1.130 2003/03/31 01:24:23 robertj
149 * Added ReadFrom functions for standard container classes such as
150 * PIntArray and PStringList etc
152 * Revision 1.129 2003/03/05 08:48:32 robertj
153 * Added PStringArray::ToCharAray() function at suggestion of Ravelli Rossano
155 * Revision 1.128 2003/02/02 23:29:34 robertj
156 * Fixed bug in RightTrim() (lost off last non blank char), tnanks Joerg Schoemer
158 * Revision 1.127 2002/12/16 08:10:35 robertj
159 * Fixed infinite loop when converting an illegal (incomplete) UTF-8 string
160 * to UCS-2, thanks Chih-Wei Huang
162 * Revision 1.126 2002/11/26 01:08:33 robertj
163 * Fixed problem when using pre-initialised PStringStream greater than 255
164 * bytes, would truncate and lose trailing null. Reported by Thien Nguyen
166 * Revision 1.125 2002/11/12 09:18:03 robertj
167 * Added PString::NumCompare() as functional equivalent of strncmp().
168 * Added PSortedStringList::GetNextStringsIndex() to do searches of binary
169 * tree on partal strings.
171 * Revision 1.124 2002/11/01 05:10:01 robertj
172 * Fixed bug in UTF-8 to UCS-2 conversion, not compiler portable!
174 * Revision 1.123 2002/10/31 07:33:59 robertj
175 * Changed UTF-8 to UCS-2 conversion function to not include trailing null.
177 * Revision 1.122 2002/10/31 05:55:55 robertj
178 * Now comprehensively stated that a PString is ALWAYS an 8 bit string as
179 * there are far too many inheerent assumptions every to make it 16 bit.
180 * Added UTF-8/UCS-2 conversion functions to PString.
182 * Revision 1.121 2002/10/10 04:43:44 robertj
183 * VxWorks port, thanks Martijn Roest
185 * Revision 1.120 2002/08/14 00:43:40 robertj
186 * Added ability to have fixed maximum length PStringStream's so does not do
187 * unwanted malloc()'s while outputing data.
189 * Revision 1.119 2002/08/06 08:51:36 robertj
190 * Added missing va_end, thanks Klaus Kaempf
192 * Revision 1.118 2002/06/27 06:59:34 robertj
193 * Removed memory leak display of static that is not really a leak.
195 * Revision 1.117 2002/06/25 02:24:24 robertj
196 * Improved assertion system to allow C++ class name to be displayed if
197 * desired, especially relevant to container classes.
199 * Revision 1.116 2002/06/24 06:18:36 robertj
200 * Fixed bug when getting extra space at start of outputing PBaseArray.
201 * Added ability to not include ASCII in PbaseArray output using ios::fixed.
203 * Revision 1.115 2002/06/19 04:04:30 robertj
204 * Fixed bug in setting/getting bits from PBitArray, could exceed array bounds.
206 * Revision 1.114 2002/06/17 09:16:18 robertj
207 * Fixed strange deadlock woth gcc 3.0.2, thanks Artis Kugevics
209 * Revision 1.113 2002/06/14 13:22:52 robertj
210 * Added PBitArray class.
212 * Revision 1.112 2002/06/05 12:29:15 craigs
213 * Changes for gcc 3.1
215 * Revision 1.111 2002/04/09 02:30:18 robertj
216 * Removed GCC3 variable as __GNUC__ can be used instead, thanks jason Spence
218 * Revision 1.110 2002/02/15 04:30:39 robertj
219 * Added PString::Empty() to return the primordial empty string. Saves on a
220 * couple of memory allocations for every empty string ever used.
221 * Changed every place where a const char * is used with PString so that a
222 * NULL pointer is treated like an empty string instead of asserting.
224 * Revision 1.109 2002/01/26 23:57:45 craigs
225 * Changed for GCC 3.0 compatibility, thanks to manty@manty.net
227 * Revision 1.108 2002/01/22 01:03:57 craigs
228 * Added operator += and operator + functions to PStringArray and PStringList
229 * Added AppendString operator to PStringArray
231 * Revision 1.107 2001/10/30 00:20:12 robertj
232 * Fixed broken signed number conversion from previous change.
234 * Revision 1.106 2001/10/18 00:35:08 robertj
235 * Fixed problem with Tokenise() includeing empty string at beginning when
236 * not in onePerSeparator mode and a separator starts the string.
238 * Revision 1.105 2001/10/17 05:09:22 robertj
239 * Added contructors and assigmnent operators so integer types can be
240 * automatically converted to strings.
242 * Revision 1.104 2001/08/11 15:01:44 rogerh
243 * Add Mac OS Carbon changes from John Woods <jfw@jfwhome.funhouse.com>
245 * Revision 1.103 2001/05/08 23:27:12 robertj
246 * Fixed, yet again, case significance in hash function.
248 * Revision 1.102 2001/04/26 03:45:19 robertj
249 * Changed PString has function again, use a prime number for modulus.
251 * Revision 1.101 2001/04/24 02:39:18 robertj
252 * Fixed problem with new string hash function giving negative indexes.
254 * Revision 1.100 2001/04/23 03:13:16 robertj
255 * Changed PString hash function to better one, thanks Patrick Koorevaar
257 * Revision 1.99 2001/04/18 04:10:15 robertj
258 * Removed hash function for caseless strings as confuses mixed dictionaries.
260 * Revision 1.98 2001/04/18 01:20:59 robertj
261 * Fixed problem with hash function for short strings, thanks Patrick Koorevaar.
262 * Also fixed hash function for caseless strings.
264 * Revision 1.97 2001/03/14 01:51:01 craigs
265 * Changed to handle CRLF at end of PString::ReadFrom as well as LF
267 * Revision 1.96 2001/02/26 07:50:18 robertj
268 * Updated regular expression parser to latest version from Henry Spencer.
270 * Revision 1.95 2001/02/21 03:38:37 robertj
271 * Added ability to copy between various string lists/arrays etc during construction.
273 * Revision 1.94 2001/02/14 22:21:08 robertj
274 * Fixed compiler error on some versions of GCC, thanks Klaus Kaempf.
276 * Revision 1.93 2001/02/14 06:50:01 robertj
277 * Fixed bug in doing ::flush on a PStringStream, did not set pointers correctly.
279 * Revision 1.92 2001/02/13 04:39:08 robertj
280 * Fixed problem with operator= in container classes. Some containers will
281 * break unless the copy is virtual (eg PStringStream's buffer pointers) so
282 * needed to add a new AssignContents() function to all containers.
284 * Revision 1.91 2000/12/29 07:36:57 craigs
285 * Fixed problem with Tokenise function returning NULL entries in array
287 * Revision 1.90 2000/10/12 05:14:41 robertj
288 * Fixed crash caused by previous change, didn;t work if in constructor.
290 * Revision 1.89 2000/10/09 23:43:58 robertj
291 * Fixed GNU C++ compatibility on last change.
293 * Revision 1.88 2000/10/09 23:37:17 robertj
294 * Improved PString sprintf functions so no longer limited to 1000 characters, thanks Yuriy Ershov.
296 * Revision 1.87 2000/06/26 11:17:20 robertj
297 * Nucleus++ port (incomplete).
299 * Revision 1.86 2000/04/07 06:29:46 rogerh
300 * Add a short term workaround for an Internal Compiler Error on MAC OS X when
301 * returning certain types of PString. Submitted by Kevin Packard.
303 * Revision 1.85 2000/02/05 22:36:09 craigs
304 * Fixed problem caused by last modification
306 * Revision 1.84 2000/02/04 19:34:26 craigs
307 * Fixed problem with changing size of referenced objects
309 * Revision 1.83 2000/01/25 14:05:35 robertj
310 * Added optimisation to array comparisons if referencing same array.
312 * Revision 1.82 1999/08/18 01:45:13 robertj
313 * Added concatenation function to "base type" arrays.
315 * Revision 1.81 1999/08/17 03:46:40 robertj
316 * Fixed usage of inlines in optimised version.
318 * Revision 1.80 1999/08/12 12:12:47 robertj
319 * GCC 2.95 compatibility.
321 * Revision 1.79 1999/05/28 14:01:53 robertj
322 * Added initialisers to string containers (list, sorted list and set).
324 * Revision 1.78 1999/04/18 09:36:31 robertj
325 * Get date grammar build.
327 * Revision 1.77 1999/04/16 14:38:37 craigs
328 * Changes to make getdate.y compile under Linux
330 * Revision 1.76 1998/10/28 00:58:40 robertj
331 * Changed PStringStream so flush or endl does not clear the string output, this now
332 * just sets the string to minimum size.
334 * Revision 1.75 1998/10/13 14:06:18 robertj
335 * Complete rewrite of memory leak detection code.
337 * Revision 1.74 1998/09/23 06:21:54 robertj
338 * Added open source copyright license.
340 * Revision 1.73 1998/09/22 02:42:39 robertj
341 * Fixed problem treating unsigned integer as signed in PString contructor.
343 * Revision 1.72 1998/09/15 08:26:42 robertj
344 * Fixed a number of warnings at maximum optimisation.
346 * Revision 1.71 1998/09/14 12:36:29 robertj
347 * Fixed bug causing memory leak due to uninitialised member variable for dynamic allocation of arrays.
349 * Revision 1.70 1998/08/21 05:24:07 robertj
350 * Added hex dump capability to base array types.
351 * Added ability to have base arrays of static memory blocks.
353 * Revision 1.69 1998/03/17 10:13:23 robertj
354 * Fixed bug in Trim() should do all white space not just the space character.
356 * Revision 1.68 1998/01/26 00:37:48 robertj
357 * Fixed PString & operator putting space in if right hand side is empty string, it shouldn't..
358 * Added Execute() functions to PRegularExpression that take PINDEX references instead of PIntArrays.
359 * Added FindRegEx function to PString that returns position and length.
361 * Revision 1.67 1997/12/11 13:32:49 robertj
362 * Added AsUnsigned() function to convert string to DWORD.
364 * Revision 1.66 1997/07/08 13:14:41 robertj
365 * Fixed bug where freeing null pointer.
367 * Revision 1.65 1997/06/08 04:48:04 robertj
368 * Added regular expressions.
370 * Revision 1.64 1997/03/02 03:41:42 robertj
371 * Fixed bug in not being able to construct a zero length PStringArray.
373 * Revision 1.63 1996/10/08 13:13:25 robertj
374 * Added operator += and &= for char so no implicit PString construction.
376 * Revision 1.62 1996/09/14 12:45:57 robertj
377 * Fixed bug in PString::Splice() function, no end of string put in.
379 * Revision 1.61 1996/08/22 13:21:55 robertj
380 * Fixed major bug in FindLast(), could scan all of memory in negative direction.
382 * Revision 1.60 1996/08/08 10:08:45 robertj
383 * Directory structure changes for common files.
385 * Revision 1.59 1996/05/26 03:46:27 robertj
386 * Compatibility to GNU 2.7.x
388 * Revision 1.58 1996/05/15 10:17:02 robertj
389 * Fixed idiotic bug in string compare, caseless version always matched.
391 * Revision 1.57 1996/05/09 12:17:10 robertj
392 * Fixed incorrect use of memcmp/strcmp return value.
393 * Added assertion when finding empty string.
395 * Revision 1.56 1996/04/14 02:52:39 robertj
396 * Fixed bug in PString::FindLast(), never found sub-strings.
398 * Revision 1.55 1996/03/31 08:58:49 robertj
399 * Fixed hash function for strings to work for caseless strings.
401 * Revision 1.54 1996/03/16 04:56:59 robertj
402 * Fixed bug in PStringStream assignment oeprator getting pointers wrong.
404 * Revision 1.53 1996/03/02 03:20:11 robertj
405 * Fixed bug in PString::Find() not finding substring if exactly same as string.
407 * Revision 1.52 1996/02/22 10:23:54 robertj
408 * Fixed buf in *= operator only comparing up to shortest string.
409 * Fixed bug in & operator for if left string is empty.
411 * Revision 1.51 1996/02/19 13:34:53 robertj
412 * Removed PCaselessString hash function to fix dictionary match failure.
413 * Fixed *= operator yet again.
415 * Revision 1.50 1996/02/08 12:20:44 robertj
416 * Added new operators to PString for case insensitive compare and spaced concatenate.
417 * Fixed bug in Find() not finding case insensitive substrings.
419 * Revision 1.49 1996/02/03 11:08:51 robertj
420 * Changed memcpy to memove to guarentee string operations will work correctly
421 * when moving overlapping strings around eg in PString::Splice().
423 * Revision 1.48 1996/01/28 14:12:22 robertj
424 * Fixed bug in Tokenise() for first token empty and PINDEX unsigned.
426 * Revision 1.47 1996/01/28 02:53:40 robertj
427 * Added assert into all Compare functions to assure comparison between compatible objects.
428 * Fixed bug in Find() function, subset sum calculation added one to many bytes.
430 * Revision 1.46 1996/01/24 14:43:19 robertj
431 * Added initialisers to string dictionaries.
433 * Revision 1.45 1996/01/23 13:17:38 robertj
434 * Added Replace() function to strings.
435 * String searching algorithm rewrite.
437 * Revision 1.44 1996/01/02 12:51:05 robertj
438 * Mac OS compatibility changes.
439 * Removed requirement that PArray elements have parameterless constructor..
441 * Revision 1.43 1995/10/14 15:07:42 robertj
442 * Changed arrays to not break references, but strings still need to.
444 * Revision 1.42 1995/06/17 00:46:20 robertj
445 * Added flag for PStringArray constructor to create caseless strings.
446 * Fixed bug in arrays when size set to zero.
448 * Revision 1.41 1995/06/04 12:39:59 robertj
449 * Made char * array all const in PStringArray constructor.
451 * Revision 1.40 1995/04/25 11:29:38 robertj
452 * Fixed Borland compiler warnings.
454 * Revision 1.39 1995/04/02 09:27:27 robertj
455 * Added "balloon" help.
457 * Revision 1.38 1995/03/12 04:46:02 robertj
458 * Fixed use of PCaselessString as dictionary key.
460 * Revision 1.37 1995/01/15 04:56:28 robertj
461 * Fixed PStringStream for correct pointer calculations in output.
463 * Revision 1.36 1995/01/10 11:44:13 robertj
464 * Removed PString parameter in stdarg function for GNU C++ compatibility.
466 * Revision 1.35 1995/01/09 12:32:56 robertj
467 * Removed unnecesary return value from I/O functions.
468 * Changed function names due to Mac port.
470 * Revision 1.34 1995/01/04 10:57:08 robertj
471 * Changed for HPUX and GNU2.6.x
473 * Revision 1.33 1995/01/03 09:39:08 robertj
474 * Put standard malloc style memory allocation etc into memory check system.
476 * Revision 1.32 1994/12/13 11:50:56 robertj
477 * Added MakeUnique() function to all container classes.
479 * Revision 1.31 1994/12/12 13:13:17 robertj
480 * Fixed bugs in PString mods just made.
482 * Revision 1.30 1994/12/12 10:16:27 robertj
483 * Restructuring and documentation of container classes.
484 * Renaming of some macros for declaring container classes.
485 * Added some extra functionality to PString.
486 * Added start to 2 byte characters in PString.
487 * Fixed incorrect overrides in PCaselessString.
489 * Revision 1.29 1994/12/05 11:19:36 robertj
490 * Moved SetMinSize from PAbstractArray to PContainer.
492 * Revision 1.28 1994/11/28 12:37:29 robertj
493 * Added dummy parameter to container classes.
495 * Revision 1.27 1994/10/30 11:50:44 robertj
496 * Split into Object classes and Container classes.
497 * Changed mechanism for doing notification callback functions.
499 * Revision 1.26 1994/10/23 03:43:07 robertj
500 * Changed PBaseArray so can have zero elements in it.
501 * Added Printf style constructor to PString.
503 * Revision 1.25 1994/09/25 10:49:44 robertj
504 * Added empty functions for serialisation.
506 * Revision 1.24 1994/08/21 23:43:02 robertj
507 * Added object serialisation classes.
508 * Changed parameter before variable argument list to NOT be a reference.
510 * Revision 1.23 1994/08/04 12:57:10 robertj
511 * Rewrite of memory check code.
513 * Revision 1.22 1994/08/01 03:40:28 robertj
514 * Fixed PString() constructor from integer
516 * Revision 1.21 1994/07/27 05:58:07 robertj
517 * Synchronisation.
519 * Revision 1.20 1994/07/25 03:38:38 robertj
520 * Added more memory tests.
522 * Revision 1.19 1994/07/17 10:46:06 robertj
523 * Added number conversions to PString.
525 * Revision 1.18 1994/06/25 11:55:15 robertj
526 * Unix version synchronisation.
528 * Revision 1.17 1994/04/20 12:17:44 robertj
529 * assert changes
531 * Revision 1.16 1994/04/11 12:08:37 robertj
532 * Fixed bug in memory leak hash table hash function, cant have negative numbers.
534 * Revision 1.15 1994/04/03 08:34:18 robertj
535 * Added help and focus functionality.
537 * Revision 1.14 1994/04/01 14:01:11 robertj
538 * Streams and stuff.
540 * Revision 1.13 1994/03/07 07:47:00 robertj
541 * Major upgrade
543 * Revision 1.12 1994/01/15 03:14:22 robertj
544 * Mac portability problems.
546 * Revision 1.11 1994/01/03 04:42:23 robertj
547 * Mass changes to common container classes and interactors etc etc etc.
549 * Revision 1.10 1993/12/31 06:53:02 robertj
550 * Made inlines optional for debugging purposes.
552 * Revision 1.9 1993/12/24 04:20:52 robertj
553 * Mac CFront port.
555 * Revision 1.8 1993/12/16 00:51:46 robertj
556 * Made some container functions const.
558 * Revision 1.7 1993/12/15 21:10:10 robertj
559 * Fixed reference system used by container classes.
560 * Plugged memory leaks in PList and PSortedList.
562 * Revision 1.6 1993/12/14 18:44:56 robertj
563 * Added RemoveAll() function to collections.
564 * Fixed bug in list processing when being destroyed (removes the item being
565 * deleted from the list before deleting it).
566 * Changed GetIndex() so does not assert if entry not in collection.
568 * Revision 1.5 1993/12/04 05:22:38 robertj
569 * Added more string functions.
571 * Revision 1.4 1993/09/27 16:35:25 robertj
572 * Fixed bugs in sorted list.
573 * Fixed compatibility problem with sprintf return value (SVR4).
574 * Change function for making string array to a constructor.
576 * Revision 1.3 1993/08/27 18:17:47 robertj
577 * Fixed bugs in PAbstractSortedList (including some formatting).
579 * Revision 1.2 1993/08/21 01:50:33 robertj
580 * Made Clone() function optional, default will assert if called.
582 * Revision 1.8 1993/08/01 14:05:27 robertj
583 * Added const to ToLower() and ToUpper() in the PString class.
585 * Revision 1.7 1993/07/16 14:40:55 robertj
586 * Added PString constructor for individual characters.
587 * Added string to C style literal format.
589 * Revision 1.6 1993/07/15 05:02:57 robertj
590 * Removed redundant word in PString enum for string types.
592 * Revision 1.5 1993/07/15 04:29:39 robertj
593 * Added new constructor to convert from other string formats.
594 * Fixed sprintf variable parameter list bug.
596 * Revision 1.4 1993/07/14 12:41:52 robertj
597 * Fixed comment leader.
599 * Revision 1.3 1993/07/14 02:06:34 robertj
600 * Fixed header comment for RCS.
603 #include <ptlib.h>
604 #include <ctype.h>
607 #ifdef __NUCLEUS_PLUS__
608 extern "C" int vsprintf(char *, const char *, va_list);
609 #endif
611 #if P_REGEX
612 #include <regex.h>
613 #else
614 #include "regex/regex.h"
615 #endif
617 #define regexpression ((regex_t *)expression)
619 #if !P_USE_INLINES
620 #include "ptlib/contain.inl"
621 #endif
623 #define new PNEW
624 #undef __CLASS__
625 #define __CLASS__ GetClass()
628 ///////////////////////////////////////////////////////////////////////////////
630 PContainer::PContainer(PINDEX initialSize)
632 reference = new Reference(initialSize);
633 PAssert(reference != NULL, POutOfMemory);
636 PContainer::PContainer(int, const PContainer * cont)
638 PAssert(cont != NULL, PInvalidParameter);
639 PAssert2(cont->reference != NULL, cont->GetClass(), "Clone of deleted container");
641 #if PCONTAINER_USES_CRITSEC
642 PEnterAndLeave m(cont->reference->critSec);
643 #endif
645 reference = new Reference(*cont->reference); // create a new reference
646 PAssert(reference != NULL, POutOfMemory);
649 PContainer::PContainer(const PContainer & cont)
651 PAssert2(cont.reference != NULL, cont.GetClass(), "Copy of deleted container");
653 #if PCONTAINER_USES_CRITSEC
654 PEnterAndLeave m(cont.reference->critSec);
655 #endif
657 ++cont.reference->count;
658 reference = cont.reference; // copy the reference pointer
662 void PContainer::AssignContents(const PContainer & cont)
664 #if PCONTAINER_USES_CRITSEC
665 // make sure the critsecs are entered and left in the right order to avoid deadlock
666 cont.reference->critSec.Enter();
667 reference->critSec.Enter();
668 #endif
670 PAssert2(cont.reference != NULL, cont.GetClass(), "Assign of deleted container");
672 if (reference == cont.reference) {
673 #if PCONTAINER_USES_CRITSEC
674 reference->critSec.Leave();
675 cont.reference->critSec.Leave();
676 #endif
677 return;
680 if (!IsUnique()) {
681 --reference->count;
683 #if PCONTAINER_USES_CRITSEC
684 reference->critSec.Leave();
685 #endif
686 } else {
687 #if PCONTAINER_USES_CRITSEC
688 reference->critSec.Leave();
689 #endif
690 DestroyContents();
691 delete reference;
692 reference = NULL;
695 ++cont.reference->count;
696 reference = cont.reference;
698 #if PCONTAINER_USES_CRITSEC
699 cont.reference->critSec.Leave();
700 #endif
704 void PContainer::Destruct()
706 if (reference != NULL) {
708 #if PCONTAINER_USES_CRITSEC
709 Reference * ref = reference;
710 ref->critSec.Enter();
711 #endif
713 --reference->count;
715 if (reference->count > 0) {
716 reference = NULL;
717 #if PCONTAINER_USES_CRITSEC
718 ref->critSec.Leave();
719 #endif
722 else {
723 #if PCONTAINER_USES_CRITSEC
724 ref->critSec.Leave();
725 #endif
726 DestroyContents();
727 delete reference;
728 reference = NULL;
734 BOOL PContainer::SetMinSize(PINDEX minSize)
736 PASSERTINDEX(minSize);
737 if (minSize < 0)
738 minSize = 0;
739 if (minSize < GetSize())
740 minSize = GetSize();
741 return SetSize(minSize);
745 BOOL PContainer::MakeUnique()
747 #if PCONTAINER_USES_CRITSEC
748 PEnterAndLeave m(reference->critSec);
749 #endif
751 if (IsUnique())
752 return TRUE;
754 Reference * oldReference = reference;
755 reference = new Reference(*reference);
756 --oldReference->count;
758 return FALSE;
762 ///////////////////////////////////////////////////////////////////////////////
764 PAbstractArray::PAbstractArray(PINDEX elementSizeInBytes, PINDEX initialSize)
765 : PContainer(initialSize)
767 elementSize = elementSizeInBytes;
768 PAssert(elementSize != 0, PInvalidParameter);
770 if (GetSize() == 0)
771 theArray = NULL;
772 else {
773 theArray = (char *)calloc(GetSize(), elementSize);
774 PAssert(theArray != NULL, POutOfMemory);
777 allocatedDynamically = TRUE;
781 PAbstractArray::PAbstractArray(PINDEX elementSizeInBytes,
782 const void *buffer,
783 PINDEX bufferSizeInElements,
784 BOOL dynamicAllocation)
785 : PContainer(bufferSizeInElements)
787 elementSize = elementSizeInBytes;
788 PAssert(elementSize != 0, PInvalidParameter);
790 allocatedDynamically = dynamicAllocation;
792 if (GetSize() == 0)
793 theArray = NULL;
794 else if (dynamicAllocation) {
795 PINDEX sizebytes = elementSize*GetSize();
796 theArray = (char *)malloc(sizebytes);
797 PAssert(theArray != NULL, POutOfMemory);
798 memcpy(theArray, PAssertNULL(buffer), sizebytes);
800 else
801 theArray = (char *)buffer;
805 void PAbstractArray::DestroyContents()
807 if (theArray != NULL) {
808 if (allocatedDynamically)
809 free(theArray);
810 theArray = NULL;
815 void PAbstractArray::CopyContents(const PAbstractArray & array)
817 elementSize = array.elementSize;
818 theArray = array.theArray;
819 allocatedDynamically = array.allocatedDynamically;
823 void PAbstractArray::CloneContents(const PAbstractArray * array)
825 elementSize = array->elementSize;
826 PINDEX sizebytes = elementSize*GetSize();
827 char * newArray = (char *)malloc(sizebytes);
828 if (newArray == NULL)
829 reference->size = 0;
830 else
831 memcpy(newArray, array->theArray, sizebytes);
832 theArray = newArray;
833 allocatedDynamically = TRUE;
837 void PAbstractArray::PrintOn(ostream & strm) const
839 char separator = strm.fill();
840 int width = strm.width();
841 for (PINDEX i = 0; i < GetSize(); i++) {
842 if (i > 0 && separator != '\0')
843 strm << separator;
844 strm.width(width);
845 PrintElementOn(strm, i);
847 if (separator == '\n')
848 strm << '\n';
852 void PAbstractArray::ReadFrom(istream & strm)
854 PINDEX i = 0;
855 while (strm.good()) {
856 ReadElementFrom(strm, i);
857 if (!strm.fail())
858 i++;
860 SetSize(i);
864 PObject::Comparison PAbstractArray::Compare(const PObject & obj) const
866 PAssert(PIsDescendant(&obj, PAbstractArray), PInvalidCast);
867 const PAbstractArray & other = (const PAbstractArray &)obj;
869 char * otherArray = other.theArray;
870 if (theArray == otherArray)
871 return EqualTo;
873 if (elementSize < other.elementSize)
874 return LessThan;
876 if (elementSize > other.elementSize)
877 return GreaterThan;
879 PINDEX thisSize = GetSize();
880 PINDEX otherSize = other.GetSize();
882 if (thisSize < otherSize)
883 return LessThan;
885 if (thisSize > otherSize)
886 return GreaterThan;
888 if (thisSize == 0)
889 return EqualTo;
891 int retval = memcmp(theArray, otherArray, elementSize*thisSize);
892 if (retval < 0)
893 return LessThan;
894 if (retval > 0)
895 return GreaterThan;
896 return EqualTo;
900 BOOL PAbstractArray::SetSize(PINDEX newSize)
902 if (newSize < 0)
903 newSize = 0;
905 PINDEX newsizebytes = elementSize*newSize;
906 PINDEX oldsizebytes = elementSize*GetSize();
908 char * newArray;
910 #if PCONTAINER_USES_CRITSEC
911 PEnterAndLeave m(reference->critSec);
912 #endif
914 if (!IsUnique()) {
916 if (newsizebytes == 0)
917 newArray = NULL;
918 else {
919 if ((newArray = (char *)malloc(newsizebytes)) == NULL)
920 return FALSE;
922 if (theArray != NULL)
923 memcpy(newArray, theArray, PMIN(oldsizebytes, newsizebytes));
926 --reference->count;
927 reference = new Reference(newSize);
929 } else {
931 if (newsizebytes == oldsizebytes)
932 return TRUE;
934 if (theArray != NULL) {
935 if (newsizebytes == 0) {
936 if (allocatedDynamically)
937 free(theArray);
938 newArray = NULL;
940 else if (allocatedDynamically) {
941 if ((newArray = (char *)realloc(theArray, newsizebytes)) == NULL)
942 return FALSE;
944 else {
945 if ((newArray = (char *)malloc(newsizebytes)) == NULL)
946 return FALSE;
947 memcpy(newArray, theArray, PMIN(newsizebytes, oldsizebytes));
948 allocatedDynamically = TRUE;
951 else if (newsizebytes != 0) {
952 if ((newArray = (char *)malloc(newsizebytes)) == NULL)
953 return FALSE;
955 else
956 newArray = NULL;
958 reference->size = newSize;
961 if (newsizebytes > oldsizebytes)
962 memset(newArray+oldsizebytes, 0, newsizebytes-oldsizebytes);
964 theArray = newArray;
965 return TRUE;
969 void PAbstractArray::Attach(const void *buffer, PINDEX bufferSize)
971 if (allocatedDynamically && theArray != NULL)
972 free(theArray);
974 #if PCONTAINER_USES_CRITSEC
975 PEnterAndLeave m(reference->critSec);
976 #endif
978 theArray = (char *)buffer;
979 reference->size = bufferSize;
980 allocatedDynamically = FALSE;
984 void * PAbstractArray::GetPointer(PINDEX minSize)
986 PAssert(SetMinSize(minSize), POutOfMemory);
987 return theArray;
991 BOOL PAbstractArray::Concatenate(const PAbstractArray & array)
993 if (!allocatedDynamically || array.elementSize != elementSize)
994 return FALSE;
996 PINDEX oldLen = GetSize();
997 PINDEX addLen = array.GetSize();
999 if (!SetSize(oldLen + addLen))
1000 return FALSE;
1002 memcpy(theArray+oldLen*elementSize, array.theArray, addLen*elementSize);
1003 return TRUE;
1007 void PAbstractArray::PrintElementOn(ostream & /*stream*/, PINDEX /*index*/) const
1012 void PAbstractArray::ReadElementFrom(istream & /*stream*/, PINDEX /*index*/)
1017 ///////////////////////////////////////////////////////////////////////////////
1019 void PCharArray::PrintOn(ostream & strm) const
1021 PINDEX width = strm.width();
1022 if (width > GetSize())
1023 width -= GetSize();
1024 else
1025 width = 0;
1027 BOOL left = (strm.flags()&ios::adjustfield) == ios::left;
1028 if (left)
1029 strm.write(theArray, GetSize());
1031 while (width-- > 0)
1032 strm << (char)strm.fill();
1034 if (!left)
1035 strm.write(theArray, GetSize());
1039 void PCharArray::ReadFrom(istream &strm)
1041 PINDEX size = 0;
1042 SetSize(size+100);
1044 while (strm.good()) {
1045 strm >> theArray[size++];
1046 if (size >= GetSize())
1047 SetSize(size+100);
1050 SetSize(size);
1054 void PBYTEArray::PrintOn(ostream & strm) const
1056 PINDEX line_width = strm.width();
1057 if (line_width == 0)
1058 line_width = 16;
1059 strm.width(0);
1061 PINDEX indent = strm.precision();
1063 PINDEX val_width = ((strm.flags()&ios::basefield) == ios::hex) ? 2 : 3;
1065 PINDEX i = 0;
1066 while (i < GetSize()) {
1067 if (i > 0)
1068 strm << '\n';
1069 PINDEX j;
1070 for (j = 0; j < indent; j++)
1071 strm << ' ';
1072 for (j = 0; j < line_width; j++) {
1073 if (j == line_width/2)
1074 strm << ' ';
1075 if (i+j < GetSize())
1076 strm << setw(val_width) << (theArray[i+j]&0xff);
1077 else {
1078 PINDEX k;
1079 for (k = 0; k < val_width; k++)
1080 strm << ' ';
1082 strm << ' ';
1084 if ((strm.flags()&ios::floatfield) != ios::fixed) {
1085 strm << " ";
1086 for (j = 0; j < line_width; j++) {
1087 if (i+j < GetSize()) {
1088 unsigned val = theArray[i+j]&0xff;
1089 if (isprint(val))
1090 strm << (char)val;
1091 else
1092 strm << '.';
1096 i += line_width;
1101 void PBYTEArray::ReadFrom(istream &strm)
1103 PINDEX size = 0;
1104 SetSize(size+100);
1106 while (strm.good()) {
1107 unsigned v;
1108 strm >> v;
1109 theArray[size] = (BYTE)v;
1110 if (!strm.fail()) {
1111 size++;
1112 if (size >= GetSize())
1113 SetSize(size+100);
1117 SetSize(size);
1121 ///////////////////////////////////////////////////////////////////////////////
1123 PBitArray::PBitArray(PINDEX initialSize)
1124 : PBYTEArray((initialSize+7)>>3)
1129 PBitArray::PBitArray(const void * buffer,
1130 PINDEX length,
1131 BOOL dynamic)
1132 : PBYTEArray((const BYTE *)buffer, (length+7)>>3, dynamic)
1137 PObject * PBitArray::Clone() const
1139 return new PBitArray(*this);
1143 PINDEX PBitArray::GetSize() const
1145 return PBYTEArray::GetSize()<<3;
1149 BOOL PBitArray::SetSize(PINDEX newSize)
1151 return PBYTEArray::SetSize((newSize+7)>>3);
1155 BOOL PBitArray::SetAt(PINDEX index, BOOL val)
1157 if (!SetMinSize(index+1))
1158 return FALSE;
1160 if (val)
1161 theArray[index>>3] |= (1 << (index&7));
1162 else
1163 theArray[index>>3] &= ~(1 << (index&7));
1164 return TRUE;
1168 BOOL PBitArray::GetAt(PINDEX index) const
1170 PASSERTINDEX(index);
1171 if (index >= GetSize())
1172 return FALSE;
1174 return (theArray[index>>3]&(1 << (index&7))) != 0;
1178 void PBitArray::Attach(const void * buffer, PINDEX bufferSize)
1180 PBYTEArray::Attach((const BYTE *)buffer, (bufferSize+7)>>3);
1184 BYTE * PBitArray::GetPointer(PINDEX minSize)
1186 return PBYTEArray::GetPointer((minSize+7)>>3);
1190 BOOL PBitArray::Concatenate(const PBitArray & array)
1192 return PAbstractArray::Concatenate(array);
1196 ///////////////////////////////////////////////////////////////////////////////
1198 PString::PString(const char * cstr)
1199 : PCharArray(cstr != NULL ? strlen(cstr)+1 : 1)
1201 if (cstr != NULL)
1202 memcpy(theArray, cstr, GetSize());
1206 PString::PString(const WORD * ustr)
1208 if (ustr == NULL)
1209 SetSize(1);
1210 else {
1211 PINDEX len = 0;
1212 while (ustr[len] != 0)
1213 len++;
1214 InternalFromUCS2(ustr, len);
1219 PString::PString(const char * cstr, PINDEX len)
1220 : PCharArray(len+1)
1222 if (len > 0)
1223 memcpy(theArray, PAssertNULL(cstr), len);
1227 PString::PString(const WORD * ustr, PINDEX len)
1228 : PCharArray(len+1)
1230 InternalFromUCS2(ustr, len);
1234 PString::PString(const PWORDArray & ustr)
1236 InternalFromUCS2(ustr, ustr.GetSize());
1240 static int TranslateHex(char x)
1242 if (x >= 'a')
1243 return x - 'a' + 10;
1245 if (x >= 'A')
1246 return x - 'A' + '\x0a';
1248 return x - '0';
1252 static const char PStringEscapeCode[] = { 'a', 'b', 'f', 'n', 'r', 't', 'v' };
1253 static const char PStringEscapeValue[] = { '\a', '\b', '\f', '\n', '\r', '\t', '\v' };
1255 static void TranslateEscapes(const char * src, char * dst)
1257 if (*src == '"')
1258 src++;
1260 while (*src != '\0') {
1261 int c = *src++;
1262 if (c == '"' && *src == '\0')
1263 c = '\0'; // Trailing '"' is ignored
1264 else if (c == '\\') {
1265 c = *src++;
1266 for (PINDEX i = 0; i < PARRAYSIZE(PStringEscapeCode); i++) {
1267 if (c == PStringEscapeCode[i])
1268 c = PStringEscapeValue[i];
1271 if (c == 'x' && isxdigit(*src)) {
1272 c = TranslateHex(*src++);
1273 if (isxdigit(*src))
1274 c = (c << 4) + TranslateHex(*src++);
1276 else if (c >= '0' && c <= '7') {
1277 int count = c <= '3' ? 3 : 2;
1278 src--;
1279 c = 0;
1280 do {
1281 c = (c << 3) + *src++ - '0';
1282 } while (--count > 0 && *src >= '0' && *src <= '7');
1286 *dst++ = (char)c;
1291 PString::PString(ConversionType type, const char * str, ...)
1293 switch (type) {
1294 case Pascal :
1295 if (*str != '\0') {
1296 PINDEX len = *str & 0xff;
1297 PAssert(SetSize(len+1), POutOfMemory);
1298 memcpy(theArray, str+1, len);
1300 break;
1302 case Basic :
1303 if (str[0] != '\0' && str[1] != '\0') {
1304 PINDEX len = str[0] | (str[1] << 8);
1305 PAssert(SetSize(len+1), POutOfMemory);
1306 memcpy(theArray, str+2, len);
1308 break;
1310 case Literal :
1311 PAssert(SetSize(strlen(str)+1), POutOfMemory);
1312 TranslateEscapes(str, theArray);
1313 PAssert(MakeMinimumSize(), POutOfMemory);
1314 break;
1316 case Printf : {
1317 va_list args;
1318 va_start(args, str);
1319 vsprintf(str, args);
1320 va_end(args);
1321 break;
1324 default :
1325 PAssertAlways(PInvalidParameter);
1330 template <class T> char * p_unsigned2string(T value, T base, char * str)
1332 if (value >= base)
1333 str = p_unsigned2string<T>(value/base, base, str);
1334 value %= base;
1335 if (value < 10)
1336 *str = (char)(value + '0');
1337 else
1338 *str = (char)(value + 'A'-10);
1339 return str+1;
1343 template <class T> char * p_signed2string(T value, T base, char * str)
1345 if (value >= 0)
1346 return p_unsigned2string<T>(value, base, str);
1348 *str = '-';
1349 return p_unsigned2string<T>(-value, base, str+1);
1353 PString::PString(short n)
1354 : PCharArray(sizeof(short)*3+1)
1356 p_signed2string<int>(n, 10, theArray);
1357 MakeMinimumSize();
1361 PString::PString(unsigned short n)
1362 : PCharArray(sizeof(unsigned short)*3+1)
1364 p_unsigned2string<unsigned int>(n, 10, theArray);
1365 MakeMinimumSize();
1369 PString::PString(int n)
1370 : PCharArray(sizeof(int)*3+1)
1372 p_signed2string<int>(n, 10, theArray);
1373 MakeMinimumSize();
1377 PString::PString(unsigned int n)
1378 : PCharArray(sizeof(unsigned int)*3+1)
1380 p_unsigned2string<unsigned int>(n, 10, theArray);
1381 MakeMinimumSize();
1385 PString::PString(long n)
1386 : PCharArray(sizeof(long)*3+1)
1388 p_signed2string<long>(n, 10, theArray);
1389 MakeMinimumSize();
1393 PString::PString(unsigned long n)
1394 : PCharArray(sizeof(unsigned long)*3+1)
1396 p_unsigned2string<unsigned long>(n, 10, theArray);
1397 MakeMinimumSize();
1401 PString::PString(PInt64 n)
1402 : PCharArray(sizeof(PInt64)*3+1)
1404 p_signed2string<PInt64>(n, 10, theArray);
1405 MakeMinimumSize();
1409 PString::PString(PUInt64 n)
1410 : PCharArray(sizeof(PUInt64)*3+1)
1412 p_unsigned2string<PUInt64>(n, 10, theArray);
1413 MakeMinimumSize();
1417 PString::PString(ConversionType type, long value, unsigned base)
1418 : PCharArray(sizeof(long)*3+1)
1420 PAssert(base >= 2 && base <= 36, PInvalidParameter);
1421 switch (type) {
1422 case Signed :
1423 p_signed2string<long>(value, base, theArray);
1424 break;
1426 case Unsigned :
1427 p_unsigned2string<unsigned long>(value, base, theArray);
1428 break;
1430 default :
1431 PAssertAlways(PInvalidParameter);
1433 MakeMinimumSize();
1437 PString::PString(ConversionType type, double value, unsigned places)
1439 switch (type) {
1440 case Decimal :
1441 sprintf("%0.*f", (int)places, value);
1442 break;
1444 case Exponent :
1445 sprintf("%0.*e", (int)places, value);
1446 break;
1448 default :
1449 PAssertAlways(PInvalidParameter);
1454 PString & PString::operator=(short n)
1456 SetMinSize(sizeof(short)*3+1);
1457 p_signed2string<int>(n, 10, theArray);
1458 MakeMinimumSize();
1459 return *this;
1463 PString & PString::operator=(unsigned short n)
1465 SetMinSize(sizeof(unsigned short)*3+1);
1466 p_unsigned2string<unsigned int>(n, 10, theArray);
1467 MakeMinimumSize();
1468 return *this;
1472 PString & PString::operator=(int n)
1474 SetMinSize(sizeof(int)*3+1);
1475 p_signed2string<int>(n, 10, theArray);
1476 MakeMinimumSize();
1477 return *this;
1481 PString & PString::operator=(unsigned int n)
1483 SetMinSize(sizeof(unsigned int)*3+1);
1484 p_unsigned2string<unsigned int>(n, 10, theArray);
1485 MakeMinimumSize();
1486 return *this;
1490 PString & PString::operator=(long n)
1492 SetMinSize(sizeof(long)*3+1);
1493 p_signed2string<long>(n, 10, theArray);
1494 MakeMinimumSize();
1495 return *this;
1499 PString & PString::operator=(unsigned long n)
1501 SetMinSize(sizeof(unsigned long)*3+1);
1502 p_unsigned2string<unsigned long>(n, 10, theArray);
1503 MakeMinimumSize();
1504 return *this;
1508 PString & PString::operator=(PInt64 n)
1510 SetMinSize(sizeof(PInt64)*3+1);
1511 p_signed2string<PInt64>(n, 10, theArray);
1512 MakeMinimumSize();
1513 return *this;
1517 PString & PString::operator=(PUInt64 n)
1519 SetMinSize(sizeof(PUInt64)*3+1);
1520 p_unsigned2string<PUInt64>(n, 10, theArray);
1521 MakeMinimumSize();
1522 return *this;
1526 PString & PString::MakeEmpty()
1528 SetSize(1);
1529 *theArray = '\0';
1530 return *this;
1534 PObject * PString::Clone() const
1536 return new PString(*this);
1540 void PString::PrintOn(ostream &strm) const
1542 strm << theArray;
1546 void PString::ReadFrom(istream &strm)
1548 SetMinSize(100);
1549 char * ptr = theArray;
1550 PINDEX len = 0;
1551 int c;
1552 while ((c = strm.get()) != EOF && c != '\n') {
1553 *ptr++ = (char)c;
1554 len++;
1555 if (len >= GetSize()) {
1556 SetSize(len + 100);
1557 ptr = theArray + len;
1560 *ptr = '\0';
1561 if ((len > 0) && (ptr[-1] == '\r'))
1562 ptr[-1] = '\0';
1563 PAssert(MakeMinimumSize(), POutOfMemory);
1567 PObject::Comparison PString::Compare(const PObject & obj) const
1569 PAssert(PIsDescendant(&obj, PString), PInvalidCast);
1570 return InternalCompare(0, P_MAX_INDEX, ((const PString &)obj).theArray);
1574 PINDEX PString::HashFunction() const
1576 // Hash function from "Data Structures and Algorithm Analysis in C++" by
1577 // Mark Allen Weiss, with limit of only executing over first 8 characters to
1578 // increase speed when dealing with large strings.
1580 PINDEX hash = 0;
1581 for (PINDEX i = 0; i < 8 && theArray[i] != 0; i++)
1582 hash = (hash << 5) ^ tolower(theArray[i]) ^ hash;
1583 return PABSINDEX(hash)%127;
1587 BOOL PString::IsEmpty() const
1589 return (theArray == NULL) || (*theArray == '\0');
1593 BOOL PString::SetSize(PINDEX newSize)
1595 return PAbstractArray::SetSize(newSize);
1596 #if 0
1597 if (IsUnique())
1598 return PAbstractArray::SetSize(newSize);
1600 PINDEX newsizebytes = elementSize*newSize;
1601 PINDEX oldsizebytes = elementSize*GetSize();
1602 char * newArray;
1604 if (newsizebytes == 0)
1605 newArray = NULL;
1606 else {
1607 if ((newArray = (char *)malloc(newsizebytes)) == NULL)
1608 return FALSE;
1610 if (theArray != NULL)
1611 memcpy(newArray, theArray, PMIN(oldsizebytes, newsizebytes));
1614 reference->count--;
1615 reference = new Reference(newSize);
1617 if (newsizebytes > oldsizebytes)
1618 memset(newArray+oldsizebytes, 0, newsizebytes-oldsizebytes);
1620 theArray = newArray;
1621 return TRUE;
1622 #endif
1626 BOOL PString::MakeUnique()
1628 #if PCONTAINER_USES_CRITSEC
1629 PEnterAndLeave m(reference->critSec);
1630 #endif
1632 if (IsUnique())
1633 return TRUE;
1635 SetSize(GetSize());
1636 return FALSE;
1640 PString PString::operator+(const char * cstr) const
1642 if (cstr == NULL)
1643 return *this;
1645 PINDEX olen = GetLength();
1646 PINDEX alen = strlen(cstr)+1;
1647 PString str;
1648 str.SetSize(olen+alen);
1649 memmove(str.theArray, theArray, olen);
1650 memcpy(str.theArray+olen, cstr, alen);
1651 return str;
1655 PString PString::operator+(char c) const
1657 PINDEX olen = GetLength();
1658 PString str;
1659 str.SetSize(olen+2);
1660 memmove(str.theArray, theArray, olen);
1661 str.theArray[olen] = c;
1662 return str;
1666 PString & PString::operator+=(const char * cstr)
1668 if (cstr == NULL)
1669 return *this;
1671 PINDEX olen = GetLength();
1672 PINDEX alen = strlen(cstr)+1;
1673 SetSize(olen+alen);
1674 memcpy(theArray+olen, cstr, alen);
1675 return *this;
1679 PString & PString::operator+=(char ch)
1681 PINDEX olen = GetLength();
1682 SetSize(olen+2);
1683 theArray[olen] = ch;
1684 return *this;
1688 PString PString::operator&(const char * cstr) const
1690 if (cstr == NULL)
1691 return *this;
1693 PINDEX alen = strlen(cstr)+1;
1694 if (alen == 1)
1695 return *this;
1697 PINDEX olen = GetLength();
1698 PString str;
1699 PINDEX space = olen > 0 && theArray[olen-1]!=' ' && *cstr!=' ' ? 1 : 0;
1700 str.SetSize(olen+alen+space);
1701 memmove(str.theArray, theArray, olen);
1702 if (space != 0)
1703 str.theArray[olen] = ' ';
1704 memcpy(str.theArray+olen+space, cstr, alen);
1705 return str;
1709 PString PString::operator&(char c) const
1711 PINDEX olen = GetLength();
1712 PString str;
1713 PINDEX space = olen > 0 && theArray[olen-1] != ' ' && c != ' ' ? 1 : 0;
1714 str.SetSize(olen+2+space);
1715 memmove(str.theArray, theArray, olen);
1716 if (space != 0)
1717 str.theArray[olen] = ' ';
1718 str.theArray[olen+space] = c;
1719 return str;
1723 PString & PString::operator&=(const char * cstr)
1725 if (cstr == NULL)
1726 return *this;
1728 PINDEX alen = strlen(cstr)+1;
1729 if (alen == 1)
1730 return *this;
1731 PINDEX olen = GetLength();
1732 PINDEX space = olen > 0 && theArray[olen-1]!=' ' && *cstr!=' ' ? 1 : 0;
1733 SetSize(olen+alen+space);
1734 if (space != 0)
1735 theArray[olen] = ' ';
1736 memcpy(theArray+olen+space, cstr, alen);
1737 return *this;
1741 PString & PString::operator&=(char ch)
1743 PINDEX olen = GetLength();
1744 PINDEX space = olen > 0 && theArray[olen-1] != ' ' && ch != ' ' ? 1 : 0;
1745 SetSize(olen+2+space);
1746 if (space != 0)
1747 theArray[olen] = ' ';
1748 theArray[olen+space] = ch;
1749 return *this;
1753 void PString::Delete(PINDEX start, PINDEX len)
1755 if (start < 0 || len < 0)
1756 return;
1758 MakeUnique();
1760 register PINDEX slen = GetLength();
1761 if (start > slen)
1762 return;
1764 if (len > slen - start)
1765 SetAt(start, '\0');
1766 else
1767 memmove(theArray+start, theArray+start+len, slen-start-len+1);
1768 MakeMinimumSize();
1772 PString PString::operator()(PINDEX start, PINDEX end) const
1774 if (end < 0 || start < 0 || end < start)
1775 return Empty();
1777 register PINDEX len = GetLength();
1778 if (start > len)
1779 return Empty();
1781 if (end >= len) {
1782 if (start == 0)
1783 return *this;
1784 end = len-1;
1786 len = end - start + 1;
1788 return PString(theArray+start, len);
1792 PString PString::Left(PINDEX len) const
1794 if (len <= 0)
1795 return Empty();
1797 if (len >= GetLength())
1798 return *this;
1800 return PString(theArray, len);
1804 PString PString::Right(PINDEX len) const
1806 if (len <= 0)
1807 return Empty();
1809 PINDEX srclen = GetLength();
1810 if (len >= srclen)
1811 return *this;
1813 return PString(theArray+srclen-len, len);
1817 PString PString::Mid(PINDEX start, PINDEX len) const
1819 if (len <= 0 || start < 0)
1820 return Empty();
1822 if (start+len < start) // Beware of wraparound
1823 return operator()(start, P_MAX_INDEX);
1824 else
1825 return operator()(start, start+len-1);
1829 bool PString::operator*=(const char * cstr) const
1831 if (cstr == NULL)
1832 return IsEmpty() != FALSE;
1834 const char * pstr = theArray;
1835 while (*pstr != '\0' && *cstr != '\0') {
1836 if (toupper(*pstr) != toupper(*cstr))
1837 return FALSE;
1838 pstr++;
1839 cstr++;
1841 return *pstr == *cstr;
1845 PObject::Comparison PString::NumCompare(const PString & str, PINDEX count, PINDEX offset) const
1847 if (offset < 0 || count < 0)
1848 return LessThan;
1849 PINDEX len = str.GetLength();
1850 if (count > len)
1851 count = len;
1852 return InternalCompare(offset, count, str);
1856 PObject::Comparison PString::NumCompare(const char * cstr, PINDEX count, PINDEX offset) const
1858 if (offset < 0 || count < 0)
1859 return LessThan;
1860 PINDEX len = ::strlen(cstr);
1861 if (count > len)
1862 count = len;
1863 return InternalCompare(offset, count, cstr);
1867 PObject::Comparison PString::InternalCompare(PINDEX offset, char c) const
1869 if (offset < 0)
1870 return LessThan;
1871 char ch = theArray[offset];
1872 if (ch < c)
1873 return LessThan;
1874 if (ch > c)
1875 return GreaterThan;
1876 return EqualTo;
1880 PObject::Comparison PString::InternalCompare(
1881 PINDEX offset, PINDEX length, const char * cstr) const
1883 if (offset < 0 || length < 0)
1884 return LessThan;
1886 if (offset == 0 && theArray == cstr)
1887 return EqualTo;
1889 if (offset < 0 || cstr == NULL)
1890 return IsEmpty() ? EqualTo : LessThan;
1892 int retval;
1893 if (length == P_MAX_INDEX)
1894 retval = strcmp(theArray+offset, cstr);
1895 else
1896 retval = strncmp(theArray+offset, cstr, length);
1898 if (retval < 0)
1899 return LessThan;
1901 if (retval > 0)
1902 return GreaterThan;
1904 return EqualTo;
1908 PINDEX PString::Find(char ch, PINDEX offset) const
1910 if (offset < 0)
1911 return P_MAX_INDEX;
1913 register PINDEX len = GetLength();
1914 while (offset < len) {
1915 if (InternalCompare(offset, ch) == EqualTo)
1916 return offset;
1917 offset++;
1919 return P_MAX_INDEX;
1923 PINDEX PString::Find(const char * cstr, PINDEX offset) const
1925 if (cstr == NULL || *cstr == '\0' || offset < 0)
1926 return P_MAX_INDEX;
1928 PINDEX len = GetLength();
1929 PINDEX clen = strlen(cstr);
1930 if (clen > len)
1931 return P_MAX_INDEX;
1933 if (offset > len - clen)
1934 return P_MAX_INDEX;
1936 if (len - clen < 10) {
1937 while (offset+clen <= len) {
1938 if (InternalCompare(offset, clen, cstr) == EqualTo)
1939 return offset;
1940 offset++;
1942 return P_MAX_INDEX;
1945 int strSum = 0;
1946 int cstrSum = 0;
1947 for (PINDEX i = 0; i < clen; i++) {
1948 strSum += toupper(theArray[offset+i]);
1949 cstrSum += toupper(cstr[i]);
1952 // search for a matching substring
1953 while (offset+clen <= len) {
1954 if (strSum == cstrSum && InternalCompare(offset, clen, cstr) == EqualTo)
1955 return offset;
1956 strSum += toupper(theArray[offset+clen]);
1957 strSum -= toupper(theArray[offset]);
1958 offset++;
1961 return P_MAX_INDEX;
1965 PINDEX PString::FindLast(char ch, PINDEX offset) const
1967 PINDEX len = GetLength();
1968 if (len == 0 || offset < 0)
1969 return P_MAX_INDEX;
1970 if (offset >= len)
1971 offset = len-1;
1973 while (InternalCompare(offset, ch) != EqualTo) {
1974 if (offset == 0)
1975 return P_MAX_INDEX;
1976 offset--;
1979 return offset;
1983 PINDEX PString::FindLast(const char * cstr, PINDEX offset) const
1985 if (cstr == NULL || *cstr == '\0' || offset < 0)
1986 return P_MAX_INDEX;
1988 PINDEX len = GetLength();
1989 PINDEX clen = strlen(cstr);
1990 if (clen > len)
1991 return P_MAX_INDEX;
1993 if (offset > len - clen)
1994 offset = len - clen;
1996 int strSum = 0;
1997 int cstrSum = 0;
1998 for (PINDEX i = 0; i < clen; i++) {
1999 strSum += toupper(theArray[offset+i]);
2000 cstrSum += toupper(cstr[i]);
2003 // search for a matching substring
2004 while (strSum != cstrSum || InternalCompare(offset, clen, cstr) != EqualTo) {
2005 if (offset == 0)
2006 return P_MAX_INDEX;
2007 --offset;
2008 strSum += toupper(theArray[offset]);
2009 strSum -= toupper(theArray[offset+clen]);
2012 return offset;
2016 PINDEX PString::FindOneOf(const char * cset, PINDEX offset) const
2018 if (cset == NULL || *cset == '\0' || offset < 0)
2019 return P_MAX_INDEX;
2021 PINDEX len = GetLength();
2022 while (offset < len) {
2023 const char * p = cset;
2024 while (*p != '\0') {
2025 if (InternalCompare(offset, *p) == EqualTo)
2026 return offset;
2027 p++;
2029 offset++;
2031 return P_MAX_INDEX;
2035 PINDEX PString::FindRegEx(const PRegularExpression & regex, PINDEX offset) const
2037 if (offset < 0)
2038 return P_MAX_INDEX;
2040 PINDEX pos = 0;
2041 PINDEX len = 0;
2042 if (FindRegEx(regex, pos, len, offset))
2043 return pos;
2045 return P_MAX_INDEX;
2049 BOOL PString::FindRegEx(const PRegularExpression & regex,
2050 PINDEX & pos,
2051 PINDEX & len,
2052 PINDEX offset,
2053 PINDEX maxPos) const
2055 if (offset < 0 || maxPos < 0 || offset >= GetLength())
2056 return FALSE;
2058 if (!regex.Execute(&theArray[offset], pos, len, 0))
2059 return FALSE;
2061 pos += offset;
2062 if (pos+len > maxPos)
2063 return FALSE;
2065 return TRUE;
2069 void PString::Replace(const PString & target,
2070 const PString & subs,
2071 BOOL all, PINDEX offset)
2073 if (offset < 0)
2074 return;
2076 MakeUnique();
2078 PINDEX tlen = target.GetLength();
2079 PINDEX slen = subs.GetLength();
2080 do {
2081 PINDEX pos = Find(target, offset);
2082 if (pos == P_MAX_INDEX)
2083 return;
2084 Splice(subs, pos, tlen);
2085 offset = pos + slen;
2086 } while (all);
2090 void PString::Splice(const char * cstr, PINDEX pos, PINDEX len)
2092 if (len < 0 || pos < 0)
2093 return;
2095 register PINDEX slen = GetLength();
2096 if (pos >= slen)
2097 operator+=(cstr);
2098 else {
2099 MakeUnique();
2100 PINDEX clen = cstr != NULL ? strlen(cstr) : 0;
2101 PINDEX newlen = slen-len+clen;
2102 if (clen > len)
2103 SetSize(newlen+1);
2104 if (pos+len < slen)
2105 memmove(theArray+pos+clen, theArray+pos+len, slen-pos-len+1);
2106 if (clen > 0)
2107 memcpy(theArray+pos, cstr, clen);
2108 theArray[newlen] = '\0';
2113 PStringArray
2114 PString::Tokenise(const char * separators, BOOL onePerSeparator) const
2116 PStringArray tokens;
2118 if (separators == NULL || IsEmpty()) // No tokens
2119 return tokens;
2121 PINDEX token = 0;
2122 PINDEX p1 = 0;
2123 PINDEX p2 = FindOneOf(separators);
2125 if (p2 == 0) {
2126 if (onePerSeparator) { // first character is a token separator
2127 tokens[token] = Empty();
2128 token++; // make first string in array empty
2129 p1 = 1;
2130 p2 = FindOneOf(separators, 1);
2132 else {
2133 do {
2134 p1 = p2 + 1;
2135 } while ((p2 = FindOneOf(separators, p1)) == p1);
2139 while (p2 != P_MAX_INDEX) {
2140 if (p2 > p1)
2141 tokens[token] = operator()(p1, p2-1);
2142 else
2143 tokens[token] = Empty();
2144 token++;
2146 // Get next separator. If not one token per separator then continue
2147 // around loop to skip over all the consecutive separators.
2148 do {
2149 p1 = p2 + 1;
2150 } while ((p2 = FindOneOf(separators, p1)) == p1 && !onePerSeparator);
2153 tokens[token] = operator()(p1, P_MAX_INDEX);
2155 return tokens;
2159 PStringArray PString::Lines() const
2161 PStringArray lines;
2163 if (IsEmpty())
2164 return lines;
2166 PINDEX line = 0;
2167 PINDEX p1 = 0;
2168 PINDEX p2;
2169 while ((p2 = FindOneOf("\r\n", p1)) != P_MAX_INDEX) {
2170 lines[line++] = operator()(p1, p2-1);
2171 p1 = p2 + 1;
2172 if (theArray[p2] == '\r' && theArray[p1] == '\n') // CR LF pair
2173 p1++;
2175 if (p1 < GetLength())
2176 lines[line] = operator()(p1, P_MAX_INDEX);
2177 return lines;
2180 PStringArray & PStringArray::operator += (const PStringArray & v)
2182 PINDEX i;
2183 for (i = 0; i < v.GetSize(); i++)
2184 AppendString(v[i]);
2186 return *this;
2189 PString PString::LeftTrim() const
2191 const char * lpos = theArray;
2192 while (isspace(*lpos))
2193 lpos++;
2194 return PString(lpos);
2198 PString PString::RightTrim() const
2200 char * rpos = theArray+GetLength()-1;
2201 if (isspace(*rpos))
2202 return *this;
2204 while (isspace(*rpos)) {
2205 if (rpos == theArray)
2206 return Empty();
2207 rpos--;
2210 // make Apple & Tornado gnu compiler happy
2211 PString retval(theArray, rpos - theArray + 1);
2212 return retval;
2216 PString PString::Trim() const
2218 const char * lpos = theArray;
2219 while (isspace(*lpos))
2220 lpos++;
2221 if (*lpos == '\0')
2222 return Empty();
2224 const char * rpos = theArray+GetLength()-1;
2225 if (!isspace(*rpos))
2226 return PString(lpos);
2228 while (isspace(*rpos))
2229 rpos--;
2230 return PString(lpos, rpos - lpos + 1);
2234 PString PString::ToLower() const
2236 PString newStr(theArray);
2237 for (char *cpos = newStr.theArray; *cpos != '\0'; cpos++) {
2238 if (isupper(*cpos))
2239 *cpos = (char)tolower(*cpos);
2241 return newStr;
2245 PString PString::ToUpper() const
2247 PString newStr(theArray);
2248 for (char *cpos = newStr.theArray; *cpos != '\0'; cpos++) {
2249 if (islower(*cpos))
2250 *cpos = (char)toupper(*cpos);
2252 return newStr;
2256 long PString::AsInteger(unsigned base) const
2258 PAssert(base >= 2 && base <= 36, PInvalidParameter);
2259 char * dummy;
2260 return strtol(theArray, &dummy, base);
2264 DWORD PString::AsUnsigned(unsigned base) const
2266 PAssert(base >= 2 && base <= 36, PInvalidParameter);
2267 char * dummy;
2268 return strtoul(theArray, &dummy, base);
2272 double PString::AsReal() const
2274 #ifndef __HAS_NO_FLOAT
2275 char * dummy;
2276 return strtod(theArray, &dummy);
2277 #else
2278 return 0.0;
2279 #endif
2283 PWORDArray PString::AsUCS2() const
2285 #ifdef P_HAS_G_CONVERT
2287 gsize g_len = 0;
2288 gchar * g_ucs2 = g_convert(theArray, GetSize()-1, "UCS-2", "UTF-8", 0, &g_len, 0);
2289 if (g_ucs2 == NULL)
2290 return PWORDArray();
2292 PWORDArray ucs2((const WORD *)g_ucs2, (PINDEX)g_len);
2293 g_free(g_ucs2)
2294 return ucs2;
2296 #else
2298 PWORDArray ucs2(GetSize()); // Always bigger than required
2300 PINDEX count = 0;
2301 PINDEX i = 0;
2302 PINDEX length = GetSize()-1;
2303 while (i < length) {
2304 int c = theArray[i];
2305 if ((c&0x80) == 0)
2306 ucs2[count++] = (BYTE)theArray[i++];
2307 else if ((c&0xe0) == 0xc0) {
2308 if (i < length-1)
2309 ucs2[count++] = (WORD)(((theArray[i ]&0x1f)<<6)|
2310 (theArray[i+1]&0x3f));
2311 i += 2;
2313 else if ((c&0xf0) == 0xe0) {
2314 if (i < length-2)
2315 ucs2[count++] = (WORD)(((theArray[i ]&0x0f)<<12)|
2316 ((theArray[i+1]&0x3f)<< 6)|
2317 (theArray[i+2]&0x3f));
2318 i += 3;
2320 else {
2321 if ((c&0xf8) == 0xf0)
2322 i += 4;
2323 else if ((c&0xfc) == 0xf8)
2324 i += 5;
2325 else
2326 i += 6;
2327 if (i <= length)
2328 ucs2[count++] = 0xffff;
2332 ucs2.SetSize(count);
2333 return ucs2;
2335 #endif
2339 void PString::InternalFromUCS2(const WORD * ptr, PINDEX len)
2341 if (ptr == NULL || len <= 0) {
2342 *this = Empty();
2343 return;
2346 #ifdef P_HAS_G_CONVERT
2348 gsize g_len = 0;
2349 gchar * g_utf8 = g_convert(ptr, len, "UTF-8", "UCS-2", 0, &g_len, 0);
2350 if (g_utf8 == NULL) {
2351 *this = Empty();
2352 return;
2355 SetSize(&g_len);
2356 memcpy(theArray, g_char, g_len);
2357 g_free(g_utf8);
2359 #else
2361 PINDEX i;
2362 PINDEX count = 1;
2363 for (i = 0; i < len; i++) {
2364 if (ptr[i] < 0x80)
2365 count++;
2366 else if (ptr[i] < 0x800)
2367 count += 2;
2368 else
2369 count += 3;
2371 SetSize(count);
2373 count = 0;
2374 for (i = 0; i < len; i++) {
2375 unsigned v = *ptr++;
2376 if (v < 0x80)
2377 theArray[count++] = (char)v;
2378 else if (v < 0x800) {
2379 theArray[count++] = (char)(0xc0+(v>>6));
2380 theArray[count++] = (char)(0x80+(v&0x3f));
2382 else {
2383 theArray[count++] = (char)(0xd0+(v>>12));
2384 theArray[count++] = (char)(0x80+((v>>6)&0x3f));
2385 theArray[count++] = (char)(0x80+(v&0x3f));
2389 #endif
2393 PBYTEArray PString::ToPascal() const
2395 PINDEX len = GetLength();
2396 PAssert(len < 256, "Cannot convert to PASCAL string");
2397 BYTE buf[256];
2398 buf[0] = (BYTE)len;
2399 memcpy(&buf[1], theArray, len);
2400 return PBYTEArray(buf, len+1);
2404 PString PString::ToLiteral() const
2406 PString str('"');
2407 for (char * p = theArray; *p != '\0'; p++) {
2408 if (*p == '"')
2409 str += "\\\"";
2410 else if (isprint(*p))
2411 str += *p;
2412 else {
2413 PINDEX i;
2414 for (i = 0; i < PARRAYSIZE(PStringEscapeValue); i++) {
2415 if (*p == PStringEscapeValue[i]) {
2416 str += PString('\\') + PStringEscapeCode[i];
2417 break;
2420 if (i >= PARRAYSIZE(PStringEscapeValue))
2421 str.sprintf("\\%03o", *p & 0xff);
2424 return str + '"';
2428 PString & PString::sprintf(const char * fmt, ...)
2430 va_list args;
2431 va_start(args, fmt);
2432 return vsprintf(fmt, args);
2435 #if defined(__GNUC__) || defined(__SUNPRO_CC)
2436 #define _vsnprintf vsnprintf
2437 #endif
2439 PString & PString::vsprintf(const char * fmt, va_list arg)
2441 PINDEX len = theArray != NULL ? GetLength() : 0;
2442 #ifdef P_VXWORKS
2443 // The library provided with tornado 2.0 does not have the implementation
2444 // for vsnprintf
2445 // as workaround, just use a array size of 2000
2446 PAssert(SetSize(2000), POutOfMemory);
2447 ::vsprintf(theArray+len, fmt, arg);
2448 #else
2449 PINDEX size = 0;
2450 do {
2451 size += 1000;
2452 PAssert(SetSize(size), POutOfMemory);
2453 } while (_vsnprintf(theArray+len, size-len, fmt, arg) == -1);
2454 #endif // P_VXWORKS
2456 PAssert(MakeMinimumSize(), POutOfMemory);
2457 return *this;
2461 PString psprintf(const char * fmt, ...)
2463 PString str;
2464 va_list args;
2465 va_start(args, fmt);
2466 return str.vsprintf(fmt, args);
2470 PString pvsprintf(const char * fmt, va_list arg)
2472 PString str;
2473 return str.vsprintf(fmt, arg);
2477 ///////////////////////////////////////////////////////////////////////////////
2479 PObject * PCaselessString::Clone() const
2481 return new PCaselessString(*this);
2485 PObject::Comparison PCaselessString::InternalCompare(PINDEX offset, char c) const
2487 if (offset < 0)
2488 return LessThan;
2490 int c1 = toupper(theArray[offset]);
2491 int c2 = toupper(c);
2492 if (c1 < c2)
2493 return LessThan;
2494 if (c1 > c2)
2495 return GreaterThan;
2496 return EqualTo;
2500 PObject::Comparison PCaselessString::InternalCompare(
2501 PINDEX offset, PINDEX length, const char * cstr) const
2503 if (offset < 0 || length < 0)
2504 return LessThan;
2506 if (cstr == NULL)
2507 return IsEmpty() ? EqualTo : LessThan;
2509 while (length-- > 0 && (theArray[offset] != '\0' || *cstr != '\0')) {
2510 Comparison c = PCaselessString::InternalCompare(offset++, *cstr++);
2511 if (c != EqualTo)
2512 return c;
2514 return EqualTo;
2519 ///////////////////////////////////////////////////////////////////////////////
2521 PStringStream::Buffer::Buffer(PStringStream & str, PINDEX size)
2522 : string(str),
2523 fixedBufferSize(size != 0)
2525 string.SetMinSize(size > 0 ? size : 256);
2526 sync();
2530 int PStringStream::Buffer::overflow(int c)
2532 if (pptr() >= epptr()) {
2533 if (fixedBufferSize)
2534 return EOF;
2536 int gpos = gptr() - eback();
2537 int ppos = pptr() - pbase();
2538 char * newptr = string.GetPointer(string.GetSize() + 32);
2539 setp(newptr, newptr + string.GetSize() - 1);
2540 pbump(ppos);
2541 setg(newptr, newptr + gpos, newptr + ppos);
2544 if (c != EOF) {
2545 *pptr() = (char)c;
2546 pbump(1);
2549 return 0;
2553 int PStringStream::Buffer::underflow()
2555 return gptr() >= egptr() ? EOF : *gptr();
2559 int PStringStream::Buffer::sync()
2561 char * base = string.GetPointer();
2562 PINDEX len = string.GetLength();
2563 setg(base, base, base + len);
2564 setp(base, base + string.GetSize() - 1);
2565 pbump(len);
2566 return 0;
2569 #if __USE_STL__
2570 streambuf::pos_type PStringStream::Buffer::seekoff(off_type off, ios_base::seekdir dir, ios_base::openmode mode)
2571 #else
2572 streampos PStringStream::Buffer::seekoff(streamoff off, ios::seek_dir dir, int mode)
2573 #endif
2575 int len = string.GetLength();
2576 int gpos = gptr() - eback();
2577 int ppos = pptr() - pbase();
2578 char * newgptr;
2579 char * newpptr;
2580 switch (dir) {
2581 case ios::beg :
2582 if (off < 0)
2583 newpptr = newgptr = eback();
2584 else if (off >= len)
2585 newpptr = newgptr = egptr();
2586 else
2587 newpptr = newgptr = eback()+off;
2588 break;
2590 case ios::cur :
2591 if (off < -ppos)
2592 newpptr = eback();
2593 else if (off >= len-ppos)
2594 newpptr = epptr();
2595 else
2596 newpptr = pptr()+off;
2597 if (off < -gpos)
2598 newgptr = eback();
2599 else if (off >= len-gpos)
2600 newgptr = egptr();
2601 else
2602 newgptr = gptr()+off;
2603 break;
2605 case ios::end :
2606 if (off < -len)
2607 newpptr = newgptr = eback();
2608 else if (off >= 0)
2609 newpptr = newgptr = egptr();
2610 else
2611 newpptr = newgptr = egptr()+off;
2612 break;
2614 default:
2615 PAssertAlways2(string.GetClass(), PInvalidParameter);
2616 newgptr = gptr();
2617 newpptr = pptr();
2620 if ((mode&ios::in) != 0)
2621 setg(eback(), newgptr, egptr());
2623 if ((mode&ios::out) != 0)
2624 setp(newpptr, epptr());
2626 return 0;
2630 #if __USE_STL__
2631 streampos PStringStream::Buffer::seekpos(pos_type pos, ios_base::openmode mode)
2633 return seekoff(pos, ios_base::beg, mode);
2635 #endif
2638 #ifdef _MSC_VER
2639 #pragma warning(disable:4355)
2640 #endif
2642 PStringStream::PStringStream()
2643 : iostream(new PStringStream::Buffer(*this, 0))
2648 PStringStream::PStringStream(PINDEX fixedBufferSize)
2649 : iostream(new PStringStream::Buffer(*this, fixedBufferSize))
2654 PStringStream::PStringStream(const PString & str)
2655 : PString(str),
2656 iostream(new PStringStream::Buffer(*this, 0))
2661 PStringStream::PStringStream(const char * cstr)
2662 : PString(cstr),
2663 iostream(new PStringStream::Buffer(*this, 0))
2667 #ifdef _MSC_VER
2668 #pragma warning(default:4355)
2669 #endif
2672 PStringStream::~PStringStream()
2674 delete (PStringStream::Buffer *)rdbuf();
2675 #ifndef _WIN32
2676 init(NULL);
2677 #endif
2681 PString & PStringStream::MakeEmpty()
2683 *theArray = '\0';
2684 flush();
2685 return *this;
2689 void PStringStream::AssignContents(const PContainer & cont)
2691 PString::AssignContents(cont);
2692 flush();
2696 ///////////////////////////////////////////////////////////////////////////////
2698 PStringArray::PStringArray(PINDEX count, char const * const * strarr, BOOL caseless)
2700 if (count == 0)
2701 return;
2703 if (PAssertNULL(strarr) == NULL)
2704 return;
2706 if (count == P_MAX_INDEX) {
2707 count = 0;
2708 while (strarr[count] != NULL)
2709 count++;
2712 SetSize(count);
2713 for (PINDEX i = 0; i < count; i++) {
2714 PString * newString;
2715 if (caseless)
2716 newString = new PCaselessString(strarr[i]);
2717 else
2718 newString = new PString(strarr[i]);
2719 SetAt(i, newString);
2724 PStringArray::PStringArray(const PString & str)
2726 SetSize(1);
2727 (*theArray)[0] = new PString(str);
2731 PStringArray::PStringArray(const PStringList & list)
2733 SetSize(list.GetSize());
2734 for (PINDEX i = 0; i < list.GetSize(); i++)
2735 (*theArray)[i] = new PString(list[i]);
2739 PStringArray::PStringArray(const PSortedStringList & list)
2741 SetSize(list.GetSize());
2742 for (PINDEX i = 0; i < list.GetSize(); i++)
2743 (*theArray)[i] = new PString(list[i]);
2747 void PStringArray::ReadFrom(istream & strm)
2749 while (strm.good()) {
2750 PString str;
2751 strm >> str;
2752 AppendString(str);
2757 PString & PStringArray::operator[](PINDEX index)
2759 PASSERTINDEX(index);
2760 PAssert(SetMinSize(index+1), POutOfMemory);
2761 if ((*theArray)[index] == NULL)
2762 (*theArray)[index] = new PString;
2763 return *(PString *)(*theArray)[index];
2767 char ** PStringArray::ToCharArray(PCharArray * storage) const
2769 PINDEX i;
2771 PINDEX mySize = GetSize();
2772 PINDEX storageSize = (mySize+1)*sizeof(char *);
2773 for (i = 0; i < mySize; i++)
2774 storageSize += (*this)[i].GetLength()+1;
2776 char ** storagePtr;
2777 if (storage != NULL)
2778 storagePtr = (char **)storage->GetPointer(storageSize);
2779 else
2780 storagePtr = (char **)malloc(storageSize);
2782 if (storagePtr == NULL)
2783 return NULL;
2785 char * strPtr = (char *)&storagePtr[GetSize()+1];
2787 for (i = 0; i < mySize; i++) {
2788 storagePtr[i] = strPtr;
2789 const PString & str = (*this)[i];
2790 PINDEX len = str.GetLength()+1;
2791 memcpy(strPtr, (const char *)str, len);
2792 strPtr += len;
2795 storagePtr[i] = NULL;
2797 return storagePtr;
2801 ///////////////////////////////////////////////////////////////////////////////
2803 PStringList::PStringList(PINDEX count, char const * const * strarr, BOOL caseless)
2805 if (count == 0)
2806 return;
2808 if (PAssertNULL(strarr) == NULL)
2809 return;
2811 for (PINDEX i = 0; i < count; i++) {
2812 PString * newString;
2813 if (caseless)
2814 newString = new PCaselessString(strarr[i]);
2815 else
2816 newString = new PString(strarr[i]);
2817 Append(newString);
2822 PStringList::PStringList(const PString & str)
2824 AppendString(str);
2828 PStringList::PStringList(const PStringArray & array)
2830 for (PINDEX i = 0; i < array.GetSize(); i++)
2831 AppendString(array[i]);
2835 PStringList::PStringList(const PSortedStringList & list)
2837 for (PINDEX i = 0; i < list.GetSize(); i++)
2838 AppendString(list[i]);
2841 PStringList & PStringList::operator += (const PStringList & v)
2843 PINDEX i;
2844 for (i = 0; i < v.GetSize(); i++)
2845 AppendString(v[i]);
2847 return *this;
2851 void PStringList::ReadFrom(istream & strm)
2853 while (strm.good()) {
2854 PString str;
2855 strm >> str;
2856 AppendString(str);
2861 ///////////////////////////////////////////////////////////////////////////////
2863 PSortedStringList::PSortedStringList(PINDEX count,
2864 char const * const * strarr,
2865 BOOL caseless)
2867 if (count == 0)
2868 return;
2870 if (PAssertNULL(strarr) == NULL)
2871 return;
2873 for (PINDEX i = 0; i < count; i++) {
2874 PString * newString;
2875 if (caseless)
2876 newString = new PCaselessString(strarr[i]);
2877 else
2878 newString = new PString(strarr[i]);
2879 Append(newString);
2884 PSortedStringList::PSortedStringList(const PString & str)
2886 AppendString(str);
2890 PSortedStringList::PSortedStringList(const PStringArray & array)
2892 for (PINDEX i = 0; i < array.GetSize(); i++)
2893 AppendString(array[i]);
2897 PSortedStringList::PSortedStringList(const PStringList & list)
2899 for (PINDEX i = 0; i < list.GetSize(); i++)
2900 AppendString(list[i]);
2905 void PSortedStringList::ReadFrom(istream & strm)
2907 while (strm.good()) {
2908 PString str;
2909 strm >> str;
2910 AppendString(str);
2915 PINDEX PSortedStringList::GetNextStringsIndex(const PString & str) const
2917 PINDEX len = str.GetLength();
2919 info->lastIndex = InternalStringSelect(str, len, info->root);
2921 if (info->lastIndex != 0) {
2922 Element * prev;
2923 while ((prev = Predecessor(info->lastElement)) != &info->nil &&
2924 ((PString *)prev->data)->NumCompare(str, len) >= EqualTo) {
2925 info->lastElement = prev;
2926 info->lastIndex--;
2930 return info->lastIndex;
2934 PINDEX PSortedStringList::InternalStringSelect(const char * str,
2935 PINDEX len,
2936 Element * thisElement) const
2938 if (thisElement == &info->nil)
2939 return 0;
2941 switch (((PString *)thisElement->data)->NumCompare(str, len)) {
2942 case PObject::LessThan :
2944 PINDEX index = InternalStringSelect(str, len, thisElement->right);
2945 return thisElement->left->subTreeSize + index + 1;
2948 case PObject::GreaterThan :
2949 return InternalStringSelect(str, len, thisElement->left);
2951 default :
2952 info->lastElement = thisElement;
2953 return thisElement->left->subTreeSize;
2958 ///////////////////////////////////////////////////////////////////////////////
2960 PStringSet::PStringSet(PINDEX count, char const * const * strarr, BOOL caseless)
2962 if (count == 0)
2963 return;
2965 if (PAssertNULL(strarr) == NULL)
2966 return;
2968 for (PINDEX i = 0; i < count; i++) {
2969 if (caseless)
2970 Include(PCaselessString(strarr[i]));
2971 else
2972 Include(PString(strarr[i]));
2977 PStringSet::PStringSet(const PString & str)
2979 Include(str);
2983 void PStringSet::ReadFrom(istream & strm)
2985 while (strm.good()) {
2986 PString str;
2987 strm >> str;
2988 Include(str);
2993 ///////////////////////////////////////////////////////////////////////////////
2995 POrdinalToString::POrdinalToString(PINDEX count, const Initialiser * init)
2997 while (count-- > 0) {
2998 SetAt(init->key, init->value);
2999 init++;
3004 void POrdinalToString::ReadFrom(istream & strm)
3006 while (strm.good()) {
3007 POrdinalKey key;
3008 char equal;
3009 PString str;
3010 strm >> key >> ws >> equal >> str;
3011 if (equal != '=')
3012 SetAt(key, PString::Empty());
3013 else
3014 SetAt(key, str.Mid(equal+1));
3019 ///////////////////////////////////////////////////////////////////////////////
3021 PStringToOrdinal::PStringToOrdinal(PINDEX count,
3022 const Initialiser * init,
3023 BOOL caseless)
3025 while (count-- > 0) {
3026 if (caseless)
3027 SetAt(PCaselessString(init->key), init->value);
3028 else
3029 SetAt(init->key, init->value);
3030 init++;
3035 void PStringToOrdinal::ReadFrom(istream & strm)
3037 while (strm.good()) {
3038 PString str;
3039 strm >> str;
3040 PINDEX equal = str.FindLast('=');
3041 if (equal == P_MAX_INDEX)
3042 SetAt(str, 0);
3043 else
3044 SetAt(str.Left(equal), str.Mid(equal+1).AsInteger());
3049 ///////////////////////////////////////////////////////////////////////////////
3051 PStringToString::PStringToString(PINDEX count,
3052 const Initialiser * init,
3053 BOOL caselessKeys,
3054 BOOL caselessValues)
3056 while (count-- > 0) {
3057 if (caselessValues)
3058 if (caselessKeys)
3059 SetAt(PCaselessString(init->key), PCaselessString(init->value));
3060 else
3061 SetAt(init->key, PCaselessString(init->value));
3062 else
3063 if (caselessKeys)
3064 SetAt(PCaselessString(init->key), init->value);
3065 else
3066 SetAt(init->key, init->value);
3067 init++;
3072 void PStringToString::ReadFrom(istream & strm)
3074 while (strm.good()) {
3075 PString str;
3076 strm >> str;
3077 PINDEX equal = str.Find('=');
3078 if (equal == P_MAX_INDEX)
3079 SetAt(str, PString::Empty());
3080 else
3081 SetAt(str.Left(equal), str.Mid(equal+1));
3086 ///////////////////////////////////////////////////////////////////////////////
3088 PRegularExpression::PRegularExpression()
3090 lastError = NotCompiled;
3091 expression = NULL;
3092 flagsSaved = IgnoreCase;
3096 PRegularExpression::PRegularExpression(const PString & pattern, int flags)
3098 expression = NULL;
3099 Compile(pattern, flags);
3103 PRegularExpression::PRegularExpression(const char * pattern, int flags)
3105 expression = NULL;
3106 Compile(pattern, flags);
3109 PRegularExpression::PRegularExpression(const PRegularExpression & from)
3111 expression = NULL;
3112 patternSaved = from.patternSaved;
3113 flagsSaved = from.flagsSaved;
3114 Compile(patternSaved, flagsSaved);
3117 PRegularExpression & PRegularExpression::operator =(const PRegularExpression & from)
3119 expression = NULL;
3120 patternSaved = from.patternSaved;
3121 flagsSaved = from.flagsSaved;
3122 Compile(patternSaved, flagsSaved);
3123 return *this;
3126 PRegularExpression::~PRegularExpression()
3128 if (expression != NULL) {
3129 regfree(regexpression);
3130 delete regexpression;
3135 PRegularExpression::ErrorCodes PRegularExpression::GetErrorCode() const
3137 return (ErrorCodes)lastError;
3141 PString PRegularExpression::GetErrorText() const
3143 PString str;
3144 regerror(lastError, regexpression, str.GetPointer(256), 256);
3145 return str;
3149 BOOL PRegularExpression::Compile(const PString & pattern, int flags)
3151 return Compile((const char *)pattern, flags);
3155 BOOL PRegularExpression::Compile(const char * pattern, int flags)
3157 patternSaved = pattern;
3158 flagsSaved = flags;
3160 if (expression != NULL) {
3161 regfree(regexpression);
3162 delete regexpression;
3163 expression = NULL;
3165 if (pattern == NULL || *pattern == '\0')
3166 lastError = BadPattern;
3167 else {
3168 expression = new regex_t;
3169 lastError = regcomp(regexpression, pattern, flags);
3171 return lastError == NoError;
3175 BOOL PRegularExpression::Execute(const PString & str, PINDEX & start, int flags) const
3177 PINDEX dummy;
3178 return Execute((const char *)str, start, dummy, flags);
3182 BOOL PRegularExpression::Execute(const PString & str, PINDEX & start, PINDEX & len, int flags) const
3184 return Execute((const char *)str, start, len, flags);
3188 BOOL PRegularExpression::Execute(const char * cstr, PINDEX & start, int flags) const
3190 PINDEX dummy;
3191 return Execute(cstr, start, dummy, flags);
3195 BOOL PRegularExpression::Execute(const char * cstr, PINDEX & start, PINDEX & len, int flags) const
3197 if (expression == NULL) {
3198 ((PRegularExpression*)this)->lastError = NotCompiled;
3199 return FALSE;
3202 regmatch_t match;
3204 ((PRegularExpression*)this)->lastError = regexec(regexpression, cstr, 1, &match, flags);
3205 if (lastError != NoError)
3206 return FALSE;
3208 start = match.rm_so;
3209 len = match.rm_eo - start;
3210 return TRUE;
3214 BOOL PRegularExpression::Execute(const PString & str, PIntArray & starts, int flags) const
3216 PIntArray dummy;
3217 return Execute((const char *)str, starts, dummy, flags);
3221 BOOL PRegularExpression::Execute(const PString & str,
3222 PIntArray & starts,
3223 PIntArray & ends,
3224 int flags) const
3226 return Execute((const char *)str, starts, ends, flags);
3230 BOOL PRegularExpression::Execute(const char * cstr, PIntArray & starts, int flags) const
3232 PIntArray dummy;
3233 return Execute(cstr, starts, dummy, flags);
3237 BOOL PRegularExpression::Execute(const char * cstr,
3238 PIntArray & starts,
3239 PIntArray & ends,
3240 int flags) const
3242 if (expression == NULL) {
3243 ((PRegularExpression*)this)->lastError = NotCompiled;
3244 return FALSE;
3247 regmatch_t single_match;
3248 regmatch_t * matches = &single_match;
3250 PINDEX count = starts.GetSize();
3251 if (count > 1)
3252 matches = new regmatch_t[count];
3253 else
3254 count = 1;
3256 ((PRegularExpression*)this)->lastError = regexec(regexpression, cstr, count, matches, flags);
3258 if (lastError == NoError) {
3259 starts.SetMinSize(count);
3260 ends.SetMinSize(count);
3261 for (PINDEX i = 0; i < count; i++) {
3262 starts[i] = matches[i].rm_so;
3263 ends[i] = matches[i].rm_eo;
3267 if (matches != &single_match)
3268 delete [] matches;
3270 return lastError == NoError;
3274 PString PRegularExpression::EscapeString(const PString & str)
3276 PString translated;
3278 PINDEX lastPos = 0;
3279 PINDEX nextPos;
3280 while ((nextPos = str.FindOneOf("\\^$+?*.[]()|{}", lastPos+1)) != P_MAX_INDEX) {
3281 translated += str(lastPos, nextPos-1) + "\\";
3282 lastPos = nextPos;
3285 if (lastPos == 0)
3286 return str;
3288 return translated + str.Mid(lastPos);
3292 // End Of File ///////////////////////////////////////////////////////////////