contain.cxx
上传用户:hzhsqp
上传日期:2007-01-06
资源大小:1600k
文件大小:54k
源码类别:

IP电话/视频会议

开发平台:

Visual C++

  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.  * $Log: contain.cxx,v $
  30.  * Revision 1.87  2000/06/26 11:17:20  robertj
  31.  * Nucleus++ port (incomplete).
  32.  *
  33.  * Revision 1.86  2000/04/07 06:29:46  rogerh
  34.  * Add a short term workaround for an Internal Compiler Error on MAC OS X when
  35.  * returning certain types of PString. Submitted by Kevin Packard.
  36.  *
  37.  * Revision 1.85  2000/02/05 22:36:09  craigs
  38.  * Fixed problem caused by last modification
  39.  *
  40.  * Revision 1.84  2000/02/04 19:34:26  craigs
  41.  * Fixed problem with changing size of referenced objects
  42.  *
  43.  * Revision 1.83  2000/01/25 14:05:35  robertj
  44.  * Added optimisation to array comparisons if referencing same array.
  45.  *
  46.  * Revision 1.82  1999/08/18 01:45:13  robertj
  47.  * Added concatenation function to "base type" arrays.
  48.  *
  49.  * Revision 1.81  1999/08/17 03:46:40  robertj
  50.  * Fixed usage of inlines in optimised version.
  51.  *
  52.  * Revision 1.80  1999/08/12 12:12:47  robertj
  53.  * GCC 2.95 compatibility.
  54.  *
  55.  * Revision 1.79  1999/05/28 14:01:53  robertj
  56.  * Added initialisers to string containers (list, sorted list and set).
  57.  *
  58.  * Revision 1.78  1999/04/18 09:36:31  robertj
  59.  * Get date grammar build.
  60.  *
  61.  * Revision 1.77  1999/04/16 14:38:37  craigs
  62.  * Changes to make getdate.y compile under Linux
  63.  *
  64.  * Revision 1.76  1998/10/28 00:58:40  robertj
  65.  * Changed PStringStream so flush or endl does not clear the string output, this now
  66.  *    just sets the string to minimum size.
  67.  *
  68.  * Revision 1.75  1998/10/13 14:06:18  robertj
  69.  * Complete rewrite of memory leak detection code.
  70.  *
  71.  * Revision 1.74  1998/09/23 06:21:54  robertj
  72.  * Added open source copyright license.
  73.  *
  74.  * Revision 1.73  1998/09/22 02:42:39  robertj
  75.  * Fixed problem treating unsigned integer as signed in PString contructor.
  76.  *
  77.  * Revision 1.72  1998/09/15 08:26:42  robertj
  78.  * Fixed a number of warnings at maximum optimisation.
  79.  *
  80.  * Revision 1.71  1998/09/14 12:36:29  robertj
  81.  * Fixed bug causing memory leak due to uninitialised member variable for dynamic allocation of arrays.
  82.  *
  83.  * Revision 1.70  1998/08/21 05:24:07  robertj
  84.  * Added hex dump capability to base array types.
  85.  * Added ability to have base arrays of static memory blocks.
  86.  *
  87.  * Revision 1.69  1998/03/17 10:13:23  robertj
  88.  * Fixed bug in Trim() should do all white space not just the space character.
  89.  *
  90.  * Revision 1.68  1998/01/26 00:37:48  robertj
  91.  * Fixed PString & operator putting space in if right hand side is empty string, it shouldn't..
  92.  * Added Execute() functions to PRegularExpression that take PINDEX references instead of PIntArrays.
  93.  * Added FindRegEx function to PString that returns position and length.
  94.  *
  95.  * Revision 1.67  1997/12/11 13:32:49  robertj
  96.  * Added AsUnsigned() function to convert string to DWORD.
  97.  *
  98.  * Revision 1.66  1997/07/08 13:14:41  robertj
  99.  * Fixed bug where freeing null pointer.
  100.  *
  101.  * Revision 1.65  1997/06/08 04:48:04  robertj
  102.  * Added regular expressions.
  103.  *
  104.  * Revision 1.64  1997/03/02 03:41:42  robertj
  105.  * Fixed bug in not being able to construct a zero length PStringArray.
  106.  *
  107.  * Revision 1.63  1996/10/08 13:13:25  robertj
  108.  * Added operator += and &= for char so no implicit PString construction.
  109.  *
  110.  * Revision 1.62  1996/09/14 12:45:57  robertj
  111.  * Fixed bug in PString::Splice() function, no end of string put in.
  112.  *
  113.  * Revision 1.61  1996/08/22 13:21:55  robertj
  114.  * Fixed major bug in FindLast(), could scan all of memory in negative direction.
  115.  *
  116.  * Revision 1.60  1996/08/08 10:08:45  robertj
  117.  * Directory structure changes for common files.
  118.  *
  119.  * Revision 1.59  1996/05/26 03:46:27  robertj
  120.  * Compatibility to GNU 2.7.x
  121.  *
  122.  * Revision 1.58  1996/05/15 10:17:02  robertj
  123.  * Fixed idiotic bug in string compare, caseless version always matched.
  124.  *
  125.  * Revision 1.57  1996/05/09 12:17:10  robertj
  126.  * Fixed incorrect use of memcmp/strcmp return value.
  127.  * Added assertion when finding empty string.
  128.  *
  129.  * Revision 1.56  1996/04/14 02:52:39  robertj
  130.  * Fixed bug in PString::FindLast(), never found sub-strings.
  131.  *
  132.  * Revision 1.55  1996/03/31 08:58:49  robertj
  133.  * Fixed hash function for strings to work for caseless strings.
  134.  *
  135.  * Revision 1.54  1996/03/16 04:56:59  robertj
  136.  * Fixed bug in PStringStream assignment oeprator getting pointers wrong.
  137.  *
  138.  * Revision 1.53  1996/03/02 03:20:11  robertj
  139.  * Fixed bug in PString::Find() not finding substring if exactly same as string.
  140.  *
  141.  * Revision 1.52  1996/02/22 10:23:54  robertj
  142.  * Fixed buf in *= operator only comparing up to shortest string.
  143.  * Fixed bug in & operator for if left string is empty.
  144.  *
  145.  * Revision 1.51  1996/02/19 13:34:53  robertj
  146.  * Removed PCaselessString hash function to fix dictionary match failure.
  147.  * Fixed *= operator yet again.
  148.  *
  149.  * Revision 1.50  1996/02/08 12:20:44  robertj
  150.  * Added new operators to PString for case insensitive compare and spaced concatenate.
  151.  * Fixed bug in Find() not finding case insensitive substrings.
  152.  *
  153.  * Revision 1.49  1996/02/03 11:08:51  robertj
  154.  * Changed memcpy to memove to guarentee string operations will work correctly
  155.  *    when moving overlapping strings around eg in PString::Splice().
  156.  *
  157.  * Revision 1.48  1996/01/28 14:12:22  robertj
  158.  * Fixed bug in Tokenise() for first token empty and PINDEX unsigned.
  159.  *
  160.  * Revision 1.47  1996/01/28 02:53:40  robertj
  161.  * Added assert into all Compare functions to assure comparison between compatible objects.
  162.  * Fixed bug in Find() function, subset sum calculation added one to many bytes.
  163.  *
  164.  * Revision 1.46  1996/01/24 14:43:19  robertj
  165.  * Added initialisers to string dictionaries.
  166.  *
  167.  * Revision 1.45  1996/01/23 13:17:38  robertj
  168.  * Added Replace() function to strings.
  169.  * String searching algorithm rewrite.
  170.  *
  171.  * Revision 1.44  1996/01/02 12:51:05  robertj
  172.  * Mac OS compatibility changes.
  173.  * Removed requirement that PArray elements have parameterless constructor..
  174.  *
  175.  * Revision 1.43  1995/10/14 15:07:42  robertj
  176.  * Changed arrays to not break references, but strings still need to.
  177.  *
  178.  * Revision 1.42  1995/06/17 00:46:20  robertj
  179.  * Added flag for PStringArray constructor to create caseless strings.
  180.  * Fixed bug in arrays when size set to zero.
  181.  *
  182.  * Revision 1.41  1995/06/04 12:39:59  robertj
  183.  * Made char * array all const in PStringArray constructor.
  184.  *
  185.  * Revision 1.40  1995/04/25 11:29:38  robertj
  186.  * Fixed Borland compiler warnings.
  187.  *
  188.  * Revision 1.39  1995/04/02 09:27:27  robertj
  189.  * Added "balloon" help.
  190.  *
  191.  * Revision 1.38  1995/03/12 04:46:02  robertj
  192.  * Fixed use of PCaselessString as dictionary key.
  193.  *
  194.  * Revision 1.37  1995/01/15  04:56:28  robertj
  195.  * Fixed PStringStream for correct pointer calculations in output.
  196.  *
  197.  * Revision 1.36  1995/01/10  11:44:13  robertj
  198.  * Removed PString parameter in stdarg function for GNU C++ compatibility.
  199.  *
  200.  * Revision 1.35  1995/01/09  12:32:56  robertj
  201.  * Removed unnecesary return value from I/O functions.
  202.  * Changed function names due to Mac port.
  203.  *
  204.  * Revision 1.34  1995/01/04  10:57:08  robertj
  205.  * Changed for HPUX and GNU2.6.x
  206.  *
  207.  * Revision 1.33  1995/01/03  09:39:08  robertj
  208.  * Put standard malloc style memory allocation etc into memory check system.
  209.  *
  210.  * Revision 1.32  1994/12/13  11:50:56  robertj
  211.  * Added MakeUnique() function to all container classes.
  212.  *
  213.  * Revision 1.31  1994/12/12  13:13:17  robertj
  214.  * Fixed bugs in PString mods just made.
  215.  *
  216.  * Revision 1.30  1994/12/12  10:16:27  robertj
  217.  * Restructuring and documentation of container classes.
  218.  * Renaming of some macros for declaring container classes.
  219.  * Added some extra functionality to PString.
  220.  * Added start to 2 byte characters in PString.
  221.  * Fixed incorrect overrides in PCaselessString.
  222.  *
  223.  * Revision 1.29  1994/12/05  11:19:36  robertj
  224.  * Moved SetMinSize from PAbstractArray to PContainer.
  225.  *
  226.  * Revision 1.28  1994/11/28  12:37:29  robertj
  227.  * Added dummy parameter to container classes.
  228.  *
  229.  * Revision 1.27  1994/10/30  11:50:44  robertj
  230.  * Split into Object classes and Container classes.
  231.  * Changed mechanism for doing notification callback functions.
  232.  *
  233.  * Revision 1.26  1994/10/23  03:43:07  robertj
  234.  * Changed PBaseArray so can have zero elements in it.
  235.  * Added Printf style constructor to PString.
  236.  *
  237.  * Revision 1.25  1994/09/25  10:49:44  robertj
  238.  * Added empty functions for serialisation.
  239.  *
  240.  * Revision 1.24  1994/08/21  23:43:02  robertj
  241.  * Added object serialisation classes.
  242.  * Changed parameter before variable argument list to NOT be a reference.
  243.  *
  244.  * Revision 1.23  1994/08/04  12:57:10  robertj
  245.  * Rewrite of memory check code.
  246.  *
  247.  * Revision 1.22  1994/08/01  03:40:28  robertj
  248.  * Fixed PString() constructor from integer
  249.  *
  250.  * Revision 1.21  1994/07/27  05:58:07  robertj
  251.  * Synchronisation.
  252.  *
  253.  * Revision 1.20  1994/07/25  03:38:38  robertj
  254.  * Added more memory tests.
  255.  *
  256.  * Revision 1.19  1994/07/17  10:46:06  robertj
  257.  * Added number conversions to PString.
  258.  *
  259.  * Revision 1.18  1994/06/25  11:55:15  robertj
  260.  * Unix version synchronisation.
  261.  *
  262.  * Revision 1.17  1994/04/20  12:17:44  robertj
  263.  * assert changes
  264.  *
  265.  * Revision 1.16  1994/04/11  12:08:37  robertj
  266.  * Fixed bug in memory leak hash table hash function, cant have negative numbers.
  267.  *
  268.  * Revision 1.15  1994/04/03  08:34:18  robertj
  269.  * Added help and focus functionality.
  270.  *
  271.  * Revision 1.14  1994/04/01  14:01:11  robertj
  272.  * Streams and stuff.
  273.  *
  274.  * Revision 1.13  1994/03/07  07:47:00  robertj
  275.  * Major upgrade
  276.  *
  277.  * Revision 1.12  1994/01/15  03:14:22  robertj
  278.  * Mac portability problems.
  279.  *
  280.  * Revision 1.11  1994/01/03  04:42:23  robertj
  281.  * Mass changes to common container classes and interactors etc etc etc.
  282.  *
  283.  * Revision 1.10  1993/12/31  06:53:02  robertj
  284.  * Made inlines optional for debugging purposes.
  285.  *
  286.  * Revision 1.9  1993/12/24  04:20:52  robertj
  287.  * Mac CFront port.
  288.  *
  289.  * Revision 1.8  1993/12/16  00:51:46  robertj
  290.  * Made some container functions const.
  291.  *
  292.  * Revision 1.7  1993/12/15  21:10:10  robertj
  293.  * Fixed reference system used by container classes.
  294.  * Plugged memory leaks in PList and PSortedList.
  295.  *
  296.  * Revision 1.6  1993/12/14  18:44:56  robertj
  297.  * Added RemoveAll() function to collections.
  298.  * Fixed bug in list processing when being destroyed (removes the item being
  299.  *     deleted from the list before deleting it).
  300.  * Changed GetIndex() so does not assert if entry not in collection.
  301.  *
  302.  * Revision 1.5  1993/12/04  05:22:38  robertj
  303.  * Added more string functions.
  304.  *
  305.  * Revision 1.4  1993/09/27  16:35:25  robertj
  306.  * Fixed bugs in sorted list.
  307.  * Fixed compatibility problem with sprintf return value (SVR4).
  308.  * Change function for making string array to a constructor.
  309.  *
  310.  * Revision 1.3  1993/08/27  18:17:47  robertj
  311.  * Fixed bugs in PAbstractSortedList (including some formatting).
  312.  *
  313.  * Revision 1.2  1993/08/21  01:50:33  robertj
  314.  * Made Clone() function optional, default will assert if called.
  315.  *
  316.  * Revision 1.8  1993/08/01  14:05:27  robertj
  317.  * Added const to ToLower() and ToUpper() in the PString class.
  318.  *
  319.  * Revision 1.7  1993/07/16  14:40:55  robertj
  320.  * Added PString constructor for individual characters.
  321.  * Added string to C style literal format.
  322.  *
  323.  * Revision 1.6  1993/07/15  05:02:57  robertj
  324.  * Removed redundant word in PString enum for string types.
  325.  *
  326.  * Revision 1.5  1993/07/15  04:29:39  robertj
  327.  * Added new constructor to convert from other string formats.
  328.  * Fixed sprintf variable parameter list bug.
  329.  *
  330.  * Revision 1.4  1993/07/14  12:41:52  robertj
  331.  * Fixed comment leader.
  332.  *
  333.  * Revision 1.3  1993/07/14  02:06:34  robertj
  334.  * Fixed header comment for RCS.
  335.  */
  336. #include <ptlib.h>
  337. #include <ctype.h>
  338. #ifdef __NUCLEUS_PLUS__
  339. extern "C" int vsprintf(char *, const char *, va_list);
  340. #endif
  341. #ifndef __STDC__
  342. #define __STDC__ 1
  343. #endif
  344. #include "regex.h"
  345. #if !P_USE_INLINES
  346. #include "ptlib/contain.inl"
  347. #endif
  348. #define new PNEW
  349. ///////////////////////////////////////////////////////////////////////////////
  350. PContainer::PContainer(PINDEX initialSize)
  351. {
  352.   reference = new Reference(initialSize);
  353.   PAssertNULL(reference);
  354. }
  355. PContainer::PContainer(int, const PContainer * cont)
  356. {
  357.   reference = new Reference(0);
  358.   *PAssertNULL(reference) = *cont->reference;
  359. }
  360. PContainer::PContainer(const PContainer & cont)
  361. {                                                            
  362.   reference = PAssertNULL(cont.reference);
  363.   reference->count++;
  364. }
  365. PContainer & PContainer::operator=(const PContainer & cont)
  366. {
  367.   if (reference != cont.reference) {
  368.     if (!IsUnique())
  369.       reference->count--;
  370.     else {
  371.       DestroyContents();
  372.       delete reference;
  373.     }
  374.   
  375.     reference = PAssertNULL(cont.reference);
  376.     reference->count++;
  377.   }
  378.   return *this;
  379. }
  380. void PContainer::Destruct()
  381. {
  382.   if (reference != NULL) {
  383.     if (reference->count > 1)
  384.       reference->count--;
  385.     else {
  386.       DestroyContents();
  387.       delete reference;
  388.     }
  389.     reference = NULL;
  390.   }
  391. }
  392. BOOL PContainer::SetMinSize(PINDEX minSize)
  393. {
  394.   PASSERTINDEX(minSize);
  395.   if (minSize < GetSize())
  396.     minSize = GetSize();
  397.   return SetSize(minSize);
  398. }
  399. BOOL PContainer::MakeUnique()
  400. {
  401.   if (IsUnique())
  402.     return TRUE;
  403.   reference->count--;
  404.   reference = new Reference(GetSize());
  405.   return FALSE;
  406. }
  407. ///////////////////////////////////////////////////////////////////////////////
  408. PAbstractArray::PAbstractArray(PINDEX elementSizeInBytes, PINDEX initialSize)
  409.   : PContainer(initialSize)
  410. {
  411.   elementSize = elementSizeInBytes;
  412.   PAssert(elementSize != 0, PInvalidParameter);
  413.   if (GetSize() == 0)
  414.     theArray = NULL;
  415.   else
  416.     theArray = (char *)calloc(GetSize(), elementSize);
  417.   allocatedDynamically = TRUE;
  418. }
  419. PAbstractArray::PAbstractArray(PINDEX elementSizeInBytes,
  420.                                const void *buffer,
  421.                                PINDEX bufferSizeInElements,
  422.                                BOOL dynamicAllocation)
  423.   : PContainer(bufferSizeInElements)
  424. {
  425.   elementSize = elementSizeInBytes;
  426.   PAssert(elementSize != 0, PInvalidParameter);
  427.   allocatedDynamically = dynamicAllocation;
  428.   if (GetSize() == 0)
  429.     theArray = NULL;
  430.   else if (dynamicAllocation) {
  431.     PINDEX sizebytes = elementSize*GetSize();
  432.     theArray = (char *)malloc(sizebytes);
  433.     memcpy(theArray, PAssertNULL(buffer), sizebytes);
  434.   }
  435.   else
  436.     theArray = (char *)buffer;
  437. }
  438. void PAbstractArray::DestroyContents()
  439. {
  440.   if (theArray != NULL) {
  441.     if (allocatedDynamically)
  442.       free(theArray);
  443.     theArray = NULL;
  444.   }
  445. }
  446. void PAbstractArray::CopyContents(const PAbstractArray & array)
  447. {
  448.   elementSize = array.elementSize;
  449.   theArray = array.theArray;
  450.   allocatedDynamically = array.allocatedDynamically;
  451. }
  452. void PAbstractArray::CloneContents(const PAbstractArray * array)
  453. {
  454.   elementSize = array->elementSize;
  455.   PINDEX sizebytes = elementSize*GetSize();
  456.   char * newArray = (char *)malloc(sizebytes);
  457.   if (newArray == NULL)
  458.     reference->size = 0;
  459.   else
  460.     memcpy(newArray, array->theArray, sizebytes);
  461.   theArray = newArray;
  462.   allocatedDynamically = TRUE;
  463. }
  464. PObject::Comparison PAbstractArray::Compare(const PObject & obj) const
  465. {
  466.   PAssert(obj.IsDescendant(PAbstractArray::Class()), PInvalidCast);
  467.   const PAbstractArray & other = (const PAbstractArray &)obj;
  468.   char * otherArray = other.theArray;
  469.   if (theArray == otherArray)
  470.     return EqualTo;
  471.   if (elementSize < other.elementSize)
  472.     return LessThan;
  473.   if (elementSize > other.elementSize)
  474.     return GreaterThan;
  475.   PINDEX thisSize = GetSize();
  476.   PINDEX otherSize = other.GetSize();
  477.   if (thisSize < otherSize)
  478.     return LessThan;
  479.   if (thisSize > otherSize)
  480.     return GreaterThan;
  481.   if (thisSize == 0)
  482.     return EqualTo;
  483.   int retval = memcmp(theArray, otherArray, elementSize*thisSize);
  484.   if (retval < 0)
  485.     return LessThan;
  486.   if (retval > 0)
  487.     return GreaterThan;
  488.   return EqualTo;
  489. }
  490. BOOL PAbstractArray::SetSize(PINDEX newSize)
  491. {
  492.   PINDEX newsizebytes = elementSize*newSize;
  493.   PINDEX oldsizebytes = elementSize*GetSize();
  494.   char * newArray;
  495.   if (!IsUnique()) {
  496.     if (newsizebytes == 0)
  497.       newArray = NULL;
  498.     else {
  499.       if ((newArray = (char *)malloc(newsizebytes)) == NULL)
  500.         return FALSE;
  501.   
  502.       if (theArray != NULL)
  503.         memcpy(newArray, theArray, PMIN(oldsizebytes, newsizebytes));
  504.     }
  505.     reference->count--;
  506.     reference = new Reference(newSize);
  507.   } else {
  508.     if (newsizebytes == oldsizebytes)
  509.       return TRUE;
  510.     if (theArray != NULL) {
  511.       if (newsizebytes == 0) {
  512.         if (allocatedDynamically)
  513.           free(theArray);
  514.         newArray = NULL;
  515.       }
  516.       else if (allocatedDynamically) {
  517.         if ((newArray = (char *)realloc(theArray, newsizebytes)) == NULL)
  518.           return FALSE;
  519.       }
  520.       else {
  521.         if ((newArray = (char *)malloc(newsizebytes)) == NULL)
  522.           return FALSE;
  523.         memcpy(newArray, theArray, PMIN(newsizebytes, oldsizebytes));
  524.         allocatedDynamically = TRUE;
  525.       }
  526.     }
  527.     else if (newsizebytes != 0) {
  528.       if ((newArray = (char *)malloc(newsizebytes)) == NULL)
  529.         return FALSE;
  530.     }
  531.     else
  532.       newArray = NULL;
  533.     reference->size = newSize;
  534.   }
  535.   if (newsizebytes > oldsizebytes)
  536.     memset(newArray+oldsizebytes, 0, newsizebytes-oldsizebytes);
  537.   theArray = newArray;
  538.   return TRUE;
  539. }
  540. void PAbstractArray::Attach(const void *buffer, PINDEX bufferSize)
  541. {
  542.   if (allocatedDynamically && theArray != NULL)
  543.     free(theArray);
  544.   theArray = (char *)buffer;
  545.   reference->size = bufferSize;
  546.   allocatedDynamically = FALSE;
  547. }
  548. void * PAbstractArray::GetPointer(PINDEX minSize)
  549. {
  550.   PAssert(SetMinSize(minSize), POutOfMemory);
  551.   return theArray;
  552. }
  553. BOOL PAbstractArray::Concatenate(const PAbstractArray & array)
  554. {
  555.   if (!allocatedDynamically || array.elementSize != elementSize)
  556.     return FALSE;
  557.   PINDEX oldLen = GetSize();
  558.   PINDEX addLen = array.GetSize();
  559.   if (!SetSize(oldLen + addLen))
  560.     return FALSE;
  561.   memcpy(theArray+oldLen*elementSize, array.theArray, addLen*elementSize);
  562.   return TRUE;
  563. }
  564. void PAbstractArray::PrintNumbersOn(ostream & strm, PINDEX size, BOOL is_signed) const
  565. {
  566.   PINDEX line_width = strm.width();
  567.   if (line_width == 0)
  568.     line_width = 16/size;
  569.   PINDEX indent = strm.precision();
  570.   PINDEX val_width;
  571.   switch (strm.flags()&ios::basefield) {
  572.     case ios::hex :
  573.       val_width = size*2;
  574.       is_signed = FALSE;
  575.       break;
  576.     case ios::oct :
  577.       val_width = ((size*8)+2)/3;
  578.       is_signed = FALSE;
  579.       break;
  580.     default :
  581.       switch (size) {
  582.         case 1 :
  583.           val_width = 3;
  584.           break;
  585.         case 2 :
  586.           val_width = 5;
  587.           break;
  588.         default :
  589.           val_width = 10;
  590.           break;
  591.       }
  592.       if (is_signed)
  593.         val_width++;
  594.   }
  595.   long mask = -1;
  596.   if (size < sizeof(mask))
  597.     mask = (1L << (size*8)) - 1;
  598.   PINDEX i = 0;
  599.   while (i < GetSize()) {
  600.     if (i > 0)
  601.       strm << 'n';
  602.     PINDEX j;
  603.     for (j = 0; j < indent; j++)
  604.       strm.put(' ');
  605.     for (j = 0; j < line_width; j++) {
  606.       if (j == line_width/2)
  607.         strm.put(' ');
  608.       if (i+j < GetSize()) {
  609.         strm << setw(val_width);
  610.         if (is_signed)
  611.           strm << GetNumberValueAt(i+j);
  612.         else
  613.           strm << (DWORD)(GetNumberValueAt(i+j)&mask);
  614.       }
  615.       else {
  616.         PINDEX k;
  617.         for (k = 0; k < val_width; k++)
  618.           strm.put(' ');
  619.       }
  620.       strm << ' ';
  621.     }
  622.     strm << "  ";
  623.     for (j = 0; j < line_width; j++) {
  624.       if (i+j < GetSize()) {
  625.         long val = GetNumberValueAt(i+j);
  626.         if (val >= 0 && val < 256 && isprint(val))
  627.           strm << (char)val;
  628.         else
  629.           strm << '.';
  630.       }
  631.     }
  632.     i += line_width;
  633.   }
  634. }
  635. long PAbstractArray::GetNumberValueAt(PINDEX) const
  636. {
  637.   PAssertAlways(PUnimplementedFunction);
  638.   return 0;
  639. }
  640. ///////////////////////////////////////////////////////////////////////////////
  641. void PCharArray::PrintOn(ostream & strm) const
  642. {
  643.   PINDEX width = strm.width();
  644.   if (width > GetSize())
  645.     width -= GetSize();
  646.   else
  647.     width = 0;
  648.   BOOL left = (strm.flags()&ios::adjustfield) == ios::left;
  649.   if (left)
  650.     strm.write(theArray, GetSize());
  651.   while (width-- > 0)
  652.     strm.put(strm.fill());
  653.   if (!left)
  654.     strm.write(theArray, GetSize());
  655. }
  656. void PShortArray::PrintOn(ostream & strm) const
  657. {
  658.   PrintNumbersOn(strm, sizeof(short), TRUE);
  659. }
  660. long PShortArray::GetNumberValueAt(PINDEX idx) const
  661. {
  662.   return ((short *)theArray)[idx];
  663. }
  664. void PIntArray::PrintOn(ostream & strm) const
  665. {
  666.   PrintNumbersOn(strm, sizeof(int), TRUE);
  667. }
  668. long PIntArray::GetNumberValueAt(PINDEX idx) const
  669. {
  670.   return ((int *)theArray)[idx];
  671. }
  672. void PLongArray::PrintOn(ostream & strm) const
  673. {
  674.   PrintNumbersOn(strm, sizeof(long), TRUE);
  675. }
  676. long PLongArray::GetNumberValueAt(PINDEX idx) const
  677. {
  678.   return ((long *)theArray)[idx];
  679. }
  680. void PBYTEArray::PrintOn(ostream & strm) const
  681. {
  682.   PrintNumbersOn(strm, sizeof(BYTE), FALSE);
  683. }
  684. long PBYTEArray::GetNumberValueAt(PINDEX idx) const
  685. {
  686.   return ((BYTE *)theArray)[idx];
  687. }
  688. void PWORDArray::PrintOn(ostream & strm) const
  689. {
  690.   PrintNumbersOn(strm, sizeof(WORD), FALSE);
  691. }
  692. long PWORDArray::GetNumberValueAt(PINDEX idx) const
  693. {
  694.   return ((WORD *)theArray)[idx];
  695. }
  696. void PUnsignedArray::PrintOn(ostream & strm) const
  697. {
  698.   PrintNumbersOn(strm, sizeof(unsigned), FALSE);
  699. }
  700. long PUnsignedArray::GetNumberValueAt(PINDEX idx) const
  701. {
  702.   return ((unsigned *)theArray)[idx];
  703. }
  704. void PDWORDArray::PrintOn(ostream & strm) const
  705. {
  706.   PrintNumbersOn(strm, sizeof(DWORD), FALSE);
  707. }
  708. long PDWORDArray::GetNumberValueAt(PINDEX idx) const
  709. {
  710.   return ((DWORD *)theArray)[idx];
  711. }
  712. ///////////////////////////////////////////////////////////////////////////////
  713. #ifdef PHAS_UNICODE
  714. #define PSTRING_COPY(d, s, l) UnicodeCopy((WORD *)(d), (s), (l))
  715. #define PSTRING_MOVE(d, doff, s, soff, l) 
  716.             memmove(((WORD*)(d))+(doff), ((WORD*)(s))+(soff), (l)*sizeof(WORD))
  717. static void UnicodeCopy(WORD * theArray, char * src, size_t len)
  718. {
  719.   while (len-- > 0)
  720.     *theArray++ = *src++;
  721. }
  722. #else
  723. #define PSTRING_COPY(d, s, l) memcpy((d), (s), (l))
  724. #define PSTRING_MOVE(d, doff, s, soff, l) memmove((d)+(doff), (s)+(soff), (l))
  725. #endif
  726. PString::PString(const char * cstr)
  727.   : PSTRING_ANCESTOR_CLASS(strlen(PAssertNULL(cstr))+1)
  728. {
  729.   PSTRING_COPY(theArray, cstr, GetSize());
  730. }
  731. PString::PString(const WORD * ustr)
  732. {
  733.   const WORD * ptr = PAssertNULL(ustr);
  734.   PINDEX len = 0;
  735.   while (*ptr++ != 0)
  736.     len++;
  737.   SetSize(len+1);
  738. #ifdef PHAS_UNICODE
  739.   memcpy(theArray, ustr, len*sizeof(WORD))
  740. #else
  741.   char * cstr = theArray;
  742.   while (len-- > 0)
  743.     *cstr++ = (char)*ustr++;
  744. #endif
  745. }
  746. PString::PString(const char * cstr, PINDEX len)
  747.   : PSTRING_ANCESTOR_CLASS(len+1)
  748. {
  749.   PSTRING_COPY(theArray, PAssertNULL(cstr), len);
  750. }
  751. PString::PString(const WORD * ustr, PINDEX len)
  752.   : PSTRING_ANCESTOR_CLASS(len+1)
  753. {
  754.   PAssertNULL(ustr);
  755. #ifdef PHAS_UNICODE
  756.   memcpy(theArray, ustr, len*sizeof(WORD))
  757. #else
  758.   char * cstr = theArray;
  759.   while (len-- > 0)
  760.     *cstr++ = (char)*ustr++;
  761. #endif
  762. }
  763. static int TranslateHex(char x)
  764. {
  765.   if (x >= 'a')
  766.     return x - 'a' + 10;
  767.   if (x >= 'A')
  768.     return x - 'A' + 'x0a';
  769.   return x - '0';
  770. }
  771. static const char PStringEscapeCode[]  = {  'a',  'b',  'f',  'n',  'r',  't',  'v' };
  772. static const char PStringEscapeValue[] = { 'a', 'b', 'f', 'n', 'r', 't', 'v' };
  773. static void TranslateEscapes(const char * src, char * dst)
  774. {
  775.   if (*src == '"')
  776.     src++;
  777.   while (*src != '') {
  778.     int c = *src++;
  779.     if (c == '"' && *src == '')
  780.       c  = ''; // Trailing '"' is ignored
  781.     else if (c == '\') {
  782.       c = *src++;
  783.       for (PINDEX i = 0; i < PARRAYSIZE(PStringEscapeCode); i++) {
  784.         if (c == PStringEscapeCode[i])
  785.           c = PStringEscapeValue[i];
  786.       }
  787.       if (c == 'x' && isxdigit(*src)) {
  788.         c = TranslateHex(*src++);
  789.         if (isxdigit(*src))
  790.           c = (c << 4) + TranslateHex(*src++);
  791.       }
  792.       else if (c >= '0' && c <= '7') {
  793.         int count = c <= '3' ? 3 : 2;
  794.         src--;
  795.         c = 0;
  796.         do {
  797.           c = (c << 3) + *src++ - '0';
  798.         } while (--count > 0 && *src >= '0' && *src <= '7');
  799.       }
  800.     }
  801.     *dst++ = (char)c;
  802.   }
  803. }
  804. PString::PString(ConversionType type, const char * str, ...)
  805. {
  806.   switch (type) {
  807.     case Pascal :
  808.       if (*str != '') {
  809.         PINDEX len = *str & 0xff;
  810.         PAssert(SetSize(len+1), POutOfMemory);
  811.         PSTRING_COPY(theArray, str+1, len);
  812.       }
  813.       break;
  814.     case Basic :
  815.       if (str[0] != '' && str[1] != '') {
  816.         PINDEX len = str[0] | (str[1] << 8);
  817.         PAssert(SetSize(len+1), POutOfMemory);
  818.         PSTRING_COPY(theArray, str+2, len);
  819.       }
  820.       break;
  821.     case Literal :
  822.       PAssert(SetSize(strlen(str)+1), POutOfMemory);
  823.       TranslateEscapes(str, theArray);
  824.       PAssert(MakeMinimumSize(), POutOfMemory);
  825.       break;
  826.     case Printf :
  827.       va_list args;
  828.       va_start(args, str);
  829.       vsprintf(str, args);
  830.       break;
  831.     default :
  832.       PAssertAlways(PInvalidParameter);
  833.   }
  834. }
  835. static char * ltostr(DWORD value, unsigned base, char * str)
  836. {
  837.   if (value >= base)
  838.     str = ltostr(value/base, base, str);
  839.   value %= base;
  840.   if (value < 10)
  841.     *str = (char)(value + '0');
  842.   else
  843.     *str = (char)(value + 'A'-10);
  844.   return str+1;
  845. }
  846. PString::PString(ConversionType type, long value, unsigned base)
  847.   : PCharArray(100)
  848. {
  849.   PAssert(base >= 2 && base <= 36, PInvalidParameter);
  850.   switch (type) {
  851.     case Signed :
  852.       if (value < 0) {
  853.         *theArray = '-';
  854.         ltostr(-value, base, theArray+1);
  855.         break;
  856.       }
  857.       // Otherwise do Unsigned case
  858.     case Unsigned :
  859.       ltostr(value, base, theArray);
  860.       break;
  861.     default :
  862.       PAssertAlways(PInvalidParameter);
  863.   }
  864.   MakeMinimumSize();
  865. }
  866. PString::PString(ConversionType type, double value, unsigned places)
  867. {
  868.   switch (type) {
  869.     case Decimal :
  870.       sprintf("%0.*f", (int)places, value);
  871.       break;
  872.     case Exponent :
  873.       sprintf("%0.*e", (int)places, value);
  874.       break;
  875.     default :
  876.       PAssertAlways(PInvalidParameter);
  877.   }
  878. }
  879. PString & PString::operator=(const char * cstr)
  880. {
  881.   PString pstr(cstr);
  882.   PCharArray::operator=(pstr);
  883.   return *this;
  884. }
  885. PString & PString::operator=(char ch)
  886. {
  887.   PString pstr(ch);
  888.   PCharArray::operator=(pstr);
  889.   return *this;
  890. }
  891. PObject * PString::Clone() const
  892. {
  893.   return new PString(*this);
  894. }
  895. void PString::PrintOn(ostream &strm) const
  896. {
  897.   strm << theArray;
  898. }
  899. void PString::ReadFrom(istream &strm)
  900. {
  901.   SetMinSize(100);
  902.   char * ptr = theArray;
  903.   PINDEX len = 0;
  904.   int c;
  905.   while ((c = strm.get()) != EOF && c != 'n') {
  906.     *ptr++ = (char)c;
  907.     len++;
  908.     if (len >= GetSize()) {
  909.       SetSize(len + 100);
  910.       ptr = theArray + len;
  911.     }
  912.   }
  913.   *ptr = '';
  914.   PAssert(MakeMinimumSize(), POutOfMemory);
  915. }
  916. PObject::Comparison PString::Compare(const PObject & obj) const
  917. {
  918.   PAssert(obj.IsDescendant(PString::Class()), PInvalidCast);
  919.   return InternalCompare(0, P_MAX_INDEX, ((const PString &)obj).theArray);
  920. }
  921. PINDEX PString::HashFunction() const
  922. {
  923. #ifdef PHAS_UNICODE
  924.   return (((WORD*)theArray)[0]+((WORD*)theArray)[1]+((WORD*)theArray)[2])%23;
  925. #else
  926.   return ((BYTE)toupper(theArray[0]) +
  927.           (BYTE)toupper(theArray[1]) +
  928.           (BYTE)toupper(theArray[2]))%23;
  929. #endif
  930. }
  931. BOOL PString::IsEmpty() const
  932. {
  933. #ifdef PHAS_UNICODE
  934.   return *(WORD*)theArray == '';
  935. #else
  936.   return *theArray == '';
  937. #endif
  938. }
  939. BOOL PString::SetSize(PINDEX newSize)
  940. {
  941.   return PAbstractArray::SetSize(newSize);
  942. #if 0
  943.   if (IsUnique())
  944.     return PAbstractArray::SetSize(newSize);
  945.   PINDEX newsizebytes = elementSize*newSize;
  946.   PINDEX oldsizebytes = elementSize*GetSize();
  947.   char * newArray;
  948.   if (newsizebytes == 0)
  949.     newArray = NULL;
  950.   else {
  951.     if ((newArray = (char *)malloc(newsizebytes)) == NULL)
  952.       return FALSE;
  953.     if (theArray != NULL)
  954.       memcpy(newArray, theArray, PMIN(oldsizebytes, newsizebytes));
  955.   }
  956.   reference->count--;
  957.   reference = new Reference(newSize);
  958.   if (newsizebytes > oldsizebytes)
  959.     memset(newArray+oldsizebytes, 0, newsizebytes-oldsizebytes);
  960.   theArray = newArray;
  961.   return TRUE;
  962. #endif
  963. }
  964. BOOL PString::MakeUnique()
  965. {
  966.   if (IsUnique())
  967.     return TRUE;
  968.   SetSize(GetSize());
  969.   return FALSE;
  970. }
  971. #ifdef PHAS_UNICODE
  972. PINDEX PString::GetLength() const
  973. {
  974.   for (len = 0; len < GetSize(); len++)
  975.     if (((WORD *)theArray)[len] == 0)
  976.       break;
  977.   return len;
  978. }
  979. #endif
  980. PString PString::operator+(const char * cstr) const
  981. {
  982.   PINDEX olen = GetLength();
  983.   PINDEX alen = strlen(PAssertNULL(cstr))+1;
  984.   PString str;
  985.   str.SetSize(olen+alen);
  986.   PSTRING_MOVE(str.theArray, 0, theArray, 0, olen);
  987.   PSTRING_COPY(str.theArray+olen, cstr, alen);
  988.   return str;
  989. }
  990. PString PString::operator+(char c) const
  991. {
  992.   PINDEX olen = GetLength();
  993.   PString str;
  994.   str.SetSize(olen+2);
  995.   PSTRING_MOVE(str.theArray, 0, theArray, 0, olen);
  996.   str.theArray[olen] = c;
  997.   return str;
  998. }
  999. PString & PString::operator+=(const char * cstr)
  1000. {
  1001.   PINDEX olen = GetLength();
  1002.   PINDEX alen = strlen(PAssertNULL(cstr))+1;
  1003.   SetSize(olen+alen);
  1004.   PSTRING_COPY(theArray+olen, cstr, alen);
  1005.   return *this;
  1006. }
  1007. PString & PString::operator+=(char ch)
  1008. {
  1009.   PINDEX olen = GetLength();
  1010.   SetSize(olen+2);
  1011.   theArray[olen] = ch;
  1012.   return *this;
  1013. }
  1014. PString PString::operator&(const char * cstr) const
  1015. {
  1016.   PINDEX alen = strlen(PAssertNULL(cstr))+1;
  1017.   if (alen == 1)
  1018.     return *this;
  1019.   PINDEX olen = GetLength();
  1020.   PString str;
  1021.   PINDEX space = olen > 0 && theArray[olen-1]!=' ' && *cstr!=' ' ? 1 : 0;
  1022.   str.SetSize(olen+alen+space);
  1023.   PSTRING_MOVE(str.theArray, 0, theArray, 0, olen);
  1024.   if (space != 0)
  1025.     str.theArray[olen] = ' ';
  1026.   PSTRING_COPY(str.theArray+olen+space, cstr, alen);
  1027.   return str;
  1028. }
  1029. PString PString::operator&(char c) const
  1030. {
  1031.   PINDEX olen = GetLength();
  1032.   PString str;
  1033.   PINDEX space = olen > 0 && theArray[olen-1] != ' ' && c != ' ' ? 1 : 0;
  1034.   str.SetSize(olen+2+space);
  1035.   PSTRING_MOVE(str.theArray, 0, theArray, 0, olen);
  1036.   if (space != 0)
  1037.     str.theArray[olen] = ' ';
  1038.   str.theArray[olen+space] = c;
  1039.   return str;
  1040. }
  1041. PString & PString::operator&=(const char * cstr)
  1042. {
  1043.   PINDEX alen = strlen(PAssertNULL(cstr))+1;
  1044.   if (alen == 1)
  1045.     return *this;
  1046.   PINDEX olen = GetLength();
  1047.   PINDEX space = olen > 0 && theArray[olen-1]!=' ' && *cstr!=' ' ? 1 : 0;
  1048.   SetSize(olen+alen+space);
  1049.   if (space != 0)
  1050.     theArray[olen] = ' ';
  1051.   PSTRING_COPY(theArray+olen+space, cstr, alen);
  1052.   return *this;
  1053. }
  1054. PString & PString::operator&=(char ch)
  1055. {
  1056.   PINDEX olen = GetLength();
  1057.   PINDEX space = olen > 0 && theArray[olen-1] != ' ' && ch != ' ' ? 1 : 0;
  1058.   SetSize(olen+2+space);
  1059.   if (space != 0)
  1060.     theArray[olen] = ' ';
  1061.   theArray[olen+space] = ch;
  1062.   return *this;
  1063. }
  1064. void PString::Delete(PINDEX start, PINDEX len)
  1065. {
  1066.   MakeUnique();
  1067.   register PINDEX slen = GetLength();
  1068.   if (start > slen)
  1069.     return;
  1070.   if (len > slen - start)
  1071.     SetAt(start, '');
  1072.   else
  1073.     PSTRING_MOVE(theArray, start, theArray, start+len, slen-start-len+1);
  1074.   MakeMinimumSize();
  1075. }
  1076. PString PString::operator()(PINDEX start, PINDEX end) const
  1077. {
  1078.   if (end < start)
  1079.     return PString();
  1080.   register PINDEX len = GetLength();
  1081.   if (start > len)
  1082.     return PString();
  1083.   if (end >= len) {
  1084.     if (start == 0)
  1085.       return *this;
  1086.     end = len-1;
  1087.   }
  1088.   len = end - start + 1;
  1089.   return PString(theArray+start, len);
  1090. }
  1091. PString PString::Left(PINDEX len) const
  1092. {
  1093.   if (len == 0)
  1094.     return PString();
  1095.   if (len >= GetLength())
  1096.     return *this;
  1097.   return PString(theArray, len);
  1098. }
  1099. PString PString::Right(PINDEX len) const
  1100. {
  1101.   if (len == 0)
  1102.     return PString();
  1103.   PINDEX srclen = GetLength();
  1104.   if (len >= srclen)
  1105.     return *this;
  1106.   return PString(theArray+srclen-len, len);
  1107. }
  1108. PString PString::Mid(PINDEX start, PINDEX len) const
  1109. {
  1110.   if (len == 0)
  1111.     return PString();
  1112.   if (start+len < start) // Beware of wraparound
  1113.     return operator()(start, P_MAX_INDEX);
  1114.   else
  1115.     return operator()(start, start+len-1);
  1116. }
  1117. BOOL PString::operator*=(const char * cstr) const
  1118. {
  1119.   PAssertNULL(cstr);
  1120.   const char * pstr = theArray;
  1121.   while (*pstr != '' && *cstr != '') {
  1122.     if (toupper(*pstr) != toupper(*cstr))
  1123.       return FALSE;
  1124.     pstr++;
  1125.     cstr++;
  1126.   }
  1127.   return *pstr == *cstr;
  1128. }
  1129. PObject::Comparison PString::InternalCompare(PINDEX offset, char c) const
  1130. {
  1131.   char ch = theArray[offset];
  1132.   if (ch < c)
  1133.     return LessThan;
  1134.   if (ch > c)
  1135.     return GreaterThan;
  1136.   return EqualTo;
  1137. }
  1138. PObject::Comparison PString::InternalCompare(
  1139.                          PINDEX offset, PINDEX length, const char * cstr) const
  1140. {
  1141.   if (offset == 0 && theArray == cstr)
  1142.     return EqualTo;
  1143.   int retval;
  1144.   if (length == P_MAX_INDEX)
  1145.     retval = strcmp(theArray+offset, PAssertNULL(cstr));
  1146.   else
  1147.     retval = strncmp(theArray+offset, PAssertNULL(cstr), length);
  1148.   if (retval < 0)
  1149.     return LessThan;
  1150.   if (retval > 0)
  1151.     return GreaterThan;
  1152.   return EqualTo;
  1153. }
  1154. PINDEX PString::Find(char ch, PINDEX offset) const
  1155. {
  1156.   register PINDEX len = GetLength();
  1157.   while (offset < len) {
  1158.     if (InternalCompare(offset, ch) == EqualTo)
  1159.       return offset;
  1160.     offset++;
  1161.   }
  1162.   return P_MAX_INDEX;
  1163. }
  1164. PINDEX PString::Find(const char * cstr, PINDEX offset) const
  1165. {
  1166.   PAssertNULL(cstr);
  1167.   PAssert(*cstr != '', PInvalidParameter);
  1168.   PINDEX len = GetLength();
  1169.   PINDEX clen = strlen(cstr);
  1170.   if (clen > len)
  1171.     return P_MAX_INDEX;
  1172.   if (offset > len - clen)
  1173.     return P_MAX_INDEX;
  1174.   if (len - clen < 10) {
  1175.     while (offset+clen <= len) {
  1176.       if (InternalCompare(offset, clen, cstr) == EqualTo)
  1177.         return offset;
  1178.       offset++;
  1179.     }
  1180.     return P_MAX_INDEX;
  1181.   }
  1182.   int strSum = 0;
  1183.   int cstrSum = 0;
  1184.   for (PINDEX i = 0; i < clen; i++) {
  1185.     strSum += toupper(theArray[offset+i]);
  1186.     cstrSum += toupper(cstr[i]);
  1187.   }
  1188.   // search for a matching substring
  1189.   while (offset+clen <= len) {
  1190.     if (strSum == cstrSum && InternalCompare(offset, clen, cstr) == EqualTo)
  1191.       return offset;
  1192.     strSum += toupper(theArray[offset+clen]);
  1193.     strSum -= toupper(theArray[offset++]);
  1194.   }
  1195.   return P_MAX_INDEX;
  1196. }
  1197. PINDEX PString::FindLast(char ch, PINDEX offset) const
  1198. {
  1199.   PINDEX len = GetLength();
  1200.   if (len == 0)
  1201.     return P_MAX_INDEX;
  1202.   if (offset >= len)
  1203.     offset = len-1;
  1204.   while (InternalCompare(offset, ch) != EqualTo) {
  1205.     if (offset == 0)
  1206.       return P_MAX_INDEX;
  1207.     offset--;
  1208.   }
  1209.   return offset;
  1210. }
  1211. PINDEX PString::FindLast(const char * cstr, PINDEX offset) const
  1212. {
  1213.   PAssertNULL(cstr);
  1214.   PAssert(*cstr != '', PInvalidParameter);
  1215.   PINDEX len = GetLength();
  1216.   PINDEX clen = strlen(cstr);
  1217.   if (clen > len)
  1218.     return P_MAX_INDEX;
  1219.   if (offset == 0)
  1220.     return P_MAX_INDEX;
  1221.   if (offset > len - clen)
  1222.     offset = len - clen;
  1223.   int strSum = 0;
  1224.   int cstrSum = 0;
  1225.   for (PINDEX i = 0; i < clen; i++) {
  1226.     strSum += toupper(theArray[offset+i]);
  1227.     cstrSum += toupper(cstr[i]);
  1228.   }
  1229.   // search for a matching substring
  1230.   while (offset > 0) {
  1231.     if (strSum == cstrSum && InternalCompare(offset, clen, cstr) == EqualTo)
  1232.       return offset;
  1233.     strSum += toupper(theArray[--offset]);
  1234.     strSum -= toupper(theArray[offset+clen]);
  1235.   }
  1236.   return P_MAX_INDEX;
  1237. }
  1238. PINDEX PString::FindOneOf(const char * cset, PINDEX offset) const
  1239. {
  1240.   PAssertNULL(cset);
  1241.   PINDEX len = GetLength();
  1242.   while (offset < len) {
  1243.     const char * p = cset;
  1244.     while (*p != '') {
  1245.       if (InternalCompare(offset, *p) == EqualTo)
  1246.         return offset;
  1247.       p++;
  1248.     }
  1249.     offset++;
  1250.   }
  1251.   return P_MAX_INDEX;
  1252. }
  1253. PINDEX PString::FindRegEx(const PRegularExpression & regex, PINDEX offset) const
  1254. {
  1255.   PINDEX pos = 0;
  1256.   PINDEX len = 0;
  1257.   if (FindRegEx(regex, pos, len, offset))
  1258.     return pos;
  1259.   return P_MAX_INDEX;
  1260. }
  1261. BOOL PString::FindRegEx(const PRegularExpression & regex,
  1262.                         PINDEX & pos,
  1263.                         PINDEX & len,
  1264.                         PINDEX offset,
  1265.                         PINDEX maxPos) const
  1266. {
  1267.   if (offset >= GetLength())
  1268.     return FALSE;
  1269.   if (!regex.Execute(&theArray[offset], pos, len, 0))
  1270.     return FALSE;
  1271.   pos += offset;
  1272.   if (pos+len > maxPos)
  1273.     return FALSE;
  1274.   return TRUE;
  1275. }
  1276. void PString::Replace(const PString & target,
  1277.                       const PString & subs,
  1278.                       BOOL all, PINDEX offset)
  1279. {
  1280.   MakeUnique();
  1281.   PINDEX tlen = target.GetLength();
  1282.   PINDEX slen = subs.GetLength();
  1283.   do {
  1284.     PINDEX pos = Find(target, offset);
  1285.     if (pos == P_MAX_INDEX)
  1286.       return;
  1287.     Splice(subs, pos, tlen);
  1288.     offset = pos + slen;
  1289.   } while (all);
  1290. }
  1291. void PString::Splice(const char * cstr, PINDEX pos, PINDEX len)
  1292. {
  1293.   register PINDEX slen = GetLength();
  1294.   if (pos >= slen)
  1295.     operator+=(cstr);
  1296.   else {
  1297.     MakeUnique();
  1298.     PINDEX clen = strlen(PAssertNULL(cstr));
  1299.     PINDEX newlen = slen-len+clen;
  1300.     if (clen > len)
  1301.       SetSize(newlen+1);
  1302.     if (pos+len < slen)
  1303.       PSTRING_MOVE(theArray, pos+clen, theArray, pos+len, slen-pos-len+1);
  1304.     PSTRING_COPY(theArray+pos, cstr, clen);
  1305.     theArray[newlen] = '';
  1306.   }
  1307. }
  1308. PStringArray
  1309.         PString::Tokenise(const char * separators, BOOL onePerSeparator) const
  1310. {
  1311.   PStringArray tokens;
  1312.   
  1313.   if (IsEmpty())  // No tokens
  1314.     return tokens;
  1315.     
  1316.   PINDEX token = 0;
  1317.   PINDEX p1 = 0;
  1318.   PINDEX p2 = FindOneOf(separators);
  1319.   if (p2 == 0 && onePerSeparator) { // first character is a token separator
  1320.     token++;                        // make first string in array empty
  1321.     p1 = 1;
  1322.     p2 = FindOneOf(separators, 1);
  1323.   }
  1324.   while (p2 != P_MAX_INDEX) {
  1325.     if (p2 > p1)
  1326.       tokens[token] = operator()(p1, p2-1);
  1327.     token++;
  1328.     // Get next separator. If not one token per separator then continue
  1329.     // around loop to skip over all the consecutive separators.
  1330.     do {
  1331.       p1 = p2 + 1;
  1332.     } while ((p2 = FindOneOf(separators, p1)) == p1 && !onePerSeparator);
  1333.   }
  1334.   tokens[token] = operator()(p1, P_MAX_INDEX);
  1335.   return tokens;
  1336. }
  1337. PStringArray PString::Lines() const
  1338. {
  1339.   PStringArray lines;
  1340.   
  1341.   if (IsEmpty())
  1342.     return lines;
  1343.     
  1344.   PINDEX line = 0;
  1345.   PINDEX p1 = 0;
  1346.   PINDEX p2;
  1347.   while ((p2 = FindOneOf("rn", p1)) != P_MAX_INDEX) {
  1348.     lines[line++] = operator()(p1, p2-1);
  1349.     p1 = p2 + 1;
  1350.     if (theArray[p2] == 'r' && theArray[p1] == 'n') // CR LF pair
  1351.       p1++;
  1352.   }
  1353.   if (p1 < GetLength())
  1354.     lines[line] = operator()(p1, P_MAX_INDEX);
  1355.   return lines;
  1356. }
  1357. PString PString::LeftTrim() const
  1358. {
  1359.   const char * lpos = theArray;
  1360.   while (isspace(*lpos))
  1361.     lpos++;
  1362.   return PString(lpos);
  1363. }
  1364. PString PString::RightTrim() const
  1365. {
  1366.   char * rpos = theArray+GetLength()-1;
  1367.   if (isspace(*rpos))
  1368.     return *this;
  1369.   while (isspace(*rpos)) {
  1370.     if (rpos == theArray)
  1371.       return PString();
  1372.     rpos--;
  1373.   }
  1374. #if defined(P_MACOSX) // make Apple gnu compiler happy
  1375.   PString retval(theArray, rpos - theArray);
  1376.   return retval;
  1377. #else
  1378.   return PString(theArray, rpos - theArray);
  1379. #endif
  1380. }
  1381. PString PString::Trim() const
  1382. {
  1383.   const char * lpos = theArray;
  1384.   while (isspace(*lpos))
  1385.     lpos++;
  1386.   if (*lpos == '')
  1387.     return PString();
  1388.   const char * rpos = theArray+GetLength()-1;
  1389.   if (!isspace(*rpos))
  1390.     return PString(lpos);
  1391.   while (isspace(*rpos))
  1392.     rpos--;
  1393.   return PString(lpos, rpos - lpos + 1);
  1394. }
  1395. PString PString::ToLower() const
  1396. {
  1397.   PString newStr(theArray);
  1398.   for (char *cpos = newStr.theArray; *cpos != ''; cpos++) {
  1399.     if (isupper(*cpos))
  1400.       *cpos = (char)tolower(*cpos);
  1401.   }
  1402.   return newStr;
  1403. }
  1404. PString PString::ToUpper() const
  1405. {
  1406.   PString newStr(theArray);
  1407.   for (char *cpos = newStr.theArray; *cpos != ''; cpos++) {
  1408.     if (islower(*cpos))
  1409.       *cpos = (char)toupper(*cpos);
  1410.   }
  1411.   return newStr;
  1412. }
  1413. long PString::AsInteger(unsigned base) const
  1414. {
  1415.   PAssert(base >= 2 && base <= 36, PInvalidParameter);
  1416.   char * dummy;
  1417.   return strtol(theArray, &dummy, base);
  1418. }
  1419. DWORD PString::AsUnsigned(unsigned base) const
  1420. {
  1421.   PAssert(base >= 2 && base <= 36, PInvalidParameter);
  1422.   char * dummy;
  1423.   return strtoul(theArray, &dummy, base);
  1424. }
  1425. double PString::AsReal() const
  1426. {
  1427. #ifndef __HAS_NO_FLOAT
  1428.   char * dummy;
  1429.   return strtod(theArray, &dummy);
  1430. #else
  1431.   return 0.0;
  1432. #endif
  1433. }
  1434. PBYTEArray PString::ToPascal() const
  1435. {
  1436.   PINDEX len = GetLength();
  1437.   PAssert(len < 256, "Cannot convert to PASCAL string");
  1438.   BYTE buf[256];
  1439.   buf[0] = (BYTE)len;
  1440. #ifdef PHAS_UNICODE
  1441.   WORD * ptr = (WORD *)theArray;
  1442.   while (len > 0) {
  1443.     buf[len] = (BYTE)(*ptr < 256 ? *ptr : 255);
  1444.     len--;
  1445.   }
  1446. #else
  1447.   memcpy(&buf[1], theArray, len);
  1448. #endif
  1449.   return PBYTEArray(buf, len+1);
  1450. }
  1451. PString PString::ToLiteral() const
  1452. {
  1453.   PString str('"');
  1454.   for (char * p = theArray; *p != ''; p++) {
  1455.     if (*p == '"')
  1456.       str += "\"";
  1457.     else if (isprint(*p))
  1458.       str += *p;
  1459.     else {
  1460.       PINDEX i;
  1461.       for (i = 0; i < PARRAYSIZE(PStringEscapeValue); i++) {
  1462.         if (*p == PStringEscapeValue[i]) {
  1463.           str += PString('\') + PStringEscapeCode[i];
  1464.           break;
  1465.         }
  1466.       }
  1467.       if (i >= PARRAYSIZE(PStringEscapeValue))
  1468.         str.sprintf("\%03o", *p & 0xff);
  1469.     }
  1470.   }
  1471.   return str + '"';
  1472. }
  1473. PString & PString::sprintf(const char * fmt, ...)
  1474. {
  1475.   va_list args;
  1476.   va_start(args, fmt);
  1477.   return vsprintf(fmt, args);
  1478. }
  1479. PString & PString::vsprintf(const char * fmt, va_list arg)
  1480. {
  1481.   char * p = GetPointer(1000);
  1482.   ::vsprintf(p+strlen(p), fmt, arg);
  1483.   PAssert(strlen(theArray) < 1000, "Single sprintf() too large");
  1484.   PAssert(MakeMinimumSize(), POutOfMemory);
  1485.   return *this;
  1486. }
  1487. PString psprintf(const char * fmt, ...)
  1488. {
  1489.   PString str;
  1490.   va_list args;
  1491.   va_start(args, fmt);
  1492.   return str.vsprintf(fmt, args);
  1493. }
  1494. PString pvsprintf(const char * fmt, va_list arg)
  1495. {
  1496.   PString str;
  1497.   return str.vsprintf(fmt, arg);
  1498. }
  1499. ///////////////////////////////////////////////////////////////////////////////
  1500. PObject * PCaselessString::Clone() const
  1501. {
  1502.   return new PCaselessString(*this);
  1503. }
  1504. PObject::Comparison PCaselessString::InternalCompare(PINDEX offset, char c) const
  1505. {
  1506.   int c1 = toupper(theArray[offset]);
  1507.   int c2 = toupper(c);
  1508.   if (c1 < c2)
  1509.     return LessThan;
  1510.   if (c1 > c2)
  1511.     return GreaterThan;
  1512.   return EqualTo;
  1513. }
  1514. PObject::Comparison PCaselessString::InternalCompare(
  1515.                          PINDEX offset, PINDEX length, const char * cstr) const
  1516. {
  1517.   PAssertNULL(cstr);
  1518.   while (length-- > 0 && (theArray[offset] != '' || *cstr != '')) {
  1519.     Comparison c = PCaselessString::InternalCompare(offset++, *cstr++);
  1520.     if (c != EqualTo)
  1521.       return c;
  1522.   }
  1523.   return EqualTo;
  1524. }
  1525. ///////////////////////////////////////////////////////////////////////////////
  1526. int PStringStream::Buffer::overflow(int c)
  1527. {
  1528.   if (pptr() >= epptr()) {
  1529.     int gpos = gptr() - eback();
  1530.     int ppos = pptr() - pbase();
  1531.     char * newptr = string->GetPointer(string->GetSize() + 32);
  1532.     setp(newptr, newptr + string->GetSize() - 1);
  1533.     pbump(ppos);
  1534.     setg(newptr, newptr + gpos, newptr + ppos);
  1535.   }
  1536.   if (c != EOF) {
  1537.     *pptr() = (char)c;
  1538.     pbump(1);
  1539.   }
  1540.   return 0;
  1541. }
  1542. int PStringStream::Buffer::underflow()
  1543. {
  1544.   return gptr() >= egptr() ? EOF : *gptr();
  1545. }
  1546. int PStringStream::Buffer::sync()
  1547. {
  1548.   string->MakeMinimumSize();
  1549.   char * base = string->GetPointer();
  1550.   char * end = base + string->GetLength();
  1551.   setg(base, base, end);
  1552.   setp(end, end);
  1553.   return 0;
  1554. }
  1555. streampos PStringStream::Buffer::seekoff(streamoff off,
  1556. #ifdef __MWERKS__
  1557.                                  ios::seekdir dir, ios::openmode mode)
  1558. #else
  1559.                                  ios::seek_dir dir, int mode)
  1560. #endif
  1561. {
  1562.   int len = string->GetLength();
  1563.   int gpos = gptr() - eback();
  1564.   int ppos = pptr() - pbase();
  1565.   char * newgptr;
  1566.   char * newpptr;
  1567.   switch (dir) {
  1568.     case ios::beg :
  1569.       if (off < 0)
  1570.         newpptr = newgptr = eback();
  1571.       else if (off >= len)
  1572.         newpptr = newgptr = egptr();
  1573.       else
  1574.         newpptr = newgptr = eback()+off;
  1575.       break;
  1576.     case ios::cur :
  1577.       if (off < -ppos)
  1578.         newpptr = eback();
  1579.       else if (off >= len-ppos)
  1580.         newpptr = epptr();
  1581.       else
  1582.         newpptr = pptr()+off;
  1583.       if (off < -gpos)
  1584.         newgptr = eback();
  1585.       else if (off >= len-gpos)
  1586.         newgptr = egptr();
  1587.       else
  1588.         newgptr = gptr()+off;
  1589.       break;
  1590.     case ios::end :
  1591.       if (off < -len)
  1592.         newpptr = newpptr = newgptr = eback();
  1593.       else if (off >= 0)
  1594.         newpptr = newgptr = egptr();
  1595.       else
  1596.         newpptr = newgptr = egptr()+off;
  1597.       break;
  1598.     default:
  1599.       PAssertAlways(PInvalidParameter);
  1600.       newgptr = gptr();
  1601.       newpptr = pptr();
  1602.   }
  1603.   if ((mode&ios::in) != 0)
  1604.     setg(eback(), newgptr, egptr());
  1605.   if ((mode&ios::out) != 0)
  1606.     setp(newpptr, epptr());
  1607.   return 0;
  1608. }
  1609. PStringStream::PStringStream()
  1610. {
  1611.   init(new PStringStream::Buffer(this));
  1612. }
  1613. PStringStream::PStringStream(const PString & str)
  1614.   : PString(str)
  1615. {
  1616.   init(new PStringStream::Buffer(this));
  1617. }
  1618. PStringStream::PStringStream(const char * cstr)
  1619.   : PString(cstr)
  1620. {
  1621.   init(new PStringStream::Buffer(this));
  1622. }
  1623. PStringStream & PStringStream::operator=(const char * cstr)
  1624. {
  1625.   PString::operator=(cstr);
  1626.   flush();
  1627.   return *this;
  1628. }
  1629. PStringStream & PStringStream::operator=(const PString & str)
  1630. {
  1631.   PString::operator=(str);
  1632.   flush();
  1633.   return *this;
  1634. }
  1635. PStringStream::~PStringStream()
  1636. {
  1637.   delete (PStringStream::Buffer *)rdbuf();
  1638.   init(NULL);
  1639. }
  1640. ///////////////////////////////////////////////////////////////////////////////
  1641. PStringArray::PStringArray(PINDEX count, char const * const * strarr, BOOL caseless)
  1642. {
  1643.   if (count == 0)
  1644.     return;
  1645.   PAssertNULL(strarr);
  1646.   SetSize(count);
  1647.   for (PINDEX i = 0; i < count; i++) {
  1648.     PString * newString;
  1649.     if (caseless)
  1650.       newString = new PCaselessString(strarr[i]);
  1651.     else
  1652.       newString = new PString(strarr[i]);
  1653.     SetAt(i, newString);
  1654.   }
  1655. }
  1656. PString & PStringArray::operator[](PINDEX index)
  1657. {
  1658.   PASSERTINDEX(index);
  1659.   PAssert(SetMinSize(index+1), POutOfMemory);
  1660.   if ((*theArray)[index] == NULL)
  1661.     (*theArray)[index] = new PString;
  1662.   return *(PString *)(*theArray)[index];
  1663. }
  1664. ///////////////////////////////////////////////////////////////////////////////
  1665. PStringList::PStringList(PINDEX count, char const * const * strarr, BOOL caseless)
  1666. {
  1667.   if (count == 0)
  1668.     return;
  1669.   PAssertNULL(strarr);
  1670.   for (PINDEX i = 0; i < count; i++) {
  1671.     PString * newString;
  1672.     if (caseless)
  1673.       newString = new PCaselessString(strarr[i]);
  1674.     else
  1675.       newString = new PString(strarr[i]);
  1676.     Append(newString);
  1677.   }
  1678. }
  1679. ///////////////////////////////////////////////////////////////////////////////
  1680. PSortedStringList::PSortedStringList(PINDEX count,
  1681.                                      char const * const * strarr,
  1682.                                      BOOL caseless)
  1683. {
  1684.   if (count == 0)
  1685.     return;
  1686.   PAssertNULL(strarr);
  1687.   for (PINDEX i = 0; i < count; i++) {
  1688.     PString * newString;
  1689.     if (caseless)
  1690.       newString = new PCaselessString(strarr[i]);
  1691.     else
  1692.       newString = new PString(strarr[i]);
  1693.     Append(newString);
  1694.   }
  1695. }
  1696. ///////////////////////////////////////////////////////////////////////////////
  1697. PStringSet::PStringSet(PINDEX count, char const * const * strarr, BOOL caseless)
  1698. {
  1699.   if (count == 0)
  1700.     return;
  1701.   PAssertNULL(strarr);
  1702.   for (PINDEX i = 0; i < count; i++) {
  1703.     if (caseless)
  1704.       Include(PCaselessString(strarr[i]));
  1705.     else
  1706.       Include(PString(strarr[i]));
  1707.   }
  1708. }
  1709. ///////////////////////////////////////////////////////////////////////////////
  1710. POrdinalToString::POrdinalToString(PINDEX count, const Initialiser * init)
  1711. {
  1712.   while (count-- > 0) {
  1713.     SetAt(init->key, init->value);
  1714.     init++;
  1715.   }
  1716. }
  1717. ///////////////////////////////////////////////////////////////////////////////
  1718. PStringToOrdinal::PStringToOrdinal(PINDEX count,
  1719.                                    const Initialiser * init,
  1720.                                    BOOL caseless)
  1721. {
  1722.   while (count-- > 0) {
  1723.     if (caseless)
  1724.       SetAt(PCaselessString(init->key), init->value);
  1725.     else
  1726.       SetAt(init->key, init->value);
  1727.     init++;
  1728.   }
  1729. }
  1730. ///////////////////////////////////////////////////////////////////////////////
  1731. PStringToString::PStringToString(PINDEX count,
  1732.                                  const Initialiser * init,
  1733.                                  BOOL caselessKeys,
  1734.                                  BOOL caselessValues)
  1735. {
  1736.   while (count-- > 0) {
  1737.     if (caselessValues)
  1738.       if (caselessKeys)
  1739.         SetAt(PCaselessString(init->key), PCaselessString(init->value));
  1740.       else
  1741.         SetAt(init->key, PCaselessString(init->value));
  1742.     else
  1743.       if (caselessKeys)
  1744.         SetAt(PCaselessString(init->key), init->value);
  1745.       else
  1746.         SetAt(init->key, init->value);
  1747.     init++;
  1748.   }
  1749. }
  1750. ///////////////////////////////////////////////////////////////////////////////
  1751. PRegularExpression::PRegularExpression()
  1752. {
  1753.   lastError = NotCompiled;
  1754.   expression = NULL;
  1755. }
  1756. PRegularExpression::PRegularExpression(const PString & pattern, int flags)
  1757. {
  1758.   expression = NULL;
  1759.   Compile(pattern, flags);
  1760. }
  1761. PRegularExpression::PRegularExpression(const char * pattern, int flags)
  1762. {
  1763.   expression = NULL;
  1764.   Compile(pattern, flags);
  1765. }
  1766. PRegularExpression::~PRegularExpression()
  1767. {
  1768.   if (expression != NULL) {
  1769.     regfree(expression);
  1770.     delete expression;
  1771.   }
  1772. }
  1773. PRegularExpression::ErrorCodes PRegularExpression::GetErrorCode() const
  1774. {
  1775.   return (ErrorCodes)lastError;
  1776. }
  1777. PString PRegularExpression::GetErrorText() const
  1778. {
  1779.   PString str;
  1780.   regerror(lastError, expression, str.GetPointer(256), 256);
  1781.   return str;
  1782. }
  1783. BOOL PRegularExpression::Compile(const PString & pattern, int flags)
  1784. {
  1785.   return Compile((const char *)pattern, flags);
  1786. }
  1787. BOOL PRegularExpression::Compile(const char * pattern, int flags)
  1788. {
  1789.   if (expression != NULL) {
  1790.     regfree(expression);
  1791.     delete expression;
  1792.   }
  1793.   if (pattern == NULL || *pattern == '')
  1794.     return BadPattern;
  1795.   expression = new regex_t;
  1796.   lastError = regcomp(expression, pattern, flags);
  1797.   return lastError == NoError;
  1798. }
  1799. BOOL PRegularExpression::Execute(const PString & str, PINDEX & start, int flags) const
  1800. {
  1801.   PINDEX dummy;
  1802.   return Execute((const char *)str, start, dummy, flags);
  1803. }
  1804. BOOL PRegularExpression::Execute(const PString & str, PINDEX & start, PINDEX & len, int flags) const
  1805. {
  1806.   return Execute((const char *)str, start, len, flags);
  1807. }
  1808. BOOL PRegularExpression::Execute(const char * cstr, PINDEX & start, int flags) const
  1809. {
  1810.   PINDEX dummy;
  1811.   return Execute(cstr, start, dummy, flags);
  1812. }
  1813. BOOL PRegularExpression::Execute(const char * cstr, PINDEX & start, PINDEX & len, int flags) const
  1814. {
  1815.   if (expression == NULL) {
  1816.     ((PRegularExpression*)this)->lastError = NotCompiled;
  1817.     return FALSE;
  1818.   }
  1819.   regmatch_t match;
  1820.   ((PRegularExpression*)this)->lastError = regexec(expression, cstr, 1, &match, flags);
  1821.   if (lastError != NoError)
  1822.     return FALSE;
  1823.   start = match.rm_so;
  1824.   len = match.rm_eo - start;
  1825.   return TRUE;
  1826. }
  1827. BOOL PRegularExpression::Execute(const PString & str, PIntArray & starts, int flags) const
  1828. {
  1829.   PIntArray dummy;
  1830.   return Execute((const char *)str, starts, dummy, flags);
  1831. }
  1832. BOOL PRegularExpression::Execute(const PString & str,
  1833.                                  PIntArray & starts,
  1834.                                  PIntArray & ends,
  1835.                                  int flags) const
  1836. {
  1837.   return Execute((const char *)str, starts, ends, flags);
  1838. }
  1839. BOOL PRegularExpression::Execute(const char * cstr, PIntArray & starts, int flags) const
  1840. {
  1841.   PIntArray dummy;
  1842.   return Execute(cstr, starts, dummy, flags);
  1843. }
  1844. BOOL PRegularExpression::Execute(const char * cstr,
  1845.                                  PIntArray & starts,
  1846.                                  PIntArray & ends,
  1847.                                  int flags) const
  1848. {
  1849.   if (expression == NULL) {
  1850.     ((PRegularExpression*)this)->lastError = NotCompiled;
  1851.     return FALSE;
  1852.   }
  1853.   regmatch_t single_match;
  1854.   regmatch_t * matches = &single_match;
  1855.   PINDEX count = starts.GetSize();
  1856.   if (count > 1)
  1857.     matches = new regmatch_t[count];
  1858.   else
  1859.     count = 1;
  1860.   ((PRegularExpression*)this)->lastError = regexec(expression, cstr, count, matches, flags);
  1861.   if (lastError == NoError) {
  1862.     starts.SetMinSize(count);
  1863.     ends.SetMinSize(count);
  1864.     for (PINDEX i = 0; i < count; i++) {
  1865.       starts[i] = matches[i].rm_so;
  1866.       ends[i] = matches[i].rm_eo;
  1867.     }
  1868.   }
  1869.   if (matches != &single_match)
  1870.     delete [] matches;
  1871.   return lastError == NoError;
  1872. }
  1873. PString PRegularExpression::EscapeString(const PString & str)
  1874. {
  1875.   PString translated;
  1876.   PINDEX lastPos = 0;
  1877.   PINDEX nextPos;
  1878.   while ((nextPos = str.FindOneOf("\^$+?*.[]()|{}", lastPos+1)) != P_MAX_INDEX) {
  1879.     translated += str(lastPos, nextPos-1) + "\";
  1880.     lastPos = nextPos;
  1881.   }
  1882.   if (lastPos == 0)
  1883.     return str;
  1884.   return translated + str.Mid(lastPos);
  1885. }
  1886. // End Of File ///////////////////////////////////////////////////////////////