/[rdesktop]/sourceforge.net/trunk/seamlessrdp/ClientDLL/stdstring.h
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Diff of /sourceforge.net/trunk/seamlessrdp/ClientDLL/stdstring.h

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 929 by astrand, Thu Jun 30 09:06:43 2005 UTC revision 930 by astrand, Thu Jun 30 14:14:56 2005 UTC
# Line 1  Line 1 
1  // =============================================================================  // =============================================================================
2  //  FILE:  StdString.h  //  FILE:  StdString.h
3  //  AUTHOR:     Joe O'Leary (with outside help noted in comments)  //  AUTHOR:     Joe O'Leary (with outside help noted in comments)
4  //  REMARKS:  //  REMARKS:
5  //              This header file declares the CStdStr template.  This template derives  //              This header file declares the CStdStr template.  This template derives
6  //              the Standard C++ Library basic_string<> template and add to it the  //              the Standard C++ Library basic_string<> template and add to it the
7  //              the following conveniences:  //              the following conveniences:
8  //                      - The full MFC CString set of functions (including implicit cast)  //                      - The full MFC CString set of functions (including implicit cast)
9  //                      - writing to/reading from COM IStream interfaces  //                      - writing to/reading from COM IStream interfaces
10  //                      - Functional objects for use in STL algorithms  //                      - Functional objects for use in STL algorithms
11  //  //
12  //              From this template, we intstantiate two classes:  CStdStringA and  //              From this template, we intstantiate two classes:  CStdStringA and
13  //              CStdStringW.  The name "CStdString" is just a #define of one of these,  //              CStdStringW.  The name "CStdString" is just a #define of one of these,
14  //              based upone the _UNICODE macro setting  //              based upone the _UNICODE macro setting
15  //  //
16  //              This header also declares our own version of the MFC/ATL UNICODE-MBCS  //              This header also declares our own version of the MFC/ATL UNICODE-MBCS
17  //              conversion macros.  Our version looks exactly like the Microsoft's to  //              conversion macros.  Our version looks exactly like the Microsoft's to
18  //              facilitate portability.  //              facilitate portability.
19  //  //
20  //      NOTE:  //      NOTE:
21  //              If you you use this in an MFC or ATL build, you should include either  //              If you you use this in an MFC or ATL build, you should include either
22  //              afx.h or atlbase.h first, as appropriate.  //              afx.h or atlbase.h first, as appropriate.
23  //  //
24  //      PEOPLE WHO HAVE CONTRIBUTED TO THIS CLASS:  //      PEOPLE WHO HAVE CONTRIBUTED TO THIS CLASS:
25  //  //
26  //              Several people have helped me iron out problems and othewise improve  //              Several people have helped me iron out problems and othewise improve
27  //              this class.  OK, this is a long list but in my own defense, this code  //              this class.  OK, this is a long list but in my own defense, this code
28  //              has undergone two major rewrites.  Many of the improvements became  //              has undergone two major rewrites.  Many of the improvements became
29  //              necessary after I rewrote the code as a template.  Others helped me  //              necessary after I rewrote the code as a template.  Others helped me
30  //              improve the CString facade.  //              improve the CString facade.
31  //  //
32  //              Anyway, these people are (in chronological order):  //              Anyway, these people are (in chronological order):
33  //  //
34  //                      - Pete the Plumber (???)  //                      - Pete the Plumber (???)
35  //                      - Julian Selman  //                      - Julian Selman
36  //                      - Chris (of Melbsys)  //                      - Chris (of Melbsys)
37  //                      - Dave Plummer  //                      - Dave Plummer
38  //                      - John C Sipos  //                      - John C Sipos
39  //                      - Chris Sells  //                      - Chris Sells
40  //                      - Nigel Nunn  //                      - Nigel Nunn
41  //                      - Fan Xia  //                      - Fan Xia
42  //                      - Matthew Williams  //                      - Matthew Williams
43  //                      - Carl Engman  //                      - Carl Engman
44  //                      - Mark Zeren  //                      - Mark Zeren
45  //                      - Craig Watson  //                      - Craig Watson
46  //                      - Rich Zuris  //                      - Rich Zuris
47  //                      - Karim Ratib  //                      - Karim Ratib
48  //                      - Chris Conti  //                      - Chris Conti
49  //                      - Baptiste Lepilleur  //                      - Baptiste Lepilleur
50  //                      - Greg Pickles  //                      - Greg Pickles
51  //                      - Jim Cline  //                      - Jim Cline
52  //                      - Jeff Kohn  //                      - Jeff Kohn
53  //                      - Todd Heckel  //                      - Todd Heckel
54  //                      - Ullrich Pollähne  //                      - Ullrich Pollähne
55  //                      - Joe Vitaterna  //                      - Joe Vitaterna
56  //                      - Joe Woodbury  //                      - Joe Woodbury
57  //                      - Aaron (no last name)  //                      - Aaron (no last name)
58  //                      - Joldakowski (???)  //                      - Joldakowski (???)
59  //                      - Scott Hathaway  //                      - Scott Hathaway
60  //                      - Eric Nitzche  //                      - Eric Nitzche
61  //                      - Pablo Presedo  //                      - Pablo Presedo
62  //  //
63  //      REVISION HISTORY  //      REVISION HISTORY
64  //        2001-APR-27 - StreamLoad was calculating the number of BYTES in one  //        2001-APR-27 - StreamLoad was calculating the number of BYTES in one
65  //                                      case, not characters.  Thanks to Pablo Presedo for this.  //                                      case, not characters.  Thanks to Pablo Presedo for this.
66  //  //
67  //    2001-FEB-23 - Replace() had a bug which caused infinite loops if the  //    2001-FEB-23 - Replace() had a bug which caused infinite loops if the
68  //                                      source string was empty.  Fixed thanks to Eric Nitzsche.  //                                      source string was empty.  Fixed thanks to Eric Nitzsche.
69  //  //
70  //    2001-FEB-23 - Scott Hathaway was a huge help in providing me with the  //    2001-FEB-23 - Scott Hathaway was a huge help in providing me with the
71  //                                      ability to build CStdString on Sun Unix systems.  He  //                                      ability to build CStdString on Sun Unix systems.  He
72  //                                      sent me detailed build reports about what works and what  //                                      sent me detailed build reports about what works and what
73  //                                      does not.  If CStdString compiles on your Unix box, you  //                                      does not.  If CStdString compiles on your Unix box, you
74  //                                      can thank Scott for it.  //                                      can thank Scott for it.
75  //  //
76  //        2000-DEC-29 - Joldakowski noticed one overload of Insert failed to do  //        2000-DEC-29 - Joldakowski noticed one overload of Insert failed to do
77  //                                      range check as CString's does.  Now fixed -- thanks!  //                                      range check as CString's does.  Now fixed -- thanks!
78  //  //
79  //        2000-NOV-07 - Aaron pointed out that I was calling static member  //        2000-NOV-07 - Aaron pointed out that I was calling static member
80  //                                      functions of char_traits via a temporary.  This was not  //                                      functions of char_traits via a temporary.  This was not
81  //                                      technically wrong, but it was unnecessary and caused  //                                      technically wrong, but it was unnecessary and caused
82  //                                      problems for poor old buggy VC5.  Thanks Aaron!  //                                      problems for poor old buggy VC5.  Thanks Aaron!
83  //  //
84  //        2000-JUL-11 - Joe Woodbury noted that the CString::Find docs don't match  //        2000-JUL-11 - Joe Woodbury noted that the CString::Find docs don't match
85  //                                      what the CString::Find code really ends up doing.   I was  //                                      what the CString::Find code really ends up doing.   I was
86  //                                      trying to match the docs.  Now I match the CString code  //                                      trying to match the docs.  Now I match the CString code
87  //                                - Joe also caught me truncating strings for GetBuffer() calls  //                                - Joe also caught me truncating strings for GetBuffer() calls
88  //                                      when the supplied length was less than the current length.  //                                      when the supplied length was less than the current length.
89  //  //
90  //        2000-MAY-25 - Better support for STLPORT's Standard library distribution  //        2000-MAY-25 - Better support for STLPORT's Standard library distribution
91  //                                - Got rid of the NSP macro - it interfered with Koenig lookup  //                                - Got rid of the NSP macro - it interfered with Koenig lookup
92  //                                - Thanks to Joe Woodbury for catching a TrimLeft() bug that  //                                - Thanks to Joe Woodbury for catching a TrimLeft() bug that
93  //                                      I introduced in January.  Empty strings were not getting  //                                      I introduced in January.  Empty strings were not getting
94  //                                      trimmed  //                                      trimmed
95  //  //
96  //        2000-APR-17 - Thanks to Joe Vitaterna for pointing out that ReverseFind  //        2000-APR-17 - Thanks to Joe Vitaterna for pointing out that ReverseFind
97  //                                      is supposed to be a const function.  //                                      is supposed to be a const function.
98  //  //
99  //        2000-MAR-07 - Thanks to Ullrich Pollähne for catching a range bug in one  //        2000-MAR-07 - Thanks to Ullrich Pollähne for catching a range bug in one
100  //                                      of the overloads of assign.  //                                      of the overloads of assign.
101  //  //
102  //    2000-FEB-01 - You can now use CStdString on the Mac with CodeWarrior!  //    2000-FEB-01 - You can now use CStdString on the Mac with CodeWarrior!
103  //                                      Thanks to Todd Heckel for helping out with this.  //                                      Thanks to Todd Heckel for helping out with this.
104  //  //
105  //        2000-JAN-23 - Thanks to Jim Cline for pointing out how I could make the  //        2000-JAN-23 - Thanks to Jim Cline for pointing out how I could make the
106  //                                      Trim() function more efficient.  //                                      Trim() function more efficient.
107  //                                - Thanks to Jeff Kohn for prompting me to find and fix a typo  //                                - Thanks to Jeff Kohn for prompting me to find and fix a typo
108  //                                      in one of the addition operators that takes _bstr_t.  //                                      in one of the addition operators that takes _bstr_t.
109  //                                - Got rid of the .CPP file -  you only need StdString.h now!  //                                - Got rid of the .CPP file -  you only need StdString.h now!
110  //  //
111  //        1999-DEC-22 - Thanks to Greg Pickles for helping me identify a problem  //        1999-DEC-22 - Thanks to Greg Pickles for helping me identify a problem
112  //                                      with my implementation of CStdString::FormatV in which  //                                      with my implementation of CStdString::FormatV in which
113  //                                      resulting string might not be properly NULL terminated.  //                                      resulting string might not be properly NULL terminated.
114  //  //
115  //        1999-DEC-06 - Chris Conti pointed yet another basic_string<> assignment  //        1999-DEC-06 - Chris Conti pointed yet another basic_string<> assignment
116  //                                      bug that MS has not fixed.  CStdString did nothing to fix  //                                      bug that MS has not fixed.  CStdString did nothing to fix
117  //                                      it either but it does now!  The bug was: create a string  //                                      it either but it does now!  The bug was: create a string
118  //                                      longer than 31 characters, get a pointer to it (via c_str())  //                                      longer than 31 characters, get a pointer to it (via c_str())
119  //                                      and then assign that pointer to the original string object.  //                                      and then assign that pointer to the original string object.
120  //                                      The resulting string would be empty.  Not with CStdString!  //                                      The resulting string would be empty.  Not with CStdString!
121  //  //
122  //        1999-OCT-06 - BufferSet was erasing the string even when it was merely  //        1999-OCT-06 - BufferSet was erasing the string even when it was merely
123  //                                      supposed to shrink it.  Fixed.  Thanks to Chris Conti.  //                                      supposed to shrink it.  Fixed.  Thanks to Chris Conti.
124  //                                - Some of the Q172398 fixes were not checking for assignment-  //                                - Some of the Q172398 fixes were not checking for assignment-
125  //                                      to-self.  Fixed.  Thanks to Baptiste Lepilleur.  //                                      to-self.  Fixed.  Thanks to Baptiste Lepilleur.
126  //  //
127  //        1999-AUG-20 - Improved Load() function to be more efficient by using  //        1999-AUG-20 - Improved Load() function to be more efficient by using
128  //                                      SizeOfResource().  Thanks to Rich Zuris for this.  //                                      SizeOfResource().  Thanks to Rich Zuris for this.
129  //                                - Corrected resource ID constructor, again thanks to Rich.  //                                - Corrected resource ID constructor, again thanks to Rich.
130  //                                - Fixed a bug that occurred with UNICODE characters above  //                                - Fixed a bug that occurred with UNICODE characters above
131  //                                      the first 255 ANSI ones.  Thanks to Craig Watson.  //                                      the first 255 ANSI ones.  Thanks to Craig Watson.
132  //                                - Added missing overloads of TrimLeft() and TrimRight().  //                                - Added missing overloads of TrimLeft() and TrimRight().
133  //                                      Thanks to Karim Ratib for pointing them out  //                                      Thanks to Karim Ratib for pointing them out
134  //  //
135  //        1999-JUL-21 - Made all calls to GetBuf() with no args check length first.  //        1999-JUL-21 - Made all calls to GetBuf() with no args check length first.
136  //  //
137  //        1999-JUL-10 - Improved MFC/ATL independence of conversion macros  //        1999-JUL-10 - Improved MFC/ATL independence of conversion macros
138  //                                - Added SS_NO_REFCOUNT macro to allow you to disable any  //                                - Added SS_NO_REFCOUNT macro to allow you to disable any
139  //                                      reference-counting your basic_string<> impl. may do.  //                                      reference-counting your basic_string<> impl. may do.
140  //                                - Improved ReleaseBuffer() to be as forgiving as CString.  //                                - Improved ReleaseBuffer() to be as forgiving as CString.
141  //                                      Thanks for Fan Xia for helping me find this and to  //                                      Thanks for Fan Xia for helping me find this and to
142  //                                      Matthew Williams for pointing it out directly.  //                                      Matthew Williams for pointing it out directly.
143  //  //
144  //        1999-JUL-06 - Thanks to Nigel Nunn for catching a very sneaky bug in  //        1999-JUL-06 - Thanks to Nigel Nunn for catching a very sneaky bug in
145  //                                      ToLower/ToUpper.  They should call GetBuf() instead of  //                                      ToLower/ToUpper.  They should call GetBuf() instead of
146  //                                      data() in order to ensure the changed string buffer is not  //                                      data() in order to ensure the changed string buffer is not
147  //                                      reference-counted (in those implementations that refcount).  //                                      reference-counted (in those implementations that refcount).
148  //  //
149  //        1999-JUL-01 - Added a true CString facade.  Now you can use CStdString as  //        1999-JUL-01 - Added a true CString facade.  Now you can use CStdString as
150  //                                      a drop-in replacement for CString.  If you find this useful,  //                                      a drop-in replacement for CString.  If you find this useful,
151  //                                      you can thank Chris Sells for finally convincing me to give  //                                      you can thank Chris Sells for finally convincing me to give
152  //                                      in and implement it.  //                                      in and implement it.
153  //                                - Changed operators << and >> (for MFC CArchive) to serialize  //                                - Changed operators << and >> (for MFC CArchive) to serialize
154  //                                      EXACTLY as CString's do.  So now you can send a CString out  //                                      EXACTLY as CString's do.  So now you can send a CString out
155  //                                      to a CArchive and later read it in as a CStdString.   I have  //                                      to a CArchive and later read it in as a CStdString.   I have
156  //                                      no idea why you would want to do this but you can.  //                                      no idea why you would want to do this but you can.
157  //  //
158  //        1999-JUN-21 - Changed the CStdString class into the CStdStr template.  //        1999-JUN-21 - Changed the CStdString class into the CStdStr template.
159  //                                - Fixed FormatV() to correctly decrement the loop counter.  //                                - Fixed FormatV() to correctly decrement the loop counter.
160  //                                      This was harmless bug but a bug nevertheless.  Thanks to  //                                      This was harmless bug but a bug nevertheless.  Thanks to
161  //                                      Chris (of Melbsys) for pointing it out  //                                      Chris (of Melbsys) for pointing it out
162  //                                - Changed Format() to try a normal stack-based array before  //                                - Changed Format() to try a normal stack-based array before
163  //                                      using to _alloca().  //                                      using to _alloca().
164  //                                - Updated the text conversion macros to properly use code  //                                - Updated the text conversion macros to properly use code
165  //                                      pages and to fit in better in MFC/ATL builds.  In other  //                                      pages and to fit in better in MFC/ATL builds.  In other
166  //                                      words, I copied Microsoft's conversion stuff again.  //                                      words, I copied Microsoft's conversion stuff again.
167  //                                - Added equivalents of CString::GetBuffer, GetBufferSetLength  //                                - Added equivalents of CString::GetBuffer, GetBufferSetLength
168  //                                - new sscpy() replacement of CStdString::CopyString()  //                                - new sscpy() replacement of CStdString::CopyString()
169  //                                - a Trim() function that combines TrimRight() and TrimLeft().  //                                - a Trim() function that combines TrimRight() and TrimLeft().
170  //  //
171  //        1999-MAR-13 - Corrected the "NotSpace" functional object to use _istpace()  //        1999-MAR-13 - Corrected the "NotSpace" functional object to use _istpace()
172  //                                      instead of _isspace()   Thanks to Dave Plummer for this.  //                                      instead of _isspace()   Thanks to Dave Plummer for this.
173  //  //
174  //        1999-FEB-26 - Removed errant line (left over from testing) that #defined  //        1999-FEB-26 - Removed errant line (left over from testing) that #defined
175  //                                      _MFC_VER.  Thanks to John C Sipos for noticing this.  //                                      _MFC_VER.  Thanks to John C Sipos for noticing this.
176  //  //
177  //        1999-FEB-03 - Fixed a bug in a rarely-used overload of operator+() that  //        1999-FEB-03 - Fixed a bug in a rarely-used overload of operator+() that
178  //                                      caused infinite recursion and stack overflow  //                                      caused infinite recursion and stack overflow
179  //                                - Added member functions to simplify the process of  //                                - Added member functions to simplify the process of
180  //                                      persisting CStdStrings to/from DCOM IStream interfaces  //                                      persisting CStdStrings to/from DCOM IStream interfaces
181  //                                - Added functional objects (e.g. StdStringLessNoCase) that  //                                - Added functional objects (e.g. StdStringLessNoCase) that
182  //                                      allow CStdStrings to be used as keys STL map objects with  //                                      allow CStdStrings to be used as keys STL map objects with
183  //                                      case-insensitive comparison  //                                      case-insensitive comparison
184  //                                - Added array indexing operators (i.e. operator[]).  I  //                                - Added array indexing operators (i.e. operator[]).  I
185  //                                      originally assumed that these were unnecessary and would be  //                                      originally assumed that these were unnecessary and would be
186  //                                      inherited from basic_string.  However, without them, Visual  //                                      inherited from basic_string.  However, without them, Visual
187  //                                      C++ complains about ambiguous overloads when you try to use  //                                      C++ complains about ambiguous overloads when you try to use
188  //                                      them.  Thanks to Julian Selman to pointing this out.  //                                      them.  Thanks to Julian Selman to pointing this out.
189  //  //
190  //        1998-FEB-?? - Added overloads of assign() function to completely account  //        1998-FEB-?? - Added overloads of assign() function to completely account
191  //                                      for Q172398 bug.  Thanks to "Pete the Plumber" for this  //                                      for Q172398 bug.  Thanks to "Pete the Plumber" for this
192  //  //
193  //        1998-FEB-?? - Initial submission  //        1998-FEB-?? - Initial submission
194  //  //
195  // COPYRIGHT:  // COPYRIGHT:
196  //              1999 Joseph M. O'Leary.  This code is free.  Use it anywhere you want.  //              1999 Joseph M. O'Leary.  This code is free.  Use it anywhere you want.
197  //              Rewrite it, restructure it, whatever.  Please don't blame me if it makes  //              Rewrite it, restructure it, whatever.  Please don't blame me if it makes
198  //              your $30 billion dollar satellite explode in orbit.  If you redistribute  //              your $30 billion dollar satellite explode in orbit.  If you redistribute
199  //              it in any form, I'd appreciate it if you would leave this notice here.  //              it in any form, I'd appreciate it if you would leave this notice here.
200  //  //
201  //              If you find any bugs, please let me know:  //              If you find any bugs, please let me know:
202  //  //
203  //                              jmoleary@earthlink.net  //                              jmoleary@earthlink.net
204  //                              http://home.earthlink.net/~jmoleary  //                              http://home.earthlink.net/~jmoleary
205  // =============================================================================  // =============================================================================
206    
207  // Avoid multiple inclusion the VC++ way,  // Avoid multiple inclusion the VC++ way,
208  // Turn off browser references  // Turn off browser references
209  // Turn off unavoidable compiler warnings  // Turn off unavoidable compiler warnings
210    
211  #if defined(_MSC_VER) && (_MSC_VER > 1100)  #if defined(_MSC_VER) && (_MSC_VER > 1100)
212          #pragma once          #pragma once
213          #pragma component(browser, off, references, "CStdString")          #pragma component(browser, off, references, "CStdString")
214          #pragma warning (disable : 4290) // C++ Exception Specification ignored          #pragma warning (disable : 4290) // C++ Exception Specification ignored
215          #pragma warning (disable : 4127) // Conditional expression is constant          #pragma warning (disable : 4127) // Conditional expression is constant
216          #pragma warning (disable : 4097) // typedef name used as synonym for class name          #pragma warning (disable : 4097) // typedef name used as synonym for class name
217  #endif  #endif
218    
219  #ifndef STDSTRING_H  #ifndef STDSTRING_H
220  #define STDSTRING_H  #define STDSTRING_H
221    
222  // MACRO: SS_NO_REFCOUNT:  // MACRO: SS_NO_REFCOUNT:
223  //              turns off reference counting at the assignment level  //              turns off reference counting at the assignment level
224  //              I define this by default.  comment it out if you don't want it.  //              I define this by default.  comment it out if you don't want it.
225    
226  #define SS_NO_REFCOUNT    #define SS_NO_REFCOUNT  
227    
228  // In non-Visual C++ and/or non-Win32 builds, we can't use some cool stuff.  // In non-Visual C++ and/or non-Win32 builds, we can't use some cool stuff.
229    
230  #if !defined(_MSC_VER) || !defined(_WIN32)  #if !defined(_MSC_VER) || !defined(_WIN32)
231          #define SS_ANSI          #define SS_ANSI
232  #endif  #endif
233    
234  // Avoid legacy code screw up: if _UNICODE is defined, UNICODE must be as well  // Avoid legacy code screw up: if _UNICODE is defined, UNICODE must be as well
235    
236  #if defined (_UNICODE) && !defined (UNICODE)  #if defined (_UNICODE) && !defined (UNICODE)
237          #define UNICODE          #define UNICODE
238  #endif  #endif
239  #if defined (UNICODE) && !defined (_UNICODE)  #if defined (UNICODE) && !defined (_UNICODE)
240          #define _UNICODE          #define _UNICODE
241  #endif  #endif
242    
243  // -----------------------------------------------------------------------------  // -----------------------------------------------------------------------------
244  // MIN and MAX.  The Standard C++ template versions go by so many names (at  // MIN and MAX.  The Standard C++ template versions go by so many names (at
245  // at least in the MS implementation) that you never know what's available  // at least in the MS implementation) that you never know what's available
246  // -----------------------------------------------------------------------------  // -----------------------------------------------------------------------------
247  template<class Type>  template<class Type>
248  inline const Type& SSMIN(const Type& arg1, const Type& arg2)  inline const Type& SSMIN(const Type& arg1, const Type& arg2)
249  {  {
250          return arg2 < arg1 ? arg2 : arg1;          return arg2 < arg1 ? arg2 : arg1;
251  }  }
252  template<class Type>  template<class Type>
253  inline const Type& SSMAX(const Type& arg1, const Type& arg2)  inline const Type& SSMAX(const Type& arg1, const Type& arg2)
254  {  {
255          return arg2 > arg1 ? arg2 : arg1;          return arg2 > arg1 ? arg2 : arg1;
256  }  }
257    
258  // If they have not #included W32Base.h (part of my W32 utility library) then  // If they have not #included W32Base.h (part of my W32 utility library) then
259  // we need to define some stuff.  Otherwise, this is all defined there.  // we need to define some stuff.  Otherwise, this is all defined there.
260    
261  #if !defined(W32BASE_H)  #if !defined(W32BASE_H)
262    
263          // If they want us to use only standard C++ stuff (no Win32 stuff)          // If they want us to use only standard C++ stuff (no Win32 stuff)
264    
265          #ifdef SS_ANSI          #ifdef SS_ANSI
266    
267                  // On non-Win32 platforms, there is no TCHAR.H so define what we need                  // On non-Win32 platforms, there is no TCHAR.H so define what we need
268    
269                  #ifndef _WIN32                  #ifndef _WIN32
270    
271                          typedef const char*             PCSTR;                          typedef const char*             PCSTR;
272                          typedef char*                   PSTR;                          typedef char*                   PSTR;
273                          typedef const wchar_t*  PCWSTR;                          typedef const wchar_t*  PCWSTR;
274                          typedef wchar_t*                PWSTR;                          typedef wchar_t*                PWSTR;
275                          #ifdef UNICODE                          #ifdef UNICODE
276                                  typedef wchar_t         TCHAR;                                  typedef wchar_t         TCHAR;
277                          #else                          #else
278                                  typedef char            TCHAR;                                  typedef char            TCHAR;
279                          #endif                          #endif
280                          typedef wchar_t                 OLECHAR;                          typedef wchar_t                 OLECHAR;
281    
282                  #else                  #else
283    
284                          #include <TCHAR.H>                          #include <TCHAR.H>
285                          #include <WTYPES.H>                          #include <WTYPES.H>
286                          #ifndef STRICT                          #ifndef STRICT
287                                  #define STRICT                                  #define STRICT
288                          #endif                          #endif
289    
290                  #endif  // #ifndef _WIN32                  #endif  // #ifndef _WIN32
291    
292    
293                  // Make sure ASSERT and verify are defined in an ANSI fashion                  // Make sure ASSERT and verify are defined in an ANSI fashion
294    
295                  #ifndef ASSERT                  #ifndef ASSERT
296                          #include <assert.h>                          #include <assert.h>
297                          #define ASSERT(f) assert((f))                          #define ASSERT(f) assert((f))
298                  #endif                  #endif
299                  #ifndef VERIFY                  #ifndef VERIFY
300                          #ifdef _DEBUG                          #ifdef _DEBUG
301                                  #define VERIFY(x) ASSERT((x))                                  #define VERIFY(x) ASSERT((x))
302                          #else                          #else
303                                  #define VERIFY(x) x                                  #define VERIFY(x) x
304                          #endif                          #endif
305                  #endif                  #endif
306    
307          #else // #ifdef SS_ANSI          #else // #ifdef SS_ANSI
308    
309                  #include <TCHAR.H>                  #include <TCHAR.H>
310                  #include <WTYPES.H>                  #include <WTYPES.H>
311                  #ifndef STRICT                  #ifndef STRICT
312                          #define STRICT                          #define STRICT
313                  #endif                  #endif
314    
315                  // Make sure ASSERT and verify are defined                  // Make sure ASSERT and verify are defined
316    
317                  #ifndef ASSERT                  #ifndef ASSERT
318                          #include <crtdbg.h>                          #include <crtdbg.h>
319                          #define ASSERT(f) _ASSERTE((f))                          #define ASSERT(f) _ASSERTE((f))
320                  #endif                  #endif
321                  #ifndef VERIFY                  #ifndef VERIFY
322                          #ifdef _DEBUG                          #ifdef _DEBUG
323                                  #define VERIFY(x) ASSERT((x))                                  #define VERIFY(x) ASSERT((x))
324                          #else                          #else
325                                  #define VERIFY(x) x                                  #define VERIFY(x) x
326                          #endif                          #endif
327                  #endif                  #endif
328    
329          #endif // #ifdef SS_ANSI          #endif // #ifdef SS_ANSI
330    
331          #ifndef UNUSED          #ifndef UNUSED
332                  #define UNUSED(x) x                  #define UNUSED(x) x
333          #endif          #endif
334    
335  #endif // #ifndef W32BASE_H  #endif // #ifndef W32BASE_H
336    
337  // Standard headers needed  // Standard headers needed
338    
339  #include <string>                       // basic_string  #include <string>                       // basic_string
340  #include <algorithm>            // for_each, etc.  #include <algorithm>            // for_each, etc.
341  #include <functional>           // for StdStringLessNoCase, et al  #include <functional>           // for StdStringLessNoCase, et al
342  #include <locale>                       // for various facets  #include <locale>                       // for various facets
343    
344  // If this is a recent enough version of VC include comdef.h, so we can write  // If this is a recent enough version of VC include comdef.h, so we can write
345  // member functions to deal with COM types & compiler support classes e.g. _bstr_t  // member functions to deal with COM types & compiler support classes e.g. _bstr_t
346    
347  #if defined (_MSC_VER) && (_MSC_VER >= 1100)  #if defined (_MSC_VER) && (_MSC_VER >= 1100)
348          #include <comdef.h>          #include <comdef.h>
349          #define SS_INC_COMDEF           // signal that we #included MS comdef.h file          #define SS_INC_COMDEF           // signal that we #included MS comdef.h file
350          #define STDSTRING_INC_COMDEF          #define STDSTRING_INC_COMDEF
351          #define SS_NOTHROW __declspec(nothrow)          #define SS_NOTHROW __declspec(nothrow)
352  #else  #else
353          #define SS_NOTHROW          #define SS_NOTHROW
354  #endif  #endif
355    
356  #ifndef TRACE  #ifndef TRACE
357          #define TRACE_DEFINED_HERE          #define TRACE_DEFINED_HERE
358          #define TRACE          #define TRACE
359  #endif  #endif
360    
361  // Microsoft defines PCSTR, PCWSTR, etc, but no PCTSTR.  I hate to use the  // Microsoft defines PCSTR, PCWSTR, etc, but no PCTSTR.  I hate to use the
362  // versions with the "L" in front of them because that's a leftover from Win 16  // versions with the "L" in front of them because that's a leftover from Win 16
363  // days, even though it evaluates to the same thing.  Therefore, Define a PCSTR  // days, even though it evaluates to the same thing.  Therefore, Define a PCSTR
364  // as an LPCTSTR.  // as an LPCTSTR.
365    
366  #if !defined(PCTSTR) && !defined(PCTSTR_DEFINED)  #if !defined(PCTSTR) && !defined(PCTSTR_DEFINED)
367          typedef const TCHAR*                    PCTSTR;          typedef const TCHAR*                    PCTSTR;
368          #define PCTSTR_DEFINED          #define PCTSTR_DEFINED
369  #endif  #endif
370    
371  #if !defined(PCOLESTR) && !defined(PCOLESTR_DEFINED)  #if !defined(PCOLESTR) && !defined(PCOLESTR_DEFINED)
372          typedef const OLECHAR*                  PCOLESTR;          typedef const OLECHAR*                  PCOLESTR;
373          #define PCOLESTR_DEFINED          #define PCOLESTR_DEFINED
374  #endif  #endif
375    
376  #if !defined(POLESTR) && !defined(POLESTR_DEFINED)  #if !defined(POLESTR) && !defined(POLESTR_DEFINED)
377          typedef OLECHAR*                                POLESTR;          typedef OLECHAR*                                POLESTR;
378          #define POLESTR_DEFINED          #define POLESTR_DEFINED
379  #endif  #endif
380    
381  #if !defined(PCUSTR) && !defined(PCUSTR_DEFINED)  #if !defined(PCUSTR) && !defined(PCUSTR_DEFINED)
382          typedef const unsigned char*    PCUSTR;          typedef const unsigned char*    PCUSTR;
383          typedef unsigned char*                  PUSTR;          typedef unsigned char*                  PUSTR;
384          #define PCUSTR_DEFINED          #define PCUSTR_DEFINED
385  #endif  #endif
386    
387  // SS_USE_FACET macro and why we need it:  // SS_USE_FACET macro and why we need it:
388  //  //
389  // Since I'm a good little Standard C++ programmer, I use locales.  Thus, I  // Since I'm a good little Standard C++ programmer, I use locales.  Thus, I
390  // need to make use of the use_facet<> template function here.   Unfortunately,  // need to make use of the use_facet<> template function here.   Unfortunately,
391  // this need is complicated by the fact the MS' implementation of the Standard  // this need is complicated by the fact the MS' implementation of the Standard
392  // C++ Library has a non-standard version of use_facet that takes more  // C++ Library has a non-standard version of use_facet that takes more
393  // arguments than the standard dictates.  Since I'm trying to write CStdString  // arguments than the standard dictates.  Since I'm trying to write CStdString
394  // to work with any version of the Standard library, this presents a problem.  // to work with any version of the Standard library, this presents a problem.
395  //  //
396  // The upshot of this is that I can't do 'use_facet' directly.  The MS' docs  // The upshot of this is that I can't do 'use_facet' directly.  The MS' docs
397  // tell me that I have to use a macro, _USE() instead.  Since _USE obviously  // tell me that I have to use a macro, _USE() instead.  Since _USE obviously
398  // won't be available in other implementations, this means that I have to write  // won't be available in other implementations, this means that I have to write
399  // my OWN macro -- SS_USE_FACET -- that evaluates either to _USE or to the  // my OWN macro -- SS_USE_FACET -- that evaluates either to _USE or to the
400  // standard, use_facet.  // standard, use_facet.
401  //  //
402  // If you are having trouble with the SS_USE_FACET macro, in your implementation  // If you are having trouble with the SS_USE_FACET macro, in your implementation
403  // of the Standard C++ Library, you can define your own version of SS_USE_FACET.  // of the Standard C++ Library, you can define your own version of SS_USE_FACET.
404  #ifndef schMSG  #ifndef schMSG
405          #define schSTR(x)          #x          #define schSTR(x)          #x
406          #define schSTR2(x)      schSTR(x)          #define schSTR2(x)      schSTR(x)
407          #define schMSG(desc) message(__FILE__ "(" schSTR2(__LINE__) "):" #desc)          #define schMSG(desc) message(__FILE__ "(" schSTR2(__LINE__) "):" #desc)
408  #endif  #endif
409    
410  #ifndef SS_USE_FACET  #ifndef SS_USE_FACET
411          // STLPort #defines a macro (__STL_NO_EXPLICIT_FUNCTION_TMPL_ARGS) for          // STLPort #defines a macro (__STL_NO_EXPLICIT_FUNCTION_TMPL_ARGS) for
412          // all MSVC builds, erroneously in my opinion.  It causes problems for          // all MSVC builds, erroneously in my opinion.  It causes problems for
413          // my SS_ANSI builds.  In my code, I always comment out that line.  You'll          // my SS_ANSI builds.  In my code, I always comment out that line.  You'll
414          // find it in   \stlport\config\stl_msvc.h          // find it in   \stlport\config\stl_msvc.h
415          #if defined(__SGI_STL_PORT) && (__SGI_STL_PORT >= 0x400 )          #if defined(__SGI_STL_PORT) && (__SGI_STL_PORT >= 0x400 )
416                  #if defined(__STL_NO_EXPLICIT_FUNCTION_TMPL_ARGS) && defined(_MSC_VER)                  #if defined(__STL_NO_EXPLICIT_FUNCTION_TMPL_ARGS) && defined(_MSC_VER)
417                          #ifdef SS_ANSI                          #ifdef SS_ANSI
418                                  #pragma schMSG(__STL_NO_EXPLICIT_FUNCTION_TMPL_ARGS defined!!)                                  #pragma schMSG(__STL_NO_EXPLICIT_FUNCTION_TMPL_ARGS defined!!)
419                          #endif                          #endif
420                  #endif                  #endif
421                  #define SS_USE_FACET(loc, fac) std::use_facet<fac >(loc)                  #define SS_USE_FACET(loc, fac) std::use_facet<fac >(loc)
422          #elif defined(_MSC_VER )          #elif defined(_MSC_VER )
423                  #define SS_USE_FACET(loc, fac) _USE(loc, fac)                  #define SS_USE_FACET(loc, fac) _USE(loc, fac)
424    
425          // ...and          // ...and
426          #elif defined(_RWSTD_NO_TEMPLATE_ON_RETURN_TYPE)          #elif defined(_RWSTD_NO_TEMPLATE_ON_RETURN_TYPE)
427          #define SS_USE_FACET(loc, fac) std::use_facet(loc, (fac*)0)          #define SS_USE_FACET(loc, fac) std::use_facet(loc, (fac*)0)
428          #else          #else
429                  #define SS_USE_FACET(loc, fac) std::use_facet<fac >(loc)                  #define SS_USE_FACET(loc, fac) std::use_facet<fac >(loc)
430          #endif          #endif
431  #endif  #endif
432    
433  // =============================================================================  // =============================================================================
434  // UNICODE/MBCS conversion macros.  Made to work just like the MFC/ATL ones.  // UNICODE/MBCS conversion macros.  Made to work just like the MFC/ATL ones.
435  // =============================================================================  // =============================================================================
436    
437  // First define the conversion helper functions.  We define these regardless of  // First define the conversion helper functions.  We define these regardless of
438  // any preprocessor macro settings since their names won't collide.  // any preprocessor macro settings since their names won't collide.
439    
440  #ifdef SS_ANSI // Are we doing things the standard, non-Win32 way?...  #ifdef SS_ANSI // Are we doing things the standard, non-Win32 way?...
441    
442          typedef std::codecvt<wchar_t, char, mbstate_t> SSCodeCvt;          typedef std::codecvt<wchar_t, char, mbstate_t> SSCodeCvt;
443    
444          // Not sure if we need all these headers.   I believe ANSI says we do.          // Not sure if we need all these headers.   I believe ANSI says we do.
445    
446          #include <stdio.h>          #include <stdio.h>
447          #include <stdarg.h>          #include <stdarg.h>
448          #include <wchar.h>          #include <wchar.h>
449          #ifndef va_start          #ifndef va_start
450                  #include <varargs.h>                  #include <varargs.h>
451          #endif          #endif
452    
453          // StdCodeCvt - made to look like Win32 functions WideCharToMultiByte annd          // StdCodeCvt - made to look like Win32 functions WideCharToMultiByte annd
454          //              MultiByteToWideChar but uses locales in SS_ANSI builds          //              MultiByteToWideChar but uses locales in SS_ANSI builds
455          inline PWSTR StdCodeCvt(PWSTR pW, PCSTR pA, int nChars,          inline PWSTR StdCodeCvt(PWSTR pW, PCSTR pA, int nChars,
456                  const std::locale& loc=std::locale())                  const std::locale& loc=std::locale())
457          {          {
458                  ASSERT(0 != pA);                  ASSERT(0 != pA);
459                  ASSERT(0 != pW);                  ASSERT(0 != pW);
460                  pW[0] = '\0';                  pW[0] = '\0';
461                  PCSTR pBadA                             = 0;                  PCSTR pBadA                             = 0;
462                  PWSTR pBadW                             = 0;                  PWSTR pBadW                             = 0;
463                  SSCodeCvt::result res   = SSCodeCvt::ok;                  SSCodeCvt::result res   = SSCodeCvt::ok;
464                  const SSCodeCvt& conv   = SS_USE_FACET(loc, SSCodeCvt);                  const SSCodeCvt& conv   = SS_USE_FACET(loc, SSCodeCvt);
465          SSCodeCvt::state_type st= { 0 };          SSCodeCvt::state_type st= { 0 };
466                  res                                             = conv.in(st,                  res                                             = conv.in(st,
467                                                                                    pA, pA + nChars, pBadA,                                                                                    pA, pA + nChars, pBadA,
468                                                                                    pW, pW + nChars, pBadW);                                                                                    pW, pW + nChars, pBadW);
469                  ASSERT(SSCodeCvt::ok == res);                  ASSERT(SSCodeCvt::ok == res);
470                  return pW;                  return pW;
471          }          }
472          inline PWSTR StdCodeCvt(PWSTR pW, PCUSTR pA, int nChars,          inline PWSTR StdCodeCvt(PWSTR pW, PCUSTR pA, int nChars,
473                  const std::locale& loc=std::locale())                  const std::locale& loc=std::locale())
474          {          {
475                  return StdCodeCvt(pW, (PCSTR)pA, nChars, loc);                  return StdCodeCvt(pW, (PCSTR)pA, nChars, loc);
476          }          }
477    
478          inline PSTR StdCodeCvt(PSTR pA, PCWSTR pW, int nChars,          inline PSTR StdCodeCvt(PSTR pA, PCWSTR pW, int nChars,
479                  const std::locale& loc=std::locale())                  const std::locale& loc=std::locale())
480          {          {
481                  ASSERT(0 != pA);                  ASSERT(0 != pA);
482                  ASSERT(0 != pW);                  ASSERT(0 != pW);
483                  pA[0] = '\0';                  pA[0] = '\0';
484                  PSTR pBadA                              = 0;                  PSTR pBadA                              = 0;
485                  PCWSTR pBadW                    = 0;                  PCWSTR pBadW                    = 0;
486                  SSCodeCvt::result res   = SSCodeCvt::ok;                  SSCodeCvt::result res   = SSCodeCvt::ok;
487                  const SSCodeCvt& conv   = SS_USE_FACET(loc, SSCodeCvt);                  const SSCodeCvt& conv   = SS_USE_FACET(loc, SSCodeCvt);
488          SSCodeCvt::state_type st= { 0 };          SSCodeCvt::state_type st= { 0 };
489                  res                                             = conv.out(st,                  res                                             = conv.out(st,
490                                                                                     pW, pW + nChars, pBadW,                                                                                     pW, pW + nChars, pBadW,
491                                                                                     pA, pA + nChars, pBadA);                                                                                     pA, pA + nChars, pBadA);
492                  ASSERT(SSCodeCvt::ok == res);                  ASSERT(SSCodeCvt::ok == res);
493                  return pA;                  return pA;
494          }          }
495          inline PUSTR StdCodeCvt(PUSTR pA, PCWSTR pW, int nChars,          inline PUSTR StdCodeCvt(PUSTR pA, PCWSTR pW, int nChars,
496                  const std::locale& loc=std::locale())                  const std::locale& loc=std::locale())
497          {          {
498                  return (PUSTR)StdCodeCvt((PSTR)pA, pW, nChars, loc);                  return (PUSTR)StdCodeCvt((PSTR)pA, pW, nChars, loc);
499          }          }
500    
501  #else   // ...or are we doing things assuming win32 and Visual C++?  #else   // ...or are we doing things assuming win32 and Visual C++?
502    
503          #include <malloc.h>     // needed for _alloca          #include <malloc.h>     // needed for _alloca
504    
505          inline PWSTR StdCodeCvt(PWSTR pW, PCSTR pA, int nChars, UINT acp=CP_ACP)          inline PWSTR StdCodeCvt(PWSTR pW, PCSTR pA, int nChars, UINT acp=CP_ACP)
506          {          {
507                  ASSERT(0 != pA);                  ASSERT(0 != pA);
508                  ASSERT(0 != pW);                  ASSERT(0 != pW);
509                  pW[0] = '\0';                  pW[0] = '\0';
510                  MultiByteToWideChar(acp, 0, pA, -1, pW, nChars);                  MultiByteToWideChar(acp, 0, pA, -1, pW, nChars);
511                  return pW;                  return pW;
512          }          }
513          inline PWSTR StdCodeCvt(PWSTR pW, PCUSTR pA, int nChars, UINT acp=CP_ACP)          inline PWSTR StdCodeCvt(PWSTR pW, PCUSTR pA, int nChars, UINT acp=CP_ACP)
514          {          {
515                  return StdCodeCvt(pW, (PCSTR)pA, nChars, acp);                  return StdCodeCvt(pW, (PCSTR)pA, nChars, acp);
516          }          }
517    
518          inline PSTR StdCodeCvt(PSTR pA, PCWSTR pW, int nChars, UINT acp=CP_ACP)          inline PSTR StdCodeCvt(PSTR pA, PCWSTR pW, int nChars, UINT acp=CP_ACP)
519          {          {
520                  ASSERT(0 != pA);                  ASSERT(0 != pA);
521                  ASSERT(0 != pW);                  ASSERT(0 != pW);
522                  pA[0] = '\0';                  pA[0] = '\0';
523                  WideCharToMultiByte(acp, 0, pW, -1, pA, nChars, 0, 0);                  WideCharToMultiByte(acp, 0, pW, -1, pA, nChars, 0, 0);
524                  return pA;                  return pA;
525          }          }
526          inline PUSTR StdCodeCvt(PUSTR pA, PCWSTR pW, int nChars, UINT acp=CP_ACP)          inline PUSTR StdCodeCvt(PUSTR pA, PCWSTR pW, int nChars, UINT acp=CP_ACP)
527          {          {
528                  return (PUSTR)StdCodeCvt((PSTR)pA, pW, nChars, acp);                  return (PUSTR)StdCodeCvt((PSTR)pA, pW, nChars, acp);
529          }          }
530    
531          // Define our conversion macros to look exactly like Microsoft's to          // Define our conversion macros to look exactly like Microsoft's to
532          // facilitate using this stuff both with and without MFC/ATL          // facilitate using this stuff both with and without MFC/ATL
533    
534          #ifdef _CONVERSION_USES_THREAD_LOCALE          #ifdef _CONVERSION_USES_THREAD_LOCALE
535                  #ifndef _DEBUG                  #ifndef _DEBUG
536                          #define SSCVT int _cvt; _cvt; UINT _acp=GetACP(); \                          #define SSCVT int _cvt; _cvt; UINT _acp=GetACP(); \
537                                  _acp; PCWSTR _pw; _pw; PCSTR _pa; _pa                                  _acp; PCWSTR _pw; _pw; PCSTR _pa; _pa
538                  #else                  #else
539                          #define SSCVT int _cvt = 0; _cvt; UINT _acp=GetACP();\                          #define SSCVT int _cvt = 0; _cvt; UINT _acp=GetACP();\
540                                   _acp; PCWSTR _pw=0; _pw; PCSTR _pa=0; _pa                                   _acp; PCWSTR _pw=0; _pw; PCSTR _pa=0; _pa
541                  #endif                  #endif
542          #else          #else
543                  #ifndef _DEBUG                  #ifndef _DEBUG
544                          #define SSCVT int _cvt; _cvt; UINT _acp=CP_ACP; _acp;\                          #define SSCVT int _cvt; _cvt; UINT _acp=CP_ACP; _acp;\
545                                   PCWSTR _pw; _pw; PCSTR _pa; _pa                                   PCWSTR _pw; _pw; PCSTR _pa; _pa
546                  #else                  #else
547                          #define SSCVT int _cvt = 0; _cvt; UINT _acp=CP_ACP; \                          #define SSCVT int _cvt = 0; _cvt; UINT _acp=CP_ACP; \
548                                  _acp; PCWSTR _pw=0; _pw; PCSTR _pa=0; _pa                                  _acp; PCWSTR _pw=0; _pw; PCSTR _pa=0; _pa
549                  #endif                  #endif
550          #endif          #endif
551    
552          #ifdef _CONVERSION_USES_THREAD_LOCALE          #ifdef _CONVERSION_USES_THREAD_LOCALE
553                  #define SSA2W(pa) (\                  #define SSA2W(pa) (\
554                          ((_pa = pa) == 0) ? 0 : (\                          ((_pa = pa) == 0) ? 0 : (\
555                                  _cvt = (strlen(_pa)+1),\                                  _cvt = (strlen(_pa)+1),\
556                                  StdCodeCvt((PWSTR) _alloca(_cvt*2), _pa, _cvt, _acp)))                                  StdCodeCvt((PWSTR) _alloca(_cvt*2), _pa, _cvt, _acp)))
557                  #define SSW2A(pw) (\                  #define SSW2A(pw) (\
558                          ((_pw = pw) == 0) ? 0 : (\                          ((_pw = pw) == 0) ? 0 : (\
559                                  _cvt = (wcslen(_pw)+1)*2,\                                  _cvt = (wcslen(_pw)+1)*2,\
560                                  StdW2AHelper((LPSTR) _alloca(_cvt), _pw, _cvt, _acp)))                                  StdW2AHelper((LPSTR) _alloca(_cvt), _pw, _cvt, _acp)))
561          #else          #else
562                  #define SSA2W(pa) (\                  #define SSA2W(pa) (\
563                          ((_pa = pa) == 0) ? 0 : (\                          ((_pa = pa) == 0) ? 0 : (\
564                                  _cvt = (strlen(_pa)+1),\                                  _cvt = (strlen(_pa)+1),\
565                                  StdCodeCvt((PWSTR) _alloca(_cvt*2), _pa, _cvt)))                                  StdCodeCvt((PWSTR) _alloca(_cvt*2), _pa, _cvt)))
566                  #define SSW2A(pw) (\                  #define SSW2A(pw) (\
567                          ((_pw = pw) == 0) ? 0 : (\                          ((_pw = pw) == 0) ? 0 : (\
568                                  _cvt = (wcslen(_pw)+1)*2,\                                  _cvt = (wcslen(_pw)+1)*2,\
569                                  StdCodeCvt((LPSTR) _alloca(_cvt), _pw, _cvt)))                                  StdCodeCvt((LPSTR) _alloca(_cvt), _pw, _cvt)))
570          #endif          #endif
571    
572          #define SSA2CW(pa) ((PCWSTR)SSA2W((pa)))          #define SSA2CW(pa) ((PCWSTR)SSA2W((pa)))
573          #define SSW2CA(pw) ((PCSTR)SSW2A((pw)))          #define SSW2CA(pw) ((PCSTR)SSW2A((pw)))
574    
575          #ifdef UNICODE          #ifdef UNICODE
576                  #define SST2A   SSW2A                  #define SST2A   SSW2A
577                  #define SSA2T   SSA2W                  #define SSA2T   SSA2W
578                  #define SST2CA  SSW2CA                  #define SST2CA  SSW2CA
579                  #define SSA2CT  SSA2CW                  #define SSA2CT  SSA2CW
580                  inline PWSTR    SST2W(PTSTR p)                  { return p; }                  inline PWSTR    SST2W(PTSTR p)                  { return p; }
581                  inline PTSTR    SSW2T(PWSTR p)                  { return p; }                  inline PTSTR    SSW2T(PWSTR p)                  { return p; }
582                  inline PCWSTR   SST2CW(PCTSTR p)                { return p; }                  inline PCWSTR   SST2CW(PCTSTR p)                { return p; }
583                  inline PCTSTR   SSW2CT(PCWSTR p)                { return p; }                  inline PCTSTR   SSW2CT(PCWSTR p)                { return p; }
584          #else          #else
585                  #define SST2W   SSA2W                  #define SST2W   SSA2W
586                  #define SSW2T   SSW2A                  #define SSW2T   SSW2A
587                  #define SST2CW  SSA2CW                  #define SST2CW  SSA2CW
588                  #define SSW2CT  SSW2CA                  #define SSW2CT  SSW2CA
589                  inline PSTR             SST2A(PTSTR p)                  { return p; }                  inline PSTR             SST2A(PTSTR p)                  { return p; }
590                  inline PTSTR    SSA2T(PSTR p)                   { return p; }                  inline PTSTR    SSA2T(PSTR p)                   { return p; }
591                  inline PCSTR    SST2CA(PCTSTR p)                { return p; }                  inline PCSTR    SST2CA(PCTSTR p)                { return p; }
592                  inline PCTSTR   SSA2CT(PCSTR p)                 { return p; }                  inline PCTSTR   SSA2CT(PCSTR p)                 { return p; }
593          #endif // #ifdef UNICODE          #endif // #ifdef UNICODE
594    
595          #if defined(UNICODE)          #if defined(UNICODE)
596          // in these cases the default (TCHAR) is the same as OLECHAR          // in these cases the default (TCHAR) is the same as OLECHAR
597                  inline PCOLESTR SST2COLE(PCTSTR p)              { return p; }                  inline PCOLESTR SST2COLE(PCTSTR p)              { return p; }
598                  inline PCTSTR   SSOLE2CT(PCOLESTR p)    { return p; }                  inline PCTSTR   SSOLE2CT(PCOLESTR p)    { return p; }
599                  inline POLESTR  SST2OLE(PTSTR p)                { return p; }                  inline POLESTR  SST2OLE(PTSTR p)                { return p; }
600                  inline PTSTR    SSOLE2T(POLESTR p)              { return p; }                  inline PTSTR    SSOLE2T(POLESTR p)              { return p; }
601          #elif defined(OLE2ANSI)          #elif defined(OLE2ANSI)
602          // in these cases the default (TCHAR) is the same as OLECHAR          // in these cases the default (TCHAR) is the same as OLECHAR
603                  inline PCOLESTR SST2COLE(PCTSTR p)              { return p; }                  inline PCOLESTR SST2COLE(PCTSTR p)              { return p; }
604                  inline PCTSTR   SSOLE2CT(PCOLESTR p)    { return p; }                  inline PCTSTR   SSOLE2CT(PCOLESTR p)    { return p; }
605                  inline POLESTR  SST2OLE(PTSTR p)                { return p; }                  inline POLESTR  SST2OLE(PTSTR p)                { return p; }
606                  inline PTSTR    SSOLE2T(POLESTR p)              { return p; }                  inline PTSTR    SSOLE2T(POLESTR p)              { return p; }
607          #else          #else
608                  //CharNextW doesn't work on Win95 so we use this                  //CharNextW doesn't work on Win95 so we use this
609                  #define SST2COLE(pa)    SSA2CW((pa))                  #define SST2COLE(pa)    SSA2CW((pa))
610                  #define SST2OLE(pa)             SSA2W((pa))                  #define SST2OLE(pa)             SSA2W((pa))
611                  #define SSOLE2CT(po)    SSW2CA((po))                  #define SSOLE2CT(po)    SSW2CA((po))
612                  #define SSOLE2T(po)             SSW2A((po))                  #define SSOLE2T(po)             SSW2A((po))
613          #endif          #endif
614    
615          #ifdef OLE2ANSI          #ifdef OLE2ANSI
616                  #define SSW2OLE         SSW2A                  #define SSW2OLE         SSW2A
617                  #define SSOLE2W         SSA2W                  #define SSOLE2W         SSA2W
618                  #define SSW2COLE        SSW2CA                  #define SSW2COLE        SSW2CA
619                  #define SSOLE2CW        SSA2CW                  #define SSOLE2CW        SSA2CW
620                  inline POLESTR          SSA2OLE(PSTR p)         { return p; }                  inline POLESTR          SSA2OLE(PSTR p)         { return p; }
621                  inline PSTR                     SSOLE2A(POLESTR p)      { return p; }                  inline PSTR                     SSOLE2A(POLESTR p)      { return p; }
622                  inline PCOLESTR         SSA2COLE(PCSTR p)       { return p; }                  inline PCOLESTR         SSA2COLE(PCSTR p)       { return p; }
623                  inline PCSTR            SSOLE2CA(PCOLESTR p){ return p; }                  inline PCSTR            SSOLE2CA(PCOLESTR p){ return p; }
624          #else          #else
625                  #define SSA2OLE         SSA2W                  #define SSA2OLE         SSA2W
626                  #define SSOLE2A         SSW2A                  #define SSOLE2A         SSW2A
627                  #define SSA2COLE        SSA2CW                  #define SSA2COLE        SSA2CW
628                  #define SSOLE2CA        SSW2CA                  #define SSOLE2CA        SSW2CA
629                  inline POLESTR          SSW2OLE(PWSTR p)        { return p; }                  inline POLESTR          SSW2OLE(PWSTR p)        { return p; }
630                  inline PWSTR            SSOLE2W(POLESTR p)      { return p; }                  inline PWSTR            SSOLE2W(POLESTR p)      { return p; }
631                  inline PCOLESTR         SSW2COLE(PCWSTR p)      { return p; }                  inline PCOLESTR         SSW2COLE(PCWSTR p)      { return p; }
632                  inline PCWSTR           SSOLE2CW(PCOLESTR p){ return p; }                  inline PCWSTR           SSOLE2CW(PCOLESTR p){ return p; }
633          #endif          #endif
634    
635          // Above we've defined macros that look like MS' but all have          // Above we've defined macros that look like MS' but all have
636          // an 'SS' prefix.  Now we need the real macros.  We'll either          // an 'SS' prefix.  Now we need the real macros.  We'll either
637          // get them from the macros above or from MFC/ATL.  If          // get them from the macros above or from MFC/ATL.  If
638          // SS_NO_CONVERSION is #defined, we'll forgo them          // SS_NO_CONVERSION is #defined, we'll forgo them
639    
640          #ifndef SS_NO_CONVERSION          #ifndef SS_NO_CONVERSION
641    
642                  #if defined (USES_CONVERSION)                  #if defined (USES_CONVERSION)
643    
644                          #define _NO_STDCONVERSION       // just to be consistent                          #define _NO_STDCONVERSION       // just to be consistent
645    
646                  #else                  #else
647    
648                          #ifdef _MFC_VER                          #ifdef _MFC_VER
649    
650                                  #include <afxconv.h>                                  #include <afxconv.h>
651                                  #define _NO_STDCONVERSION // just to be consistent                                  #define _NO_STDCONVERSION // just to be consistent
652    
653                          #else                          #else
654    
655                                  #define USES_CONVERSION SSCVT                                  #define USES_CONVERSION SSCVT
656                                  #define A2CW                    SSA2CW                                  #define A2CW                    SSA2CW
657                                  #define W2CA                    SSW2CA                                  #define W2CA                    SSW2CA
658                                  #define T2A                             SST2A                                  #define T2A                             SST2A
659                                  #define A2T                             SSA2T                                  #define A2T                             SSA2T
660                                  #define T2W                             SST2W                                  #define T2W                             SST2W
661                                  #define W2T                             SSW2T                                  #define W2T                             SSW2T
662                                  #define T2CA                    SST2CA                                  #define T2CA                    SST2CA
663                                  #define A2CT                    SSA2CT                                  #define A2CT                    SSA2CT
664                                  #define T2CW                    SST2CW                                  #define T2CW                    SST2CW
665                                  #define W2CT                    SSW2CT                                  #define W2CT                    SSW2CT
666                                  #define ocslen                  sslen                                  #define ocslen                  sslen
667                                  #define ocscpy                  sscpy                                  #define ocscpy                  sscpy
668                                  #define T2COLE                  SST2COLE                                  #define T2COLE                  SST2COLE
669                                  #define OLE2CT                  SSOLE2CT                                  #define OLE2CT                  SSOLE2CT
670                                  #define T2OLE                   SST2COLE                                  #define T2OLE                   SST2COLE
671                                  #define OLE2T                   SSOLE2CT                                  #define OLE2T                   SSOLE2CT
672                                  #define A2OLE                   SSA2OLE                                  #define A2OLE                   SSA2OLE
673                                  #define OLE2A                   SSOLE2A                                  #define OLE2A                   SSOLE2A
674                                  #define W2OLE                   SSW2OLE                                  #define W2OLE                   SSW2OLE
675                                  #define OLE2W                   SSOLE2W                                  #define OLE2W                   SSOLE2W
676                                  #define A2COLE                  SSA2COLE                                  #define A2COLE                  SSA2COLE
677                                  #define OLE2CA                  SSOLE2CA                                  #define OLE2CA                  SSOLE2CA
678                                  #define W2COLE                  SSW2COLE                                  #define W2COLE                  SSW2COLE
679                                  #define OLE2CW                  SSOLE2CW                                  #define OLE2CW                  SSOLE2CW
680                                    
681                          #endif // #ifdef _MFC_VER                          #endif // #ifdef _MFC_VER
682                  #endif // #ifndef USES_CONVERSION                  #endif // #ifndef USES_CONVERSION
683          #endif // #ifndef SS_NO_CONVERSION          #endif // #ifndef SS_NO_CONVERSION
684    
685          // Define ostring - generic name for std::basic_string<OLECHAR>          // Define ostring - generic name for std::basic_string<OLECHAR>
686    
687          #if !defined(ostring) && !defined(OSTRING_DEFINED)          #if !defined(ostring) && !defined(OSTRING_DEFINED)
688                  typedef std::basic_string<OLECHAR> ostring;                  typedef std::basic_string<OLECHAR> ostring;
689                  #define OSTRING_DEFINED                  #define OSTRING_DEFINED
690          #endif          #endif
691    
692  #endif // #ifndef SS_ANSI  #endif // #ifndef SS_ANSI
693    
694  // StdCodeCvt when there's no conversion to be done  // StdCodeCvt when there's no conversion to be done
695  inline PSTR StdCodeCvt(PSTR pDst, PCSTR pSrc, int nChars)  inline PSTR StdCodeCvt(PSTR pDst, PCSTR pSrc, int nChars)
696  {  {
697          pDst[0]                         = '\0';          pDst[0]                         = '\0';
698          std::char_traits<char>::copy(pDst, pSrc, nChars);          std::char_traits<char>::copy(pDst, pSrc, nChars);
699          if ( nChars > 0 )          if ( nChars > 0 )
700                  pDst[nChars]    = '\0';                  pDst[nChars]    = '\0';
701    
702          return pDst;          return pDst;
703  }  }
704  inline PSTR StdCodeCvt(PSTR pDst, PCUSTR pSrc, int nChars)  inline PSTR StdCodeCvt(PSTR pDst, PCUSTR pSrc, int nChars)
705  {  {
706          return StdCodeCvt(pDst, (PCSTR)pSrc, nChars);          return StdCodeCvt(pDst, (PCSTR)pSrc, nChars);
707  }  }
708  inline PUSTR StdCodeCvt(PUSTR pDst, PCSTR pSrc, int nChars)  inline PUSTR StdCodeCvt(PUSTR pDst, PCSTR pSrc, int nChars)
709  {  {
710          return (PUSTR)StdCodeCvt((PSTR)pDst, pSrc, nChars);          return (PUSTR)StdCodeCvt((PSTR)pDst, pSrc, nChars);
711  }  }
712    
713  inline PWSTR StdCodeCvt(PWSTR pDst, PCWSTR pSrc, int nChars)  inline PWSTR StdCodeCvt(PWSTR pDst, PCWSTR pSrc, int nChars)
714  {  {
715          pDst[0]                         = '\0';          pDst[0]                         = '\0';
716          std::char_traits<wchar_t>::copy(pDst, pSrc, nChars);          std::char_traits<wchar_t>::copy(pDst, pSrc, nChars);
717          if ( nChars > 0 )          if ( nChars > 0 )
718                  pDst[nChars]    = '\0';                  pDst[nChars]    = '\0';
719    
720          return pDst;          return pDst;
721  }  }
722    
723    
724  // Define tstring -- generic name for std::basic_string<TCHAR>  // Define tstring -- generic name for std::basic_string<TCHAR>
725    
726  #if !defined(tstring) && !defined(TSTRING_DEFINED)  #if !defined(tstring) && !defined(TSTRING_DEFINED)
727          typedef std::basic_string<TCHAR> tstring;          typedef std::basic_string<TCHAR> tstring;
728          #define TSTRING_DEFINED          #define TSTRING_DEFINED
729  #endif  #endif
730    
731  // a very shorthand way of applying the fix for KB problem Q172398  // a very shorthand way of applying the fix for KB problem Q172398
732  // (basic_string assignment bug)  // (basic_string assignment bug)
733    
734  #if defined ( _MSC_VER ) && ( _MSC_VER < 1200 )  #if defined ( _MSC_VER ) && ( _MSC_VER < 1200 )
735          #define Q172398(x) (x).erase()          #define Q172398(x) (x).erase()
736  #else  #else
737          #define Q172398(x)          #define Q172398(x)
738  #endif  #endif
739    
740  // =============================================================================  // =============================================================================
741  // INLINE FUNCTIONS ON WHICH CSTDSTRING RELIES  // INLINE FUNCTIONS ON WHICH CSTDSTRING RELIES
742  //  //
743  // Usually for generic text mapping, we rely on preprocessor macro definitions  // Usually for generic text mapping, we rely on preprocessor macro definitions
744  // to map to string functions.  However the CStdStr<> template cannot use  // to map to string functions.  However the CStdStr<> template cannot use
745  // macro-based generic text mappings because its character types do not get  // macro-based generic text mappings because its character types do not get
746  // resolved until template processing which comes AFTER macro processing.  In  // resolved until template processing which comes AFTER macro processing.  In
747  // other words, UNICODE is of little help to us in the CStdStr template  // other words, UNICODE is of little help to us in the CStdStr template
748  //  //
749  // Therefore, to keep the CStdStr declaration simple, we have these inline  // Therefore, to keep the CStdStr declaration simple, we have these inline
750  // functions.  The template calls them often.  Since they are inline (and NOT  // functions.  The template calls them often.  Since they are inline (and NOT
751  // exported when this is built as a DLL), they will probably be resolved away  // exported when this is built as a DLL), they will probably be resolved away
752  // to nothing.  // to nothing.
753  //  //
754  // Without these functions, the CStdStr<> template would probably have to broken  // Without these functions, the CStdStr<> template would probably have to broken
755  // out into two, almost identical classes.  Either that or it would be a huge,  // out into two, almost identical classes.  Either that or it would be a huge,
756  // convoluted mess, with tons of "if" statements all over the place checking the  // convoluted mess, with tons of "if" statements all over the place checking the
757  // size of template parameter CT.  // size of template parameter CT.
758  //  //
759  // In several cases, you will see two versions of each function.  One version is  // In several cases, you will see two versions of each function.  One version is
760  // the more portable, standard way of doing things, while the other is the  // the more portable, standard way of doing things, while the other is the
761  // non-standard, but often significantly faster Visual C++ way.  // non-standard, but often significantly faster Visual C++ way.
762  // =============================================================================  // =============================================================================
763    
764  // If they defined SS_NO_REFCOUNT, then we must convert all assignments  // If they defined SS_NO_REFCOUNT, then we must convert all assignments
765    
766  #ifdef SS_NO_REFCOUNT  #ifdef SS_NO_REFCOUNT
767          #define SSREF(x) (x).c_str()          #define SSREF(x) (x).c_str()
768  #else  #else
769          #define SSREF(x) (x)          #define SSREF(x) (x)
770  #endif  #endif
771    
772  // -----------------------------------------------------------------------------  // -----------------------------------------------------------------------------
773  // sslen: strlen/wcslen wrappers  // sslen: strlen/wcslen wrappers
774  // -----------------------------------------------------------------------------  // -----------------------------------------------------------------------------
775  template<typename CT> inline int sslen(const CT* pT)  template<typename CT> inline int sslen(const CT* pT)
776  {  {
777          return 0 == pT ? 0 : std::char_traits<CT>::length(pT);          return 0 == pT ? 0 : std::char_traits<CT>::length(pT);
778  }  }
779  inline SS_NOTHROW int sslen(const std::string& s)  inline SS_NOTHROW int sslen(const std::string& s)
780  {  {
781          return s.length();          return s.length();
782  }  }
783  inline SS_NOTHROW int sslen(const std::wstring& s)  inline SS_NOTHROW int sslen(const std::wstring& s)
784  {  {
785          return s.length();          return s.length();
786  }  }
787    
788    
789  // -----------------------------------------------------------------------------  // -----------------------------------------------------------------------------
790  // ssasn: assignment functions -- assign "sSrc" to "sDst"  // ssasn: assignment functions -- assign "sSrc" to "sDst"
791  // -----------------------------------------------------------------------------  // -----------------------------------------------------------------------------
792  typedef std::string::size_type          SS_SIZETYPE; // just for shorthand, really  typedef std::string::size_type          SS_SIZETYPE; // just for shorthand, really
793  typedef std::string::pointer            SS_PTRTYPE;    typedef std::string::pointer            SS_PTRTYPE;  
794  typedef std::wstring::size_type         SW_SIZETYPE;  typedef std::wstring::size_type         SW_SIZETYPE;
795  typedef std::wstring::pointer           SW_PTRTYPE;    typedef std::wstring::pointer           SW_PTRTYPE;  
796    
797  inline void     ssasn(std::string& sDst, const std::string& sSrc)  inline void     ssasn(std::string& sDst, const std::string& sSrc)
798  {  {
799          if ( sDst.c_str() != sSrc.c_str() )          if ( sDst.c_str() != sSrc.c_str() )
800          {          {
801                  sDst.erase();                  sDst.erase();
802                  sDst.assign(SSREF(sSrc));                  sDst.assign(SSREF(sSrc));
803          }          }
804  }  }
805  inline void     ssasn(std::string& sDst, PCSTR pA)  inline void     ssasn(std::string& sDst, PCSTR pA)
806  {  {
807          // Watch out for NULLs, as always.          // Watch out for NULLs, as always.
808    
809          if ( 0 == pA )          if ( 0 == pA )
810          {          {
811                  sDst.erase();                  sDst.erase();
812          }          }
813    
814          // If pA actually points to part of sDst, we must NOT erase(), but          // If pA actually points to part of sDst, we must NOT erase(), but
815          // rather take a substring          // rather take a substring
816    
817          else if ( pA >= sDst.c_str() && pA <= sDst.c_str() + sDst.size() )          else if ( pA >= sDst.c_str() && pA <= sDst.c_str() + sDst.size() )
818          {          {
819                  sDst =sDst.substr(static_cast<SS_SIZETYPE>(pA-sDst.c_str()));                  sDst =sDst.substr(static_cast<SS_SIZETYPE>(pA-sDst.c_str()));
820          }          }
821    
822          // Otherwise (most cases) apply the assignment bug fix, if applicable          // Otherwise (most cases) apply the assignment bug fix, if applicable
823          // and do the assignment          // and do the assignment
824    
825          else          else
826          {          {
827                  Q172398(sDst);                  Q172398(sDst);
828                  sDst.assign(pA);                  sDst.assign(pA);
829          }          }
830  }  }
831  inline void     ssasn(std::string& sDst, const std::wstring& sSrc)  inline void     ssasn(std::string& sDst, const std::wstring& sSrc)
832  {  {
833  #ifdef SS_ANSI  #ifdef SS_ANSI
834          int nLen        = sSrc.size();          int nLen        = sSrc.size();
835          sDst.resize(0);          sDst.resize(0);
836          sDst.resize(nLen);          sDst.resize(nLen);
837          StdCodeCvt(const_cast<SS_PTRTYPE>(sDst.data()), sSrc.c_str(), nLen);          StdCodeCvt(const_cast<SS_PTRTYPE>(sDst.data()), sSrc.c_str(), nLen);
838  #else  #else
839          SSCVT;          SSCVT;
840          sDst.assign(SSW2CA(sSrc.c_str()));          sDst.assign(SSW2CA(sSrc.c_str()));
841  #endif  #endif
842  }  }
843  inline void     ssasn(std::string& sDst, PCWSTR pW)  inline void     ssasn(std::string& sDst, PCWSTR pW)
844  {  {
845  #ifdef SS_ANSI  #ifdef SS_ANSI
846          int nLen        = sslen(pW);          int nLen        = sslen(pW);
847          sDst.resize(0);          sDst.resize(0);
848          sDst.resize(nLen);          sDst.resize(nLen);
849          StdCodeCvt(const_cast<SS_PTRTYPE>(sDst.data()), pW, nLen);          StdCodeCvt(const_cast<SS_PTRTYPE>(sDst.data()), pW, nLen);
850  #else  #else
851          SSCVT;          SSCVT;
852          sDst.assign(pW ? SSW2CA(pW) : "");          sDst.assign(pW ? SSW2CA(pW) : "");
853  #endif  #endif
854  }  }
855  inline void ssasn(std::string& sDst, const int nNull)  inline void ssasn(std::string& sDst, const int nNull)
856  {  {
857          UNUSED(nNull);          UNUSED(nNull);
858          ASSERT(nNull==0);          ASSERT(nNull==0);
859          sDst.assign("");          sDst.assign("");
860  }        }      
861  inline void     ssasn(std::wstring& sDst, const std::wstring& sSrc)  inline void     ssasn(std::wstring& sDst, const std::wstring& sSrc)
862  {  {
863          if ( sDst.c_str() != sSrc.c_str() )          if ( sDst.c_str() != sSrc.c_str() )
864          {          {
865                  sDst.erase();                  sDst.erase();
866                  sDst.assign(SSREF(sSrc));                  sDst.assign(SSREF(sSrc));
867          }          }
868  }  }
869  inline void     ssasn(std::wstring& sDst, PCWSTR pW)  inline void     ssasn(std::wstring& sDst, PCWSTR pW)
870  {  {
871          // Watch out for NULLs, as always.          // Watch out for NULLs, as always.
872    
873          if ( 0 == pW )          if ( 0 == pW )
874          {          {
875                  sDst.erase();                  sDst.erase();
876          }          }
877    
878          // If pW actually points to part of sDst, we must NOT erase(), but          // If pW actually points to part of sDst, we must NOT erase(), but
879          // rather take a substring          // rather take a substring
880    
881          else if ( pW >= sDst.c_str() && pW <= sDst.c_str() + sDst.size() )          else if ( pW >= sDst.c_str() && pW <= sDst.c_str() + sDst.size() )
882          {          {
883                  sDst = sDst.substr(static_cast<SW_SIZETYPE>(pW-sDst.c_str()));                  sDst = sDst.substr(static_cast<SW_SIZETYPE>(pW-sDst.c_str()));
884          }          }
885    
886          // Otherwise (most cases) apply the assignment bug fix, if applicable          // Otherwise (most cases) apply the assignment bug fix, if applicable
887          // and do the assignment          // and do the assignment
888    
889          else          else
890          {          {
891                  Q172398(sDst);                  Q172398(sDst);
892                  sDst.assign(pW);                  sDst.assign(pW);
893          }          }
894  }  }
895  #undef StrSizeType  #undef StrSizeType
896  inline void     ssasn(std::wstring& sDst, const std::string& sSrc)  inline void     ssasn(std::wstring& sDst, const std::string& sSrc)
897  {  {
898  #ifdef SS_ANSI  #ifdef SS_ANSI
899          int nLen        = sSrc.size();          int nLen        = sSrc.size();
900          sDst.resize(0);          sDst.resize(0);
901          sDst.resize(nLen);          sDst.resize(nLen);
902          StdCodeCvt(const_cast<SW_PTRTYPE>(sDst.data()), sSrc.c_str(), nLen);          StdCodeCvt(const_cast<SW_PTRTYPE>(sDst.data()), sSrc.c_str(), nLen);
903  #else  #else
904          SSCVT;          SSCVT;
905          sDst.assign(SSA2CW(sSrc.c_str()));          sDst.assign(SSA2CW(sSrc.c_str()));
906  #endif  #endif
907  }  }
908  inline void     ssasn(std::wstring& sDst, PCSTR pA)  inline void     ssasn(std::wstring& sDst, PCSTR pA)
909  {  {
910  #ifdef SS_ANSI  #ifdef SS_ANSI
911          int nLen        = sslen(pA);          int nLen        = sslen(pA);
912          sDst.resize(0);          sDst.resize(0);
913          sDst.resize(nLen);          sDst.resize(nLen);
914          StdCodeCvt(const_cast<SW_PTRTYPE>(sDst.data()), pA, nLen);          StdCodeCvt(const_cast<SW_PTRTYPE>(sDst.data()), pA, nLen);
915  #else  #else
916          SSCVT;          SSCVT;
917          sDst.assign(pA ? SSA2CW(pA) : L"");          sDst.assign(pA ? SSA2CW(pA) : L"");
918  #endif  #endif
919  }  }
920  inline void ssasn(std::wstring& sDst, const int nNull)  inline void ssasn(std::wstring& sDst, const int nNull)
921  {  {
922          UNUSED(nNull);          UNUSED(nNull);
923          ASSERT(nNull==0);          ASSERT(nNull==0);
924          sDst.assign(L"");          sDst.assign(L"");
925  }  }
926    
927    
928  // -----------------------------------------------------------------------------  // -----------------------------------------------------------------------------
929  // ssadd: string object concatenation -- add second argument to first  // ssadd: string object concatenation -- add second argument to first
930  // -----------------------------------------------------------------------------  // -----------------------------------------------------------------------------
931  inline void     ssadd(std::string& sDst, const std::wstring& sSrc)  inline void     ssadd(std::string& sDst, const std::wstring& sSrc)
932  {  {
933  #ifdef SS_ANSI  #ifdef SS_ANSI
934          int nLen        = sSrc.size();          int nLen        = sSrc.size();
935          sDst.resize(sDst.size() + nLen);          sDst.resize(sDst.size() + nLen);
936          StdCodeCvt(const_cast<SS_PTRTYPE>(sDst.data()+nLen), sSrc.c_str(), nLen);          StdCodeCvt(const_cast<SS_PTRTYPE>(sDst.data()+nLen), sSrc.c_str(), nLen);
937  #else  #else
938          SSCVT;          SSCVT;
939          sDst.append(SSW2CA(sSrc.c_str()));          sDst.append(SSW2CA(sSrc.c_str()));
940  #endif  #endif
941  }  }
942  inline void     ssadd(std::string& sDst, const std::string& sSrc)  inline void     ssadd(std::string& sDst, const std::string& sSrc)
943  {  {
944          sDst.append(sSrc.c_str());          sDst.append(sSrc.c_str());
945  }  }
946  inline void     ssadd(std::string& sDst, PCWSTR pW)  inline void     ssadd(std::string& sDst, PCWSTR pW)
947  {  {
948  #ifdef SS_ANSI  #ifdef SS_ANSI
949          int nLen        = sslen(pW);          int nLen        = sslen(pW);
950          sDst.resize(sDst.size() + nLen);          sDst.resize(sDst.size() + nLen);
951          StdCodeCvt(const_cast<SS_PTRTYPE>(sDst.data()+nLen), pW, nLen);          StdCodeCvt(const_cast<SS_PTRTYPE>(sDst.data()+nLen), pW, nLen);
952  #else  #else
953          SSCVT;          SSCVT;
954          if ( 0 != pW )          if ( 0 != pW )
955                  sDst.append(SSW2CA(pW));                  sDst.append(SSW2CA(pW));
956  #endif  #endif
957  }  }
958  inline void     ssadd(std::string& sDst, PCSTR pA)  inline void     ssadd(std::string& sDst, PCSTR pA)
959  {  {
960          if ( pA )          if ( pA )
961                  sDst.append(pA);                  sDst.append(pA);
962  }  }
963  inline void     ssadd(std::wstring& sDst, const std::wstring& sSrc)  inline void     ssadd(std::wstring& sDst, const std::wstring& sSrc)
964  {  {
965          sDst.append(sSrc.c_str());          sDst.append(sSrc.c_str());
966  }  }
967  inline void     ssadd(std::wstring& sDst, const std::string& sSrc)  inline void     ssadd(std::wstring& sDst, const std::string& sSrc)
968  {  {
969  #ifdef SS_ANSI  #ifdef SS_ANSI
970          int nLen        = sSrc.size();          int nLen        = sSrc.size();
971          sDst.resize(sDst.size() + nLen);          sDst.resize(sDst.size() + nLen);
972          StdCodeCvt(const_cast<SW_PTRTYPE>(sDst.data()+nLen), sSrc.c_str(), nLen);          StdCodeCvt(const_cast<SW_PTRTYPE>(sDst.data()+nLen), sSrc.c_str(), nLen);
973  #else  #else
974          SSCVT;          SSCVT;
975          sDst.append(SSA2CW(sSrc.c_str()));          sDst.append(SSA2CW(sSrc.c_str()));
976  #endif  #endif
977  }  }
978  inline void     ssadd(std::wstring& sDst, PCSTR pA)  inline void     ssadd(std::wstring& sDst, PCSTR pA)
979  {  {
980  #ifdef SS_ANSI  #ifdef SS_ANSI
981          int nLen        = sslen(pA);          int nLen        = sslen(pA);
982          sDst.resize(sDst.size() + nLen);          sDst.resize(sDst.size() + nLen);
983          StdCodeCvt(const_cast<SW_PTRTYPE>(sDst.data()+nLen), pA, nLen);          StdCodeCvt(const_cast<SW_PTRTYPE>(sDst.data()+nLen), pA, nLen);
984  #else  #else
985          SSCVT;          SSCVT;
986          if ( 0 != pA )          if ( 0 != pA )
987                  sDst.append(SSA2CW(pA));                  sDst.append(SSA2CW(pA));
988  #endif  #endif
989  }  }
990  inline void     ssadd(std::wstring& sDst, PCWSTR pW)  inline void     ssadd(std::wstring& sDst, PCWSTR pW)
991  {  {
992          if ( pW )          if ( pW )
993                  sDst.append(pW);                  sDst.append(pW);
994  }  }
995    
996    
997  // -----------------------------------------------------------------------------  // -----------------------------------------------------------------------------
998  // ssicmp: comparison (case insensitive )  // ssicmp: comparison (case insensitive )
999  // -----------------------------------------------------------------------------  // -----------------------------------------------------------------------------
1000  #ifdef SS_ANSI  #ifdef SS_ANSI
1001          template<typename CT>          template<typename CT>
1002          inline int ssicmp(const CT* pA1, const CT* pA2)          inline int ssicmp(const CT* pA1, const CT* pA2)
1003          {          {
1004                  std::locale loc;                  std::locale loc;
1005                  const std::ctype<CT>& ct = SS_USE_FACET(loc, std::ctype<CT>);                  const std::ctype<CT>& ct = SS_USE_FACET(loc, std::ctype<CT>);
1006                  CT f;                  CT f;
1007                  CT l;                  CT l;
1008    
1009              do              do
1010                          {                          {
1011                                  f = ct.tolower(*(pA1++));                                  f = ct.tolower(*(pA1++));
1012                                  l = ct.tolower(*(pA2++));                                  l = ct.tolower(*(pA2++));
1013              } while ( (f) && (f == l) );              } while ( (f) && (f == l) );
1014    
1015          return (int)(f - l);          return (int)(f - l);
1016          }          }
1017  #else  #else
1018          #ifdef _MBCS          #ifdef _MBCS
1019                  inline long sscmp(PCSTR pA1, PCSTR pA2)                  inline long sscmp(PCSTR pA1, PCSTR pA2)
1020                  {                  {
1021                          return _mbscmp((PCUSTR)pA1, (PCUSTR)pA2);                          return _mbscmp((PCUSTR)pA1, (PCUSTR)pA2);
1022                  }                  }
1023                  inline long ssicmp(PCSTR pA1, PCSTR pA2)                  inline long ssicmp(PCSTR pA1, PCSTR pA2)
1024                  {                  {
1025                          return _mbsicmp((PCUSTR)pA1, (PCUSTR)pA2);                          return _mbsicmp((PCUSTR)pA1, (PCUSTR)pA2);
1026                  }                  }
1027          #else          #else
1028                  inline long sscmp(PCSTR pA1, PCSTR pA2)                  inline long sscmp(PCSTR pA1, PCSTR pA2)
1029                  {                  {
1030                          return strcmp(pA1, pA2);                          return strcmp(pA1, pA2);
1031                  }                  }
1032                  inline long ssicmp(PCSTR pA1, PCSTR pA2)                  inline long ssicmp(PCSTR pA1, PCSTR pA2)
1033                  {                  {
1034                          return _stricmp(pA1, pA2);                          return _stricmp(pA1, pA2);
1035                  }                  }
1036          #endif          #endif
1037          inline long sscmp(PCWSTR pW1, PCWSTR pW2)          inline long sscmp(PCWSTR pW1, PCWSTR pW2)
1038          {          {
1039                  return wcscmp(pW1, pW2);                  return wcscmp(pW1, pW2);
1040          }          }
1041          inline long ssicmp(PCWSTR pW1, PCWSTR pW2)          inline long ssicmp(PCWSTR pW1, PCWSTR pW2)
1042          {          {
1043                  return _wcsicmp(pW1, pW2);                  return _wcsicmp(pW1, pW2);
1044          }          }
1045  #endif  #endif
1046    
1047  // -----------------------------------------------------------------------------  // -----------------------------------------------------------------------------
1048  // ssupr/sslwr: Uppercase/Lowercase conversion functions  // ssupr/sslwr: Uppercase/Lowercase conversion functions
1049  // -----------------------------------------------------------------------------  // -----------------------------------------------------------------------------
1050  #ifdef SS_ANSI  #ifdef SS_ANSI
1051          template<typename CT>          template<typename CT>
1052          inline void sslwr(CT* pT, size_t nLen)          inline void sslwr(CT* pT, size_t nLen)
1053          {          {
1054                  SS_USE_FACET(std::locale(), std::ctype<CT>).tolower(pT, pT+nLen);                  SS_USE_FACET(std::locale(), std::ctype<CT>).tolower(pT, pT+nLen);
1055          }          }
1056          template<typename CT>          template<typename CT>
1057          inline void ssupr(CT* pT, size_t nLen)          inline void ssupr(CT* pT, size_t nLen)
1058          {          {
1059                  SS_USE_FACET(std::locale(), std::ctype<CT>).toupper(pT, pT+nLen);                  SS_USE_FACET(std::locale(), std::ctype<CT>).toupper(pT, pT+nLen);
1060          }          }
1061  #else  // #else we must be on Win32  #else  // #else we must be on Win32
1062          #ifdef _MBCS          #ifdef _MBCS
1063                  inline void     ssupr(PSTR pA, size_t /*nLen*/)                  inline void     ssupr(PSTR pA, size_t /*nLen*/)
1064                  {                  {
1065                          _mbsupr((PUSTR)pA);                          _mbsupr((PUSTR)pA);
1066                  }                  }
1067                  inline void     sslwr(PSTR pA, size_t /*nLen*/)                  inline void     sslwr(PSTR pA, size_t /*nLen*/)
1068                  {                  {
1069                          _mbslwr((PUSTR)pA);                          _mbslwr((PUSTR)pA);
1070                  }                  }
1071          #else          #else
1072                  inline void     ssupr(PSTR pA, size_t /*nLen*/)                  inline void     ssupr(PSTR pA, size_t /*nLen*/)
1073                  {                  {
1074                          _strupr(pA);                          _strupr(pA);
1075                  }                  }
1076                  inline void     sslwr(PSTR pA, size_t /*nLen*/)                  inline void     sslwr(PSTR pA, size_t /*nLen*/)
1077                  {                  {
1078                          _strlwr(pA);                          _strlwr(pA);
1079                  }                  }
1080          #endif          #endif
1081          inline void     ssupr(PWSTR pW, size_t /*nLen*/)                  inline void     ssupr(PWSTR pW, size_t /*nLen*/)        
1082          {          {
1083                  _wcsupr(pW);                  _wcsupr(pW);
1084          }          }
1085          inline void     sslwr(PWSTR pW, size_t /*nLen*/)                  inline void     sslwr(PWSTR pW, size_t /*nLen*/)        
1086          {          {
1087                  _wcslwr(pW);                  _wcslwr(pW);
1088          }          }
1089  #endif // #ifdef SS_ANSI  #endif // #ifdef SS_ANSI
1090    
1091  // -----------------------------------------------------------------------------  // -----------------------------------------------------------------------------
1092  //  vsprintf/vswprintf or _vsnprintf/_vsnwprintf equivalents.  In standard  //  vsprintf/vswprintf or _vsnprintf/_vsnwprintf equivalents.  In standard
1093  //  builds we can't use _vsnprintf/_vsnwsprintf because they're MS extensions.  //  builds we can't use _vsnprintf/_vsnwsprintf because they're MS extensions.
1094  // -----------------------------------------------------------------------------  // -----------------------------------------------------------------------------
1095  #ifdef SS_ANSI  #ifdef SS_ANSI
1096          inline int ssvsprintf(PSTR pA, size_t /*nCount*/, PCSTR pFmtA, va_list vl)          inline int ssvsprintf(PSTR pA, size_t /*nCount*/, PCSTR pFmtA, va_list vl)
1097          {          {
1098                  return vsprintf(pA, pFmtA, vl);                  return vsprintf(pA, pFmtA, vl);
1099          }          }
1100          inline int ssvsprintf(PWSTR pW, size_t nCount, PCWSTR pFmtW, va_list vl)          inline int ssvsprintf(PWSTR pW, size_t nCount, PCWSTR pFmtW, va_list vl)
1101          {          {
1102                  // JMO: It is beginning to seem like Microsoft Visual C++ is the only                  // JMO: It is beginning to seem like Microsoft Visual C++ is the only
1103                  // CRT distribution whose version of vswprintf takes THREE arguments.                  // CRT distribution whose version of vswprintf takes THREE arguments.
1104                  // All others seem to take FOUR arguments.  Therefore instead of                  // All others seem to take FOUR arguments.  Therefore instead of
1105                  // checking for every possible distro here, I'll assume that unless                  // checking for every possible distro here, I'll assume that unless
1106                  // I am running with Microsoft's CRT, then vswprintf takes four                  // I am running with Microsoft's CRT, then vswprintf takes four
1107                  // arguments.  If you get a compilation error here, then you can just                  // arguments.  If you get a compilation error here, then you can just
1108                  // change this code to call the three-argument version.                  // change this code to call the three-argument version.
1109  //      #if !defined(__MWERKS__) && !defined(__SUNPRO_CC_COMPAT) && !defined(__SUNPRO_CC)  //      #if !defined(__MWERKS__) && !defined(__SUNPRO_CC_COMPAT) && !defined(__SUNPRO_CC)
1110          #ifndef _MSC_VER          #ifndef _MSC_VER
1111                  return vswprintf(pW, nCount, pFmtW, vl);                  return vswprintf(pW, nCount, pFmtW, vl);
1112          #else          #else
1113                  nCount;                  nCount;
1114                  return vswprintf(pW, pFmtW, vl);                  return vswprintf(pW, pFmtW, vl);
1115          #endif          #endif
1116          }          }
1117  #else  #else
1118          inline int      ssnprintf(PSTR pA, size_t nCount, PCSTR pFmtA, va_list vl)          inline int      ssnprintf(PSTR pA, size_t nCount, PCSTR pFmtA, va_list vl)
1119          {          {
1120                  return _vsnprintf(pA, nCount, pFmtA, vl);                  return _vsnprintf(pA, nCount, pFmtA, vl);
1121          }          }
1122          inline int      ssnprintf(PWSTR pW, size_t nCount, PCWSTR pFmtW, va_list vl)          inline int      ssnprintf(PWSTR pW, size_t nCount, PCWSTR pFmtW, va_list vl)
1123          {          {
1124                  return _vsnwprintf(pW, nCount, pFmtW, vl);                  return _vsnwprintf(pW, nCount, pFmtW, vl);
1125          }          }
1126  #endif  #endif
1127    
1128    
1129  // -----------------------------------------------------------------------------  // -----------------------------------------------------------------------------
1130  // ssload: Type safe, overloaded ::LoadString wrappers  // ssload: Type safe, overloaded ::LoadString wrappers
1131  // There is no equivalent of these in non-Win32-specific builds.  However, I'm  // There is no equivalent of these in non-Win32-specific builds.  However, I'm
1132  // thinking that with the message facet, there might eventually be one  // thinking that with the message facet, there might eventually be one
1133  // -----------------------------------------------------------------------------  // -----------------------------------------------------------------------------
1134  #ifdef SS_ANSI  #ifdef SS_ANSI
1135  #else  #else
1136          inline int ssload(HMODULE hInst, UINT uId, PSTR pBuf, int nMax)          inline int ssload(HMODULE hInst, UINT uId, PSTR pBuf, int nMax)
1137          {          {
1138                  return ::LoadStringA(hInst, uId, pBuf, nMax);                  return ::LoadStringA(hInst, uId, pBuf, nMax);
1139          }          }
1140          inline int ssload(HMODULE hInst, UINT uId, PWSTR pBuf, int nMax)          inline int ssload(HMODULE hInst, UINT uId, PWSTR pBuf, int nMax)
1141          {          {
1142                  return ::LoadStringW(hInst, uId, pBuf, nMax);                  return ::LoadStringW(hInst, uId, pBuf, nMax);
1143          }          }
1144  #endif  #endif
1145    
1146    
1147  // -----------------------------------------------------------------------------  // -----------------------------------------------------------------------------
1148  // sscoll/ssicoll: Collation wrappers  // sscoll/ssicoll: Collation wrappers
1149  // -----------------------------------------------------------------------------  // -----------------------------------------------------------------------------
1150  #ifdef SS_ANSI  #ifdef SS_ANSI
1151          template <typename CT>          template <typename CT>
1152          inline int sscoll(const CT* sz1, int nLen1, const CT* sz2, int nLen2)          inline int sscoll(const CT* sz1, int nLen1, const CT* sz2, int nLen2)
1153          {          {
1154                  const std::collate<CT>& coll =                  const std::collate<CT>& coll =
1155                          SS_USE_FACET(std::locale(), std::collate<CT>);                          SS_USE_FACET(std::locale(), std::collate<CT>);
1156                  return coll.compare(sz1, sz1+nLen1, sz2, sz2+nLen2);                  return coll.compare(sz1, sz1+nLen1, sz2, sz2+nLen2);
1157          }          }
1158          template <typename CT>          template <typename CT>
1159          inline int ssicoll(const CT* sz1, int nLen1, const CT* sz2, int nLen2)          inline int ssicoll(const CT* sz1, int nLen1, const CT* sz2, int nLen2)
1160          {          {
1161                  const std::locale loc;                  const std::locale loc;
1162                  const std::collate<CT>& coll = SS_USE_FACET(loc, std::collate<CT>);                  const std::collate<CT>& coll = SS_USE_FACET(loc, std::collate<CT>);
1163    
1164                  // Some implementations seem to have trouble using the collate<>                  // Some implementations seem to have trouble using the collate<>
1165                  // facet typedefs so we'll just default to basic_string and hope                  // facet typedefs so we'll just default to basic_string and hope
1166                  // that's what the collate facet uses (which it generally should)                  // that's what the collate facet uses (which it generally should)
1167    
1168  //              std::collate<CT>::string_type s1(sz1);  //              std::collate<CT>::string_type s1(sz1);
1169  //              std::collate<CT>::string_type s2(sz2);  //              std::collate<CT>::string_type s2(sz2);
1170                  std::basic_string<CT> s1(sz1);                  std::basic_string<CT> s1(sz1);
1171                  std::basic_string<CT> s2(sz2);                  std::basic_string<CT> s2(sz2);
1172    
1173                  sslwr(const_cast<CT*>(s1.c_str()), nLen1);                  sslwr(const_cast<CT*>(s1.c_str()), nLen1);
1174                  sslwr(const_cast<CT*>(s2.c_str()), nLen2);                  sslwr(const_cast<CT*>(s2.c_str()), nLen2);
1175                  return coll.compare(s1.c_str(), s1.c_str()+nLen1,                  return coll.compare(s1.c_str(), s1.c_str()+nLen1,
1176                                                          s2.c_str(), s2.c_str()+nLen2);                                                          s2.c_str(), s2.c_str()+nLen2);
1177          }          }
1178  #else  #else
1179          #ifdef _MBCS          #ifdef _MBCS
1180                  inline int sscoll(PCSTR sz1, int /*nLen1*/, PCSTR sz2, int /*nLen2*/)                  inline int sscoll(PCSTR sz1, int /*nLen1*/, PCSTR sz2, int /*nLen2*/)
1181                  {                  {
1182                          return _mbscoll((PCUSTR)sz1, (PCUSTR)sz2);                          return _mbscoll((PCUSTR)sz1, (PCUSTR)sz2);
1183                  }                  }
1184                  inline int ssicoll(PCSTR sz1, int /*nLen1*/, PCSTR sz2, int /*nLen2*/)                  inline int ssicoll(PCSTR sz1, int /*nLen1*/, PCSTR sz2, int /*nLen2*/)
1185                  {                  {
1186                          return _mbsicoll((PCUSTR)sz1, (PCUSTR)sz2);                          return _mbsicoll((PCUSTR)sz1, (PCUSTR)sz2);
1187                  }                  }
1188          #else          #else
1189                  inline int sscoll(PCSTR sz1, int /*nLen1*/, PCSTR sz2, int /*nLen2*/)                  inline int sscoll(PCSTR sz1, int /*nLen1*/, PCSTR sz2, int /*nLen2*/)
1190                  {                  {
1191                          return strcoll(sz1, sz2);                          return strcoll(sz1, sz2);
1192                  }                  }
1193                  inline int ssicoll(PCSTR sz1, int /*nLen1*/, PCSTR sz2, int /*nLen2*/)                  inline int ssicoll(PCSTR sz1, int /*nLen1*/, PCSTR sz2, int /*nLen2*/)
1194                  {                  {
1195                          return _stricoll(sz1, sz2);                          return _stricoll(sz1, sz2);
1196                  }                  }
1197          #endif          #endif
1198          inline int sscoll(PCWSTR sz1, int /*nLen1*/, PCWSTR sz2, int /*nLen2*/)          inline int sscoll(PCWSTR sz1, int /*nLen1*/, PCWSTR sz2, int /*nLen2*/)
1199          {          {
1200                  return wcscoll(sz1, sz2);                  return wcscoll(sz1, sz2);
1201          }          }
1202          inline int ssicoll(PCWSTR sz1, int /*nLen1*/, PCWSTR sz2, int /*nLen2*/)          inline int ssicoll(PCWSTR sz1, int /*nLen1*/, PCWSTR sz2, int /*nLen2*/)
1203          {          {
1204                  return _wcsicoll(sz1, sz2);                  return _wcsicoll(sz1, sz2);
1205          }          }
1206  #endif  #endif
1207    
1208    
1209  // -----------------------------------------------------------------------------  // -----------------------------------------------------------------------------
1210  // ssfmtmsg: FormatMessage equivalents.  Needed because I added a CString facade  // ssfmtmsg: FormatMessage equivalents.  Needed because I added a CString facade
1211  // Again -- no equivalent of these on non-Win32 builds but their might one day  // Again -- no equivalent of these on non-Win32 builds but their might one day
1212  // be one if the message facet gets implemented  // be one if the message facet gets implemented
1213  // -----------------------------------------------------------------------------  // -----------------------------------------------------------------------------
1214  #ifdef SS_ANSI  #ifdef SS_ANSI
1215  #else  #else
1216          inline DWORD ssfmtmsg(DWORD dwFlags, LPCVOID pSrc, DWORD dwMsgId,          inline DWORD ssfmtmsg(DWORD dwFlags, LPCVOID pSrc, DWORD dwMsgId,
1217                                                    DWORD dwLangId, PSTR pBuf, DWORD nSize,                                                    DWORD dwLangId, PSTR pBuf, DWORD nSize,
1218                                                    va_list* vlArgs)                                                    va_list* vlArgs)
1219          {          {
1220                  return FormatMessageA(dwFlags, pSrc, dwMsgId, dwLangId,                  return FormatMessageA(dwFlags, pSrc, dwMsgId, dwLangId,
1221                                                            pBuf, nSize,vlArgs);                                                            pBuf, nSize,vlArgs);
1222          }          }
1223          inline DWORD ssfmtmsg(DWORD dwFlags, LPCVOID pSrc, DWORD dwMsgId,          inline DWORD ssfmtmsg(DWORD dwFlags, LPCVOID pSrc, DWORD dwMsgId,
1224                                                    DWORD dwLangId, PWSTR pBuf, DWORD nSize,                                                    DWORD dwLangId, PWSTR pBuf, DWORD nSize,
1225                                                    va_list* vlArgs)                                                    va_list* vlArgs)
1226          {          {
1227                  return FormatMessageW(dwFlags, pSrc, dwMsgId, dwLangId,                  return FormatMessageW(dwFlags, pSrc, dwMsgId, dwLangId,
1228                                                            pBuf, nSize,vlArgs);                                                            pBuf, nSize,vlArgs);
1229          }          }
1230  #endif  #endif
1231    
1232    
1233    
1234  // FUNCTION: sscpy.  Copies up to 'nMax' characters from pSrc to pDst.  // FUNCTION: sscpy.  Copies up to 'nMax' characters from pSrc to pDst.
1235  // -----------------------------------------------------------------------------  // -----------------------------------------------------------------------------
1236  // FUNCTION:  sscpy  // FUNCTION:  sscpy
1237  //              inline int sscpy(PSTR pDst, PCSTR pSrc, int nMax=-1);  //              inline int sscpy(PSTR pDst, PCSTR pSrc, int nMax=-1);
1238  //              inline int sscpy(PUSTR pDst,  PCSTR pSrc, int nMax=-1)  //              inline int sscpy(PUSTR pDst,  PCSTR pSrc, int nMax=-1)
1239  //              inline int sscpy(PSTR pDst, PCWSTR pSrc, int nMax=-1);  //              inline int sscpy(PSTR pDst, PCWSTR pSrc, int nMax=-1);
1240  //              inline int sscpy(PWSTR pDst, PCWSTR pSrc, int nMax=-1);  //              inline int sscpy(PWSTR pDst, PCWSTR pSrc, int nMax=-1);
1241  //              inline int sscpy(PWSTR pDst, PCSTR pSrc, int nMax=-1);  //              inline int sscpy(PWSTR pDst, PCSTR pSrc, int nMax=-1);
1242  //  //
1243  // DESCRIPTION:  // DESCRIPTION:
1244  //              This function is very much (but not exactly) like strcpy.  These  //              This function is very much (but not exactly) like strcpy.  These
1245  //              overloads simplify copying one C-style string into another by allowing  //              overloads simplify copying one C-style string into another by allowing
1246  //              the caller to specify two different types of strings if necessary.  //              the caller to specify two different types of strings if necessary.
1247  //  //
1248  //              The strings must NOT overlap  //              The strings must NOT overlap
1249  //  //
1250  //              "Character" is expressed in terms of the destination string, not  //              "Character" is expressed in terms of the destination string, not
1251  //              the source.  If no 'nMax' argument is supplied, then the number of  //              the source.  If no 'nMax' argument is supplied, then the number of
1252  //              characters copied will be sslen(pSrc).  A NULL terminator will  //              characters copied will be sslen(pSrc).  A NULL terminator will
1253  //              also be added so pDst must actually be big enough to hold nMax+1  //              also be added so pDst must actually be big enough to hold nMax+1
1254  //              characters.  The return value is the number of characters copied,  //              characters.  The return value is the number of characters copied,
1255  //              not including the NULL terminator.  //              not including the NULL terminator.
1256  //  //
1257  // PARAMETERS:  // PARAMETERS:
1258  //              pSrc - the string to be copied FROM.  May be a char based string, an  //              pSrc - the string to be copied FROM.  May be a char based string, an
1259  //                         MBCS string (in Win32 builds) or a wide string (wchar_t).  //                         MBCS string (in Win32 builds) or a wide string (wchar_t).
1260  //              pSrc - the string to be copied TO.  Also may be either MBCS or wide  //              pSrc - the string to be copied TO.  Also may be either MBCS or wide
1261  //              nMax - the maximum number of characters to be copied into szDest.  Note  //              nMax - the maximum number of characters to be copied into szDest.  Note
1262  //                         that this is expressed in whatever a "character" means to pDst.  //                         that this is expressed in whatever a "character" means to pDst.
1263  //                         If pDst is a wchar_t type string than this will be the maximum  //                         If pDst is a wchar_t type string than this will be the maximum
1264  //                         number of wchar_ts that my be copied.  The pDst string must be  //                         number of wchar_ts that my be copied.  The pDst string must be
1265  //                         large enough to hold least nMaxChars+1 characters.  //                         large enough to hold least nMaxChars+1 characters.
1266  //                         If the caller supplies no argument for nMax this is a signal to  //                         If the caller supplies no argument for nMax this is a signal to
1267  //                         the routine to copy all the characters in pSrc, regardless of  //                         the routine to copy all the characters in pSrc, regardless of
1268  //                         how long it is.  //                         how long it is.
1269  //  //
1270  // RETURN VALUE: none  // RETURN VALUE: none
1271  // -----------------------------------------------------------------------------  // -----------------------------------------------------------------------------
1272  template<typename CT1, typename CT2>  template<typename CT1, typename CT2>
1273  inline int sscpycvt(CT1* pDst, const CT2* pSrc, int nChars)  inline int sscpycvt(CT1* pDst, const CT2* pSrc, int nChars)
1274  {  {
1275          StdCodeCvt(pDst, pSrc, nChars);          StdCodeCvt(pDst, pSrc, nChars);
1276          pDst[SSMAX(nChars, 0)]  = '\0';          pDst[SSMAX(nChars, 0)]  = '\0';
1277          return nChars;          return nChars;
1278  }  }
1279    
1280  template<typename CT1, typename CT2>  template<typename CT1, typename CT2>
1281  inline int sscpy(CT1* pDst, const CT2* pSrc, int nMax, int nLen)  inline int sscpy(CT1* pDst, const CT2* pSrc, int nMax, int nLen)
1282  {  {
1283          return sscpycvt(pDst, pSrc, SSMIN(nMax, nLen));          return sscpycvt(pDst, pSrc, SSMIN(nMax, nLen));
1284  }  }
1285  template<typename CT1, typename CT2>  template<typename CT1, typename CT2>
1286  inline int sscpy(CT1* pDst, const CT2* pSrc, int nMax)  inline int sscpy(CT1* pDst, const CT2* pSrc, int nMax)
1287  {  {
1288          return sscpycvt(pDst, pSrc, SSMIN(nMax, sslen(pSrc)));          return sscpycvt(pDst, pSrc, SSMIN(nMax, sslen(pSrc)));
1289  }  }
1290  template<typename CT1, typename CT2>  template<typename CT1, typename CT2>
1291  inline int sscpy(CT1* pDst, const CT2* pSrc)  inline int sscpy(CT1* pDst, const CT2* pSrc)
1292  {  {
1293          return sscpycvt(pDst, pSrc, sslen(pSrc));          return sscpycvt(pDst, pSrc, sslen(pSrc));
1294  }  }
1295  template<typename CT1, typename CT2>  template<typename CT1, typename CT2>
1296  inline int sscpy(CT1* pDst, const std::basic_string<CT2>& sSrc, int nMax)  inline int sscpy(CT1* pDst, const std::basic_string<CT2>& sSrc, int nMax)
1297  {  {
1298          return sscpycvt(pDst, sSrc.c_str(), SSMIN(nMax, (int)sSrc.length()));          return sscpycvt(pDst, sSrc.c_str(), SSMIN(nMax, (int)sSrc.length()));
1299  }  }
1300  template<typename CT1, typename CT2>  template<typename CT1, typename CT2>
1301  inline int sscpy(CT1* pDst, const std::basic_string<CT2>& sSrc)  inline int sscpy(CT1* pDst, const std::basic_string<CT2>& sSrc)
1302  {  {
1303          return sscpycvt(pDst, sSrc.c_str(), (int)sSrc.length());          return sscpycvt(pDst, sSrc.c_str(), (int)sSrc.length());
1304  }  }
1305    
1306  #ifdef SS_INC_COMDEF  #ifdef SS_INC_COMDEF
1307          template<typename CT1>          template<typename CT1>
1308          inline int sscpy(CT1* pDst, const _bstr_t& bs, int nMax)          inline int sscpy(CT1* pDst, const _bstr_t& bs, int nMax)
1309          {          {
1310                  return sscpycvt(pDst, static_cast<PCOLESTR>(bs), SSMIN(nMax, (int)bs.length()));                  return sscpycvt(pDst, static_cast<PCOLESTR>(bs), SSMIN(nMax, (int)bs.length()));
1311          }          }
1312          template<typename CT1>          template<typename CT1>
1313          inline int sscpy(CT1* pDst, const _bstr_t& bs)          inline int sscpy(CT1* pDst, const _bstr_t& bs)
1314          {          {
1315                  return sscpy(pDst, bs, bs.length());                  return sscpy(pDst, bs, bs.length());
1316          }          }
1317  #endif  #endif
1318    
1319    
1320  // -----------------------------------------------------------------------------  // -----------------------------------------------------------------------------
1321  // Functional objects for changing case.  They also let you pass locales  // Functional objects for changing case.  They also let you pass locales
1322  // -----------------------------------------------------------------------------  // -----------------------------------------------------------------------------
1323    
1324  #ifdef SS_ANSI  #ifdef SS_ANSI
1325          template<typename CT>          template<typename CT>
1326          struct SSToUpper : public std::binary_function<CT, std::locale, CT>          struct SSToUpper : public std::binary_function<CT, std::locale, CT>
1327          {          {
1328                  inline CT operator()(const CT& t, const std::locale& loc) const                  inline CT operator()(const CT& t, const std::locale& loc) const
1329                  {                  {
1330                          return std::toupper<CT>(t, loc);                          return std::toupper<CT>(t, loc);
1331                  }                  }
1332          };          };
1333          template<typename CT>          template<typename CT>
1334          struct SSToLower : public std::binary_function<CT, std::locale, CT>          struct SSToLower : public std::binary_function<CT, std::locale, CT>
1335          {          {
1336                  inline CT operator()(const CT& t, const std::locale& loc) const                  inline CT operator()(const CT& t, const std::locale& loc) const
1337                  {                  {
1338                          return std::tolower<CT>(t, loc);                          return std::tolower<CT>(t, loc);
1339                  }                  }
1340          };          };
1341  #endif  #endif
1342    
1343  // This struct is used for TrimRight() and TrimLeft() function implementations.  // This struct is used for TrimRight() and TrimLeft() function implementations.
1344  //template<typename CT>  //template<typename CT>
1345  //struct NotSpace : public std::unary_function<CT, bool>  //struct NotSpace : public std::unary_function<CT, bool>
1346  //{  //{
1347  //      const std::locale& loc;  //      const std::locale& loc;
1348  //      inline NotSpace(const std::locale& locArg) : loc(locArg) {}  //      inline NotSpace(const std::locale& locArg) : loc(locArg) {}
1349  //      inline bool operator() (CT t) { return !std::isspace(t, loc); }  //      inline bool operator() (CT t) { return !std::isspace(t, loc); }
1350  //};  //};
1351  template<typename CT>  template<typename CT>
1352  struct NotSpace : public std::unary_function<CT, bool>  struct NotSpace : public std::unary_function<CT, bool>
1353  {  {
1354          const std::locale& loc;          const std::locale& loc;
1355          NotSpace(const std::locale& locArg) : loc(locArg) {}          NotSpace(const std::locale& locArg) : loc(locArg) {}
1356    
1357          // DINKUMWARE BUG:          // DINKUMWARE BUG:
1358          // Note -- using std::isspace in a COM DLL gives us access violations          // Note -- using std::isspace in a COM DLL gives us access violations
1359          // because it causes the dynamic addition of a function to be called          // because it causes the dynamic addition of a function to be called
1360          // when the library shuts down.  Unfortunately the list is maintained          // when the library shuts down.  Unfortunately the list is maintained
1361          // in DLL memory but the function is in static memory.  So the COM DLL          // in DLL memory but the function is in static memory.  So the COM DLL
1362          // goes away along with the function that was supposed to be called,          // goes away along with the function that was supposed to be called,
1363          // and then later when the DLL CRT shuts down it unloads the list and          // and then later when the DLL CRT shuts down it unloads the list and
1364          // tries to call the long-gone function.          // tries to call the long-gone function.
1365          // This is DinkumWare's implementation problem.  Until then, we will          // This is DinkumWare's implementation problem.  Until then, we will
1366          // use good old isspace and iswspace from the CRT unless they          // use good old isspace and iswspace from the CRT unless they
1367          // specify SS_ANSI          // specify SS_ANSI
1368  #ifdef SS_ANSI  #ifdef SS_ANSI
1369          bool operator() (CT t) const { return !std::isspace(t, loc); }          bool operator() (CT t) const { return !std::isspace(t, loc); }
1370  #else  #else
1371          bool ssisp(char c) const { return FALSE != ::isspace((int) c); }          bool ssisp(char c) const { return FALSE != ::isspace((int) c); }
1372          bool ssisp(wchar_t c) const { return FALSE != ::iswspace((wint_t) c); }          bool ssisp(wchar_t c) const { return FALSE != ::iswspace((wint_t) c); }
1373          bool operator()(CT t) const  { return !ssisp(t); }          bool operator()(CT t) const  { return !ssisp(t); }
1374  #endif  #endif
1375  };  };
1376    
1377    
1378    
1379    
1380  //                      Now we can define the template (finally!)  //                      Now we can define the template (finally!)
1381  // =============================================================================  // =============================================================================
1382  // TEMPLATE: CStdStr  // TEMPLATE: CStdStr
1383  //              template<typename CT> class CStdStr : public std::basic_string<CT>  //              template<typename CT> class CStdStr : public std::basic_string<CT>
1384  //  //
1385  // REMARKS:  // REMARKS:
1386  //              This template derives from basic_string<CT> and adds some MFC CString-  //              This template derives from basic_string<CT> and adds some MFC CString-
1387  //              like functionality  //              like functionality
1388  //  //
1389  //              Basically, this is my attempt to make Standard C++ library strings as  //              Basically, this is my attempt to make Standard C++ library strings as
1390  //              easy to use as the MFC CString class.  //              easy to use as the MFC CString class.
1391  //  //
1392  //              Note that although this is a template, it makes the assumption that the  //              Note that although this is a template, it makes the assumption that the
1393  //              template argument (CT, the character type) is either char or wchar_t.    //              template argument (CT, the character type) is either char or wchar_t.  
1394  // =============================================================================  // =============================================================================
1395    
1396  //#define CStdStr _SS   // avoid compiler warning 4786  //#define CStdStr _SS   // avoid compiler warning 4786
1397    
1398    
1399  template<typename CT>  template<typename CT>
1400  class CStdStr : public std::basic_string<CT>  class CStdStr : public std::basic_string<CT>
1401  {  {
1402          // Typedefs for shorter names.  Using these names also appears to help          // Typedefs for shorter names.  Using these names also appears to help
1403          // us avoid some ambiguities that otherwise arise on some platforms          // us avoid some ambiguities that otherwise arise on some platforms
1404    
1405          typedef typename std::basic_string<CT>          MYBASE;  // my base class          typedef typename std::basic_string<CT>          MYBASE;  // my base class
1406          typedef CStdStr<CT>                                                     MYTYPE;  // myself          typedef CStdStr<CT>                                                     MYTYPE;  // myself
1407          typedef typename MYBASE::const_pointer          PCMYSTR; // PCSTR or PCWSTR          typedef typename MYBASE::const_pointer          PCMYSTR; // PCSTR or PCWSTR
1408          typedef typename MYBASE::pointer                        PMYSTR;  // PSTR or PWSTR          typedef typename MYBASE::pointer                        PMYSTR;  // PSTR or PWSTR
1409          typedef typename MYBASE::iterator                       MYITER;  // my iterator type          typedef typename MYBASE::iterator                       MYITER;  // my iterator type
1410          typedef typename MYBASE::const_iterator         MYCITER; // you get the idea...          typedef typename MYBASE::const_iterator         MYCITER; // you get the idea...
1411          typedef typename MYBASE::reverse_iterator       MYRITER;          typedef typename MYBASE::reverse_iterator       MYRITER;
1412          typedef typename MYBASE::size_type                      MYSIZE;            typedef typename MYBASE::size_type                      MYSIZE;  
1413          typedef typename MYBASE::value_type                     MYVAL;          typedef typename MYBASE::value_type                     MYVAL;
1414          typedef typename MYBASE::allocator_type         MYALLOC;          typedef typename MYBASE::allocator_type         MYALLOC;
1415                    
1416  public:  public:
1417    
1418          // shorthand conversion from PCTSTR to string resource ID          // shorthand conversion from PCTSTR to string resource ID
1419          #define _TRES(pctstr) (LOWORD((DWORD)(pctstr)))          #define _TRES(pctstr) (LOWORD((DWORD)(pctstr)))
1420    
1421          // CStdStr inline constructors          // CStdStr inline constructors
1422          CStdStr()          CStdStr()
1423          {          {
1424          }          }
1425    
1426          CStdStr(const MYTYPE& str) : MYBASE(SSREF(str))          CStdStr(const MYTYPE& str) : MYBASE(SSREF(str))
1427          {          {
1428          }          }
1429    
1430          CStdStr(const std::string& str)          CStdStr(const std::string& str)
1431          {          {
1432                  ssasn(*this, SSREF(str));                  ssasn(*this, SSREF(str));
1433          }          }
1434    
1435          CStdStr(const std::wstring& str)          CStdStr(const std::wstring& str)
1436          {          {
1437                  ssasn(*this, SSREF(str));                  ssasn(*this, SSREF(str));
1438          }          }
1439    
1440          CStdStr(PCMYSTR pT, MYSIZE n) : MYBASE(pT, n)          CStdStr(PCMYSTR pT, MYSIZE n) : MYBASE(pT, n)
1441          {          {
1442          }          }
1443    
1444          CStdStr(PCSTR pA)          CStdStr(PCSTR pA)
1445          {          {
1446          #ifdef SS_ANSI          #ifdef SS_ANSI
1447                  *this = pA;                  *this = pA;
1448          #else          #else
1449                  if ( 0 != HIWORD(pA) )                  if ( 0 != HIWORD(pA) )
1450                          *this = pA;                          *this = pA;
1451                  else if ( 0 != pA && !Load(_TRES(pA)) )                  else if ( 0 != pA && !Load(_TRES(pA)) )
1452                          TRACE(_T("Can't load string %u\n"), _TRES(pA));                          TRACE(_T("Can't load string %u\n"), _TRES(pA));
1453          #endif          #endif
1454          }          }
1455    
1456          CStdStr(PCWSTR pW)          CStdStr(PCWSTR pW)
1457          {          {
1458          #ifdef SS_ANSI          #ifdef SS_ANSI
1459                  *this = pW;                  *this = pW;
1460          #else          #else
1461                  if ( 0 != HIWORD(pW) )                  if ( 0 != HIWORD(pW) )
1462                          *this = pW;                          *this = pW;
1463                  else if ( 0 != pW && !Load(_TRES(pW)) )                  else if ( 0 != pW && !Load(_TRES(pW)) )
1464                          TRACE(_T("Can't load string %u\n"), _TRES(pW));                          TRACE(_T("Can't load string %u\n"), _TRES(pW));
1465          #endif          #endif
1466          }          }
1467    
1468          CStdStr(MYCITER first, MYCITER last)          CStdStr(MYCITER first, MYCITER last)
1469                  : MYBASE(first, last)                  : MYBASE(first, last)
1470          {          {
1471          }          }
1472    
1473          CStdStr(MYSIZE nSize, MYVAL ch, const MYALLOC& al=MYALLOC())          CStdStr(MYSIZE nSize, MYVAL ch, const MYALLOC& al=MYALLOC())
1474                  : MYBASE(nSize, ch, al)                  : MYBASE(nSize, ch, al)
1475          {          {
1476          }          }
1477    
1478          #ifdef SS_INC_COMDEF          #ifdef SS_INC_COMDEF
1479                  CStdStr(const _bstr_t& bstr)                  CStdStr(const _bstr_t& bstr)
1480                  {                  {
1481                          if ( bstr.length() > 0 )                          if ( bstr.length() > 0 )
1482                                  append(static_cast<PCMYSTR>(bstr), bstr.length());                                  append(static_cast<PCMYSTR>(bstr), bstr.length());
1483                  }                  }
1484          #endif          #endif
1485    
1486          // CStdStr inline assignment operators -- the ssasn function now takes care          // CStdStr inline assignment operators -- the ssasn function now takes care
1487          // of fixing  the MSVC assignment bug (see knowledge base article Q172398).          // of fixing  the MSVC assignment bug (see knowledge base article Q172398).
1488          MYTYPE& operator=(const MYTYPE& str)          MYTYPE& operator=(const MYTYPE& str)
1489          {          {
1490                  ssasn(*this, str);                  ssasn(*this, str);
1491                  return *this;                  return *this;
1492          }          }
1493    
1494          MYTYPE& operator=(const std::string& str)          MYTYPE& operator=(const std::string& str)
1495          {          {
1496                  ssasn(*this, str);                  ssasn(*this, str);
1497                  return *this;                  return *this;
1498          }          }
1499    
1500          MYTYPE& operator=(const std::wstring& str)          MYTYPE& operator=(const std::wstring& str)
1501          {          {
1502                  ssasn(*this, str);                  ssasn(*this, str);
1503                  return *this;                  return *this;
1504          }          }
1505    
1506          MYTYPE& operator=(PCSTR pA)          MYTYPE& operator=(PCSTR pA)
1507          {          {
1508                  ssasn(*this, pA);                  ssasn(*this, pA);
1509                  return *this;                  return *this;
1510          }          }
1511    
1512          MYTYPE& operator=(PCWSTR pW)          MYTYPE& operator=(PCWSTR pW)
1513          {          {
1514                  ssasn(*this, pW);                  ssasn(*this, pW);
1515                  return *this;                  return *this;
1516          }          }
1517    
1518          MYTYPE& operator=(CT t)          MYTYPE& operator=(CT t)
1519          {          {
1520                  Q172398(*this);                  Q172398(*this);
1521                  MYBASE::assign(1, t);                  MYBASE::assign(1, t);
1522                  return *this;                  return *this;
1523          }          }
1524    
1525          #ifdef SS_INC_COMDEF          #ifdef SS_INC_COMDEF
1526                  MYTYPE& operator=(const _bstr_t& bstr)                  MYTYPE& operator=(const _bstr_t& bstr)
1527                  {                  {
1528                          if ( bstr.length() > 0 )                          if ( bstr.length() > 0 )
1529                                  return assign(static_cast<PCMYSTR>(bstr), bstr.length());                                  return assign(static_cast<PCMYSTR>(bstr), bstr.length());
1530                          else                          else
1531                          {                          {
1532                                  erase();                                  erase();
1533                                  return *this;                                  return *this;
1534                          }                          }
1535                  }                  }
1536          #endif          #endif
1537    
1538    
1539          // Overloads  also needed to fix the MSVC assignment bug (KB: Q172398)          // Overloads  also needed to fix the MSVC assignment bug (KB: Q172398)
1540          //  *** Thanks to Pete The Plumber for catching this one ***          //  *** Thanks to Pete The Plumber for catching this one ***
1541          // They also are compiled if you have explicitly turned off refcounting          // They also are compiled if you have explicitly turned off refcounting
1542          #if ( defined(_MSC_VER) && ( _MSC_VER < 1200 ) ) || defined(SS_NO_REFCOUNT)          #if ( defined(_MSC_VER) && ( _MSC_VER < 1200 ) ) || defined(SS_NO_REFCOUNT)
1543    
1544                  MYTYPE& assign(const MYTYPE& str)                  MYTYPE& assign(const MYTYPE& str)
1545                  {                  {
1546                          ssasn(*this, str);                          ssasn(*this, str);
1547                          return *this;                          return *this;
1548                  }                  }
1549    
1550                  MYTYPE& assign(const MYTYPE& str, MYSIZE nStart, MYSIZE nChars)                  MYTYPE& assign(const MYTYPE& str, MYSIZE nStart, MYSIZE nChars)
1551                  {                  {
1552                          // This overload of basic_string::assign is supposed to assign up to                          // This overload of basic_string::assign is supposed to assign up to
1553                          // <nChars> or the NULL terminator, whichever comes first.  Since we                          // <nChars> or the NULL terminator, whichever comes first.  Since we
1554                          // are about to call a less forgiving overload (in which <nChars>                          // are about to call a less forgiving overload (in which <nChars>
1555                          // must be a valid length), we must adjust the length here to a safe                          // must be a valid length), we must adjust the length here to a safe
1556                          // value.  Thanks to Ullrich Pollähne for catching this bug                          // value.  Thanks to Ullrich Pollähne for catching this bug
1557    
1558                          nChars          = SSMIN(nChars, str.length() - nStart);                          nChars          = SSMIN(nChars, str.length() - nStart);
1559    
1560                          // Watch out for assignment to self                          // Watch out for assignment to self
1561    
1562                          if ( this == &str )                          if ( this == &str )
1563                          {                          {
1564                                  MYTYPE strTemp(str.c_str()+nStart, nChars);                                  MYTYPE strTemp(str.c_str()+nStart, nChars);
1565                                  assign(strTemp);                                  assign(strTemp);
1566                          }                          }
1567                          else                          else
1568                          {                          {
1569                                  Q172398(*this);                                  Q172398(*this);
1570                                  MYBASE::assign(str.c_str()+nStart, nChars);                                  MYBASE::assign(str.c_str()+nStart, nChars);
1571                          }                          }
1572                          return *this;                          return *this;
1573                  }                  }
1574    
1575                  MYTYPE& assign(const MYBASE& str)                  MYTYPE& assign(const MYBASE& str)
1576                  {                  {
1577                          ssasn(*this, str);                          ssasn(*this, str);
1578                          return *this;                          return *this;
1579                  }                  }
1580    
1581                  MYTYPE& assign(const MYBASE& str, MYSIZE nStart, MYSIZE nChars)                  MYTYPE& assign(const MYBASE& str, MYSIZE nStart, MYSIZE nChars)
1582                  {                  {
1583                          // This overload of basic_string::assign is supposed to assign up to                          // This overload of basic_string::assign is supposed to assign up to
1584                          // <nChars> or the NULL terminator, whichever comes first.  Since we                          // <nChars> or the NULL terminator, whichever comes first.  Since we
1585                          // are about to call a less forgiving overload (in which <nChars>                          // are about to call a less forgiving overload (in which <nChars>
1586                          // must be a valid length), we must adjust the length here to a safe                          // must be a valid length), we must adjust the length here to a safe
1587                          // value. Thanks to Ullrich Pollähne for catching this bug                          // value. Thanks to Ullrich Pollähne for catching this bug
1588    
1589                          nChars          = SSMIN(nChars, str.length() - nStart);                          nChars          = SSMIN(nChars, str.length() - nStart);
1590    
1591                          // Watch out for assignment to self                          // Watch out for assignment to self
1592    
1593                          if ( this == &str )     // watch out for assignment to self                          if ( this == &str )     // watch out for assignment to self
1594                          {                          {
1595                                  MYTYPE strTemp(str.c_str() + nStart, nChars);                                  MYTYPE strTemp(str.c_str() + nStart, nChars);
1596                                  assign(strTemp);                                  assign(strTemp);
1597                          }                          }
1598                          else                          else
1599                          {                          {
1600                                  Q172398(*this);                                  Q172398(*this);
1601                                  MYBASE::assign(str.c_str()+nStart, nChars);                                  MYBASE::assign(str.c_str()+nStart, nChars);
1602                          }                          }
1603                          return *this;                          return *this;
1604                  }                  }
1605    
1606                  MYTYPE& assign(const CT* pC, MYSIZE nChars)                  MYTYPE& assign(const CT* pC, MYSIZE nChars)
1607                  {                  {
1608                          // Q172398 only fix -- erase before assigning, but not if we're                          // Q172398 only fix -- erase before assigning, but not if we're
1609                          // assigning from our own buffer                          // assigning from our own buffer
1610    
1611          #if defined ( _MSC_VER ) && ( _MSC_VER < 1200 )          #if defined ( _MSC_VER ) && ( _MSC_VER < 1200 )
1612                          if ( !empty() && ( pC < data() || pC > data() + capacity() ) )                          if ( !empty() && ( pC < data() || pC > data() + capacity() ) )
1613                                  erase();                                  erase();
1614          #endif          #endif
1615                          Q172398(*this);                          Q172398(*this);
1616                          MYBASE::assign(pC, nChars);                          MYBASE::assign(pC, nChars);
1617                          return *this;                          return *this;
1618                  }                  }
1619    
1620                  MYTYPE& assign(MYSIZE nChars, MYVAL val)                  MYTYPE& assign(MYSIZE nChars, MYVAL val)
1621                  {                  {
1622                          Q172398(*this);                          Q172398(*this);
1623                          MYBASE::assign(nChars, val);                          MYBASE::assign(nChars, val);
1624                          return *this;                          return *this;
1625                  }                  }
1626    
1627                  MYTYPE& assign(const CT* pT)                  MYTYPE& assign(const CT* pT)
1628                  {                  {
1629                          return assign(pT, CStdStr::traits_type::length(pT));                          return assign(pT, CStdStr::traits_type::length(pT));
1630                  }                  }
1631    
1632                  MYTYPE& assign(MYCITER iterFirst, MYCITER iterLast)                  MYTYPE& assign(MYCITER iterFirst, MYCITER iterLast)
1633                  {                  {
1634          #if defined ( _MSC_VER ) && ( _MSC_VER < 1200 )          #if defined ( _MSC_VER ) && ( _MSC_VER < 1200 )
1635                          // Q172398 fix.  don't call erase() if we're assigning from ourself                          // Q172398 fix.  don't call erase() if we're assigning from ourself
1636                          if ( iterFirst < begin() || iterFirst > begin() + size() )                          if ( iterFirst < begin() || iterFirst > begin() + size() )
1637                                  erase()                                  erase()
1638          #endif          #endif
1639                          replace(begin(), end(), iterFirst, iterLast);                          replace(begin(), end(), iterFirst, iterLast);
1640                          return *this;                          return *this;
1641                  }                  }
1642          #endif          #endif
1643    
1644    
1645          // -------------------------------------------------------------------------          // -------------------------------------------------------------------------
1646          // CStdStr inline concatenation.          // CStdStr inline concatenation.
1647          // -------------------------------------------------------------------------          // -------------------------------------------------------------------------
1648          MYTYPE& operator+=(const MYTYPE& str)          MYTYPE& operator+=(const MYTYPE& str)
1649          {          {
1650                  ssadd(*this, str);                  ssadd(*this, str);
1651                  return *this;                  return *this;
1652          }          }
1653    
1654          MYTYPE& operator+=(const std::string& str)          MYTYPE& operator+=(const std::string& str)
1655          {          {
1656                  ssadd(*this, str);                  ssadd(*this, str);
1657                  return *this;                  return *this;
1658          }          }
1659    
1660          MYTYPE& operator+=(const std::wstring& str)          MYTYPE& operator+=(const std::wstring& str)
1661          {          {
1662                  ssadd(*this, str);                  ssadd(*this, str);
1663                  return *this;                  return *this;
1664          }          }
1665    
1666          MYTYPE& operator+=(PCSTR pA)          MYTYPE& operator+=(PCSTR pA)
1667          {          {
1668                  ssadd(*this, pA);                  ssadd(*this, pA);
1669                  return *this;                  return *this;
1670          }          }
1671    
1672          MYTYPE& operator+=(PCWSTR pW)          MYTYPE& operator+=(PCWSTR pW)
1673          {          {
1674                  ssadd(*this, pW);                  ssadd(*this, pW);
1675                  return *this;                  return *this;
1676          }          }
1677    
1678          MYTYPE& operator+=(CT t)          MYTYPE& operator+=(CT t)
1679          {          {
1680                  append(1, t);                  append(1, t);
1681                  return *this;                  return *this;
1682          }          }
1683          #ifdef SS_INC_COMDEF    // if we have _bstr_t, define a += for it too.          #ifdef SS_INC_COMDEF    // if we have _bstr_t, define a += for it too.
1684                  MYTYPE& operator+=(const _bstr_t& bstr)                  MYTYPE& operator+=(const _bstr_t& bstr)
1685                  {                  {
1686                          return operator+=(static_cast<PCMYSTR>(bstr));                          return operator+=(static_cast<PCMYSTR>(bstr));
1687                  }                  }
1688          #endif          #endif
1689    
1690    
1691          // addition operators -- global friend functions.          // addition operators -- global friend functions.
1692    
1693          friend  MYTYPE  operator+(const MYTYPE& str1,   const MYTYPE& str2);          friend  MYTYPE  operator+(const MYTYPE& str1,   const MYTYPE& str2);
1694          friend  MYTYPE  operator+(const MYTYPE& str,    CT t);          friend  MYTYPE  operator+(const MYTYPE& str,    CT t);
1695          friend  MYTYPE  operator+(const MYTYPE& str,    PCSTR sz);          friend  MYTYPE  operator+(const MYTYPE& str,    PCSTR sz);
1696          friend  MYTYPE  operator+(const MYTYPE& str,    PCWSTR sz);          friend  MYTYPE  operator+(const MYTYPE& str,    PCWSTR sz);
1697          friend  MYTYPE  operator+(PCSTR pA,                             const MYTYPE& str);          friend  MYTYPE  operator+(PCSTR pA,                             const MYTYPE& str);
1698          friend  MYTYPE  operator+(PCWSTR pW,                    const MYTYPE& str);          friend  MYTYPE  operator+(PCWSTR pW,                    const MYTYPE& str);
1699  #ifdef SS_INC_COMDEF  #ifdef SS_INC_COMDEF
1700          friend  MYTYPE  operator+(const _bstr_t& bstr,  const MYTYPE& str);          friend  MYTYPE  operator+(const _bstr_t& bstr,  const MYTYPE& str);
1701          friend  MYTYPE  operator+(const MYTYPE& str,    const _bstr_t& bstr);          friend  MYTYPE  operator+(const MYTYPE& str,    const _bstr_t& bstr);
1702  #endif  #endif
1703    
1704          // -------------------------------------------------------------------------          // -------------------------------------------------------------------------
1705          // Case changing functions          // Case changing functions
1706          // -------------------------------------------------------------------------          // -------------------------------------------------------------------------
1707          // -------------------------------------------------------------------------          // -------------------------------------------------------------------------
1708          MYTYPE& ToUpper()          MYTYPE& ToUpper()
1709          {          {
1710                  //  Strictly speaking, this would be about the most portable way                  //  Strictly speaking, this would be about the most portable way
1711    
1712                  //      std::transform(begin(),                  //      std::transform(begin(),
1713                  //                                 end(),                  //                                 end(),
1714                  //                                 begin(),                  //                                 begin(),
1715                  //                                 std::bind2nd(SSToUpper<CT>(), std::locale()));                  //                                 std::bind2nd(SSToUpper<CT>(), std::locale()));
1716    
1717                  // But practically speaking, this works faster                  // But practically speaking, this works faster
1718    
1719                  if ( !empty() )                  if ( !empty() )
1720                          ssupr(GetBuf(), size());                          ssupr(GetBuf(), size());
1721    
1722                  return *this;                  return *this;
1723          }          }
1724    
1725    
1726    
1727          MYTYPE& ToLower()          MYTYPE& ToLower()
1728          {          {
1729                  //  Strictly speaking, this would be about the most portable way                  //  Strictly speaking, this would be about the most portable way
1730    
1731                  //      std::transform(begin(),                  //      std::transform(begin(),
1732                  //                                 end(),                  //                                 end(),
1733                  //                                 begin(),                  //                                 begin(),
1734                  //                                 std::bind2nd(SSToLower<CT>(), std::locale()));                  //                                 std::bind2nd(SSToLower<CT>(), std::locale()));
1735    
1736                  // But practically speaking, this works faster                  // But practically speaking, this works faster
1737    
1738                  if ( !empty() )                  if ( !empty() )
1739                          sslwr(GetBuf(), size());                          sslwr(GetBuf(), size());
1740    
1741                  return *this;                  return *this;
1742          }          }
1743    
1744    
1745    
1746          MYTYPE& Normalize()          MYTYPE& Normalize()
1747          {          {
1748                  return Trim().ToLower();                  return Trim().ToLower();
1749          }          }
1750    
1751    
1752          // -------------------------------------------------------------------------          // -------------------------------------------------------------------------
1753          // CStdStr -- Direct access to character buffer.  In the MS' implementation,          // CStdStr -- Direct access to character buffer.  In the MS' implementation,
1754          // the at() function that we use here also calls _Freeze() providing us some          // the at() function that we use here also calls _Freeze() providing us some
1755          // protection from multithreading problems associated with ref-counting.          // protection from multithreading problems associated with ref-counting.
1756          // -------------------------------------------------------------------------          // -------------------------------------------------------------------------
1757          CT* GetBuf(int nMinLen=-1)          CT* GetBuf(int nMinLen=-1)
1758          {          {
1759                  if ( static_cast<int>(size()) < nMinLen )                  if ( static_cast<int>(size()) < nMinLen )
1760                          resize(static_cast<MYSIZE>(nMinLen));                          resize(static_cast<MYSIZE>(nMinLen));
1761    
1762                  return empty() ? const_cast<CT*>(data()) : &(at(0));                  return empty() ? const_cast<CT*>(data()) : &(at(0));
1763          }          }
1764    
1765          CT* SetBuf(int nLen)          CT* SetBuf(int nLen)
1766          {          {
1767                  nLen = ( nLen > 0 ? nLen : 0 );                  nLen = ( nLen > 0 ? nLen : 0 );
1768                  if ( capacity() < 1 && nLen == 0 )                  if ( capacity() < 1 && nLen == 0 )
1769                          resize(1);                          resize(1);
1770    
1771                  resize(static_cast<MYSIZE>(nLen));                  resize(static_cast<MYSIZE>(nLen));
1772                  return const_cast<CT*>(data());                  return const_cast<CT*>(data());
1773          }          }
1774          void RelBuf(int nNewLen=-1)          void RelBuf(int nNewLen=-1)
1775          {          {
1776                  resize(static_cast<MYSIZE>(nNewLen > -1 ? nNewLen : sslen(c_str())));                  resize(static_cast<MYSIZE>(nNewLen > -1 ? nNewLen : sslen(c_str())));
1777          }          }
1778    
1779          void BufferRel()                 { RelBuf(); }                  // backwards compatability          void BufferRel()                 { RelBuf(); }                  // backwards compatability
1780          CT*  Buffer()                    { return GetBuf(); }   // backwards compatability          CT*  Buffer()                    { return GetBuf(); }   // backwards compatability
1781          CT*  BufferSet(int nLen) { return SetBuf(nLen);}// backwards compatability          CT*  BufferSet(int nLen) { return SetBuf(nLen);}// backwards compatability
1782    
1783          bool Equals(const CT* pT, bool bUseCase=false) const          bool Equals(const CT* pT, bool bUseCase=false) const
1784          {       // get copy, THEN compare (thread safe)          {       // get copy, THEN compare (thread safe)
1785                  return  bUseCase ? compare(pT) == 0 : ssicmp(MYTYPE(*this), pT) == 0;                  return  bUseCase ? compare(pT) == 0 : ssicmp(MYTYPE(*this), pT) == 0;
1786          }          }
1787    
1788          // -------------------------------------------------------------------------          // -------------------------------------------------------------------------
1789          // FUNCTION:  CStdStr::Load          // FUNCTION:  CStdStr::Load
1790          // REMARKS:          // REMARKS:
1791          //              Loads string from resource specified by nID          //              Loads string from resource specified by nID
1792          //          //
1793          // PARAMETERS:          // PARAMETERS:
1794          //              nID - resource Identifier.  Purely a Win32 thing in this case          //              nID - resource Identifier.  Purely a Win32 thing in this case
1795          //          //
1796          // RETURN VALUE:          // RETURN VALUE:
1797          //              true if successful, false otherwise          //              true if successful, false otherwise
1798          // -------------------------------------------------------------------------          // -------------------------------------------------------------------------
1799  #ifndef SS_ANSI  #ifndef SS_ANSI
1800          bool Load(UINT nId, HMODULE hModule=NULL)          bool Load(UINT nId, HMODULE hModule=NULL)
1801          {          {
1802                  bool bLoaded            = false;        // set to true of we succeed.                  bool bLoaded            = false;        // set to true of we succeed.
1803    
1804          #ifdef _MFC_VER         // When in Rome...          #ifdef _MFC_VER         // When in Rome...
1805    
1806                  CString strRes;                  CString strRes;
1807                  bLoaded                         = FALSE != strRes.LoadString(nId);                  bLoaded                         = FALSE != strRes.LoadString(nId);
1808                  if ( bLoaded )                  if ( bLoaded )
1809                          *this                   = strRes;                          *this                   = strRes;
1810    
1811          #else          #else
1812                                    
1813                  // Get the resource name and module handle                  // Get the resource name and module handle
1814    
1815                  if ( NULL == hModule )                  if ( NULL == hModule )
1816                          hModule                 = GetResourceHandle();                          hModule                 = GetResourceHandle();
1817    
1818                  PCTSTR szName           = MAKEINTRESOURCE((nId>>4)+1); // lifted                  PCTSTR szName           = MAKEINTRESOURCE((nId>>4)+1); // lifted
1819                  DWORD dwSize            = 0;                  DWORD dwSize            = 0;
1820    
1821                  // No sense continuing if we can't find the resource                  // No sense continuing if we can't find the resource
1822    
1823                  HRSRC hrsrc                     = ::FindResource(hModule, szName, RT_STRING);                  HRSRC hrsrc                     = ::FindResource(hModule, szName, RT_STRING);
1824    
1825                  if ( NULL == hrsrc )                  if ( NULL == hrsrc )
1826                          TRACE(_T("Cannot find resource %d: 0x%X"), nId, ::GetLastError());                          TRACE(_T("Cannot find resource %d: 0x%X"), nId, ::GetLastError());
1827                  else if ( 0 == (dwSize = ::SizeofResource(hModule, hrsrc) / sizeof(CT)))                  else if ( 0 == (dwSize = ::SizeofResource(hModule, hrsrc) / sizeof(CT)))
1828                          TRACE(_T("Cant get size of resource %d 0x%X\n"),nId,GetLastError());                          TRACE(_T("Cant get size of resource %d 0x%X\n"),nId,GetLastError());
1829                  else                  else
1830                  {                  {
1831                          bLoaded                 = 0 != ssload(hModule, nId, GetBuf(dwSize), dwSize);                          bLoaded                 = 0 != ssload(hModule, nId, GetBuf(dwSize), dwSize);
1832                          ReleaseBuffer();                          ReleaseBuffer();
1833                  }                  }
1834    
1835          #endif          #endif
1836    
1837                  if ( !bLoaded )                  if ( !bLoaded )
1838                          TRACE(_T("String not loaded 0x%X\n"), ::GetLastError());                          TRACE(_T("String not loaded 0x%X\n"), ::GetLastError());
1839    
1840                  return bLoaded;                  return bLoaded;
1841          }          }
1842  #endif  #endif
1843                    
1844          // -------------------------------------------------------------------------          // -------------------------------------------------------------------------
1845          // FUNCTION:  CStdStr::Format          // FUNCTION:  CStdStr::Format
1846          //              void _cdecl Formst(CStdStringA& PCSTR szFormat, ...)          //              void _cdecl Formst(CStdStringA& PCSTR szFormat, ...)
1847          //              void _cdecl Format(PCSTR szFormat);          //              void _cdecl Format(PCSTR szFormat);
1848          //                    //          
1849          // DESCRIPTION:          // DESCRIPTION:
1850          //              This function does sprintf/wsprintf style formatting on CStdStringA          //              This function does sprintf/wsprintf style formatting on CStdStringA
1851          //              objects.  It looks a lot like MFC's CString::Format.  Some people          //              objects.  It looks a lot like MFC's CString::Format.  Some people
1852          //              might even call this identical.  Fortunately, these people are now          //              might even call this identical.  Fortunately, these people are now
1853          //              dead.          //              dead.
1854          //          //
1855          // PARAMETERS:          // PARAMETERS:
1856          //              nId - ID of string resource holding the format string          //              nId - ID of string resource holding the format string
1857          //              szFormat - a PCSTR holding the format specifiers          //              szFormat - a PCSTR holding the format specifiers
1858          //              argList - a va_list holding the arguments for the format specifiers.          //              argList - a va_list holding the arguments for the format specifiers.
1859          //          //
1860          // RETURN VALUE:  None.          // RETURN VALUE:  None.
1861          // -------------------------------------------------------------------------          // -------------------------------------------------------------------------
1862          // formatting (using wsprintf style formatting)          // formatting (using wsprintf style formatting)
1863          #ifndef SS_ANSI          #ifndef SS_ANSI
1864          void Format(UINT nId, ...)          void Format(UINT nId, ...)
1865          {          {
1866                  va_list argList;                  va_list argList;
1867                  va_start(argList, nId);                  va_start(argList, nId);
1868                  va_start(argList, nId);                  va_start(argList, nId);
1869    
1870                  MYTYPE strFmt;                  MYTYPE strFmt;
1871                  if ( strFmt.Load(nId) )                  if ( strFmt.Load(nId) )
1872                          FormatV(strFmt, argList);                          FormatV(strFmt, argList);
1873    
1874                  va_end(argList);                  va_end(argList);
1875          }          }
1876          #endif          #endif
1877          void Format(const CT* szFmt, ...)          void Format(const CT* szFmt, ...)
1878          {          {
1879                  va_list argList;                  va_list argList;
1880                  va_start(argList, szFmt);                  va_start(argList, szFmt);
1881                  FormatV(szFmt, argList);                  FormatV(szFmt, argList);
1882                  va_end(argList);                  va_end(argList);
1883          }          }
1884          void AppendFormat(const CT* szFmt, ...)          void AppendFormat(const CT* szFmt, ...)
1885          {          {
1886                  va_list argList;                  va_list argList;
1887                  va_start(argList, szFmt);                  va_start(argList, szFmt);
1888                  AppendFormatV(szFmt, argList);                  AppendFormatV(szFmt, argList);
1889                  va_end(argList);                  va_end(argList);
1890          }          }
1891    
1892          #define MAX_FMT_TRIES           5        // #of times we try          #define MAX_FMT_TRIES           5        // #of times we try
1893          #define FMT_BLOCK_SIZE          2048 // # of bytes to increment per try          #define FMT_BLOCK_SIZE          2048 // # of bytes to increment per try
1894          #define BUFSIZE_1ST     256          #define BUFSIZE_1ST     256
1895          #define BUFSIZE_2ND 512          #define BUFSIZE_2ND 512
1896          #define STD_BUF_SIZE            1024          #define STD_BUF_SIZE            1024
1897    
1898          // an efficient way to add formatted characters to the string.  You may only          // an efficient way to add formatted characters to the string.  You may only
1899          // add up to STD_BUF_SIZE characters at a time, though          // add up to STD_BUF_SIZE characters at a time, though
1900          void AppendFormatV(const CT* szFmt, va_list argList)          void AppendFormatV(const CT* szFmt, va_list argList)
1901          {          {
1902                  CT szBuf[STD_BUF_SIZE];                  CT szBuf[STD_BUF_SIZE];
1903          #ifdef SS_ANSI          #ifdef SS_ANSI
1904                  int nLen = ssvsprintf(szBuf, STD_BUF_SIZE-1, szFmt, argList);                  int nLen = ssvsprintf(szBuf, STD_BUF_SIZE-1, szFmt, argList);
1905          #else          #else
1906                  int nLen = ssnprintf(szBuf, STD_BUF_SIZE-1, szFmt, argList);                  int nLen = ssnprintf(szBuf, STD_BUF_SIZE-1, szFmt, argList);
1907          #endif          #endif
1908                  if ( 0 < nLen )                  if ( 0 < nLen )
1909                          append(szBuf, nLen);                          append(szBuf, nLen);
1910          }          }
1911    
1912          // -------------------------------------------------------------------------          // -------------------------------------------------------------------------
1913          // FUNCTION:  FormatV          // FUNCTION:  FormatV
1914          //              void FormatV(PCSTR szFormat, va_list, argList);          //              void FormatV(PCSTR szFormat, va_list, argList);
1915          //                    //          
1916          // DESCRIPTION:          // DESCRIPTION:
1917          //              This function formats the string with sprintf style format-specs.          //              This function formats the string with sprintf style format-specs.
1918          //              It makes a general guess at required buffer size and then tries          //              It makes a general guess at required buffer size and then tries
1919          //              successively larger buffers until it finds one big enough or a          //              successively larger buffers until it finds one big enough or a
1920          //              threshold (MAX_FMT_TRIES) is exceeded.          //              threshold (MAX_FMT_TRIES) is exceeded.
1921          //          //
1922          // PARAMETERS:          // PARAMETERS:
1923          //              szFormat - a PCSTR holding the format of the output          //              szFormat - a PCSTR holding the format of the output
1924          //              argList - a Microsoft specific va_list for variable argument lists          //              argList - a Microsoft specific va_list for variable argument lists
1925          //          //
1926          // RETURN VALUE:          // RETURN VALUE:
1927          // -------------------------------------------------------------------------          // -------------------------------------------------------------------------
1928    
1929          void FormatV(const CT* szFormat, va_list argList)          void FormatV(const CT* szFormat, va_list argList)
1930          {          {
1931          #ifdef SS_ANSI          #ifdef SS_ANSI
1932    
1933                  int nLen        = sslen(szFormat) + STD_BUF_SIZE;                  int nLen        = sslen(szFormat) + STD_BUF_SIZE;
1934                  ssvsprintf(GetBuffer(nLen), nLen-1, szFormat, argList);                  ssvsprintf(GetBuffer(nLen), nLen-1, szFormat, argList);
1935                  ReleaseBuffer();                  ReleaseBuffer();
1936    
1937          #else          #else
1938    
1939                  CT* pBuf                        = NULL;                  CT* pBuf                        = NULL;
1940                  int nChars                      = 1;                  int nChars                      = 1;
1941                  int nUsed                       = 0;                  int nUsed                       = 0;
1942                  size_type nActual       = 0;                  size_type nActual       = 0;
1943                  int nTry                        = 0;                  int nTry                        = 0;
1944    
1945                  do                        do      
1946                  {                  {
1947                          // Grow more than linearly (e.g. 512, 1536, 3072, etc)                          // Grow more than linearly (e.g. 512, 1536, 3072, etc)
1948    
1949                          nChars                  += ((nTry+1) * FMT_BLOCK_SIZE);                          nChars                  += ((nTry+1) * FMT_BLOCK_SIZE);
1950                          pBuf                    = reinterpret_cast<CT*>(_alloca(sizeof(CT)*nChars));                          pBuf                    = reinterpret_cast<CT*>(_alloca(sizeof(CT)*nChars));
1951                          nUsed                   = ssnprintf(pBuf, nChars-1, szFormat, argList);                          nUsed                   = ssnprintf(pBuf, nChars-1, szFormat, argList);
1952    
1953                          // Ensure proper NULL termination.                          // Ensure proper NULL termination.
1954    
1955                          nActual                 = nUsed == -1 ? nChars-1 : SSMIN(nUsed, nChars-1);                          nActual                 = nUsed == -1 ? nChars-1 : SSMIN(nUsed, nChars-1);
1956                          pBuf[nActual+1]= '\0';                          pBuf[nActual+1]= '\0';
1957    
1958    
1959                  } while ( nUsed < 0 && nTry++ < MAX_FMT_TRIES );                  } while ( nUsed < 0 && nTry++ < MAX_FMT_TRIES );
1960    
1961                  // assign whatever we managed to format                  // assign whatever we managed to format
1962    
1963                  assign(pBuf, nActual);                  assign(pBuf, nActual);
1964    
1965          #endif          #endif
1966          }          }
1967                    
1968    
1969          // -------------------------------------------------------------------------          // -------------------------------------------------------------------------
1970          // CString Facade Functions:          // CString Facade Functions:
1971          //          //
1972          // The following methods are intended to allow you to use this class as a          // The following methods are intended to allow you to use this class as a
1973          // drop-in replacement for CString.          // drop-in replacement for CString.
1974          // -------------------------------------------------------------------------          // -------------------------------------------------------------------------
1975          #ifndef SS_ANSI          #ifndef SS_ANSI
1976                  BSTR AllocSysString() const                  BSTR AllocSysString() const
1977                  {                  {
1978                          ostring os;                          ostring os;
1979                          ssasn(os, *this);                          ssasn(os, *this);
1980                          return ::SysAllocString(os.c_str());                          return ::SysAllocString(os.c_str());
1981                  }                  }
1982          #endif          #endif
1983    
1984          int Collate(PCMYSTR szThat) const          int Collate(PCMYSTR szThat) const
1985          {          {
1986                  return sscoll(c_str(), length(), szThat, sslen(szThat));                  return sscoll(c_str(), length(), szThat, sslen(szThat));
1987          }          }
1988    
1989          int CollateNoCase(PCMYSTR szThat) const          int CollateNoCase(PCMYSTR szThat) const
1990          {          {
1991                  return ssicoll(c_str(), length(), szThat, sslen(szThat));                  return ssicoll(c_str(), length(), szThat, sslen(szThat));
1992          }          }
1993    
1994          int Compare(PCMYSTR szThat) const          int Compare(PCMYSTR szThat) const
1995          {          {
1996                  return MYBASE::compare(szThat);                  return MYBASE::compare(szThat);
1997          }          }
1998    
1999          int CompareNoCase(PCMYSTR szThat)       const          int CompareNoCase(PCMYSTR szThat)       const
2000          {          {
2001                  return ssicmp(c_str(), szThat);                  return ssicmp(c_str(), szThat);
2002          }          }
2003    
2004          int Delete(int nIdx, int nCount=1)          int Delete(int nIdx, int nCount=1)
2005          {          {
2006                  if ( nIdx < GetLength() )                  if ( nIdx < GetLength() )
2007                          erase(static_cast<MYSIZE>(nIdx), static_cast<MYSIZE>(nCount));                          erase(static_cast<MYSIZE>(nIdx), static_cast<MYSIZE>(nCount));
2008    
2009                  return GetLength();                  return GetLength();
2010          }          }
2011    
2012          void Empty()          void Empty()
2013          {          {
2014                  erase();                  erase();
2015          }          }
2016    
2017          int Find(CT ch) const          int Find(CT ch) const
2018          {          {
2019                  MYSIZE nIdx     = find_first_of(ch);                  MYSIZE nIdx     = find_first_of(ch);
2020                  return static_cast<int>(MYBASE::npos == nIdx  ? -1 : nIdx);                  return static_cast<int>(MYBASE::npos == nIdx  ? -1 : nIdx);
2021          }          }
2022    
2023          int Find(PCMYSTR szSub) const          int Find(PCMYSTR szSub) const
2024          {          {
2025                  MYSIZE nIdx     = find(szSub);                  MYSIZE nIdx     = find(szSub);
2026                  return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);                  return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);
2027          }          }
2028    
2029          int Find(CT ch, int nStart) const          int Find(CT ch, int nStart) const
2030          {          {
2031                  // CString::Find docs say add 1 to nStart when it's not zero                  // CString::Find docs say add 1 to nStart when it's not zero
2032                  // CString::Find code doesn't do that however.  We'll stick                  // CString::Find code doesn't do that however.  We'll stick
2033                  // with what the code does                  // with what the code does
2034    
2035                  MYSIZE nIdx     = find_first_of(ch, static_cast<MYSIZE>(nStart));                  MYSIZE nIdx     = find_first_of(ch, static_cast<MYSIZE>(nStart));
2036                  return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);                  return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);
2037          }          }
2038    
2039          int Find(PCMYSTR szSub, int nStart) const          int Find(PCMYSTR szSub, int nStart) const
2040          {          {
2041                  // CString::Find docs say add 1 to nStart when it's not zero                  // CString::Find docs say add 1 to nStart when it's not zero
2042                  // CString::Find code doesn't do that however.  We'll stick                  // CString::Find code doesn't do that however.  We'll stick
2043                  // with what the code does                  // with what the code does
2044    
2045                  MYSIZE nIdx     = find(szSub, static_cast<MYSIZE>(nStart));                  MYSIZE nIdx     = find(szSub, static_cast<MYSIZE>(nStart));
2046                  return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);                  return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);
2047          }          }
2048    
2049          int FindOneOf(PCMYSTR szCharSet) const          int FindOneOf(PCMYSTR szCharSet) const
2050          {          {
2051                  MYSIZE nIdx = find_first_of(szCharSet);                  MYSIZE nIdx = find_first_of(szCharSet);
2052                  return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);                  return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);
2053          }          }
2054    
2055  #ifndef SS_ANSI  #ifndef SS_ANSI
2056          void FormatMessage(PCMYSTR szFormat, ...) throw(std::exception)          void FormatMessage(PCMYSTR szFormat, ...) throw(std::exception)
2057          {          {
2058                  va_list argList;                  va_list argList;
2059                  va_start(argList, szFormat);                  va_start(argList, szFormat);
2060                  PMYSTR szTemp;                  PMYSTR szTemp;
2061                  if ( ssfmtmsg(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ALLOCATE_BUFFER,                  if ( ssfmtmsg(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ALLOCATE_BUFFER,
2062                                             szFormat, 0, 0,                                             szFormat, 0, 0,
2063                                             reinterpret_cast<PMYSTR>(&szTemp), 0, &argList) == 0 ||                                             reinterpret_cast<PMYSTR>(&szTemp), 0, &argList) == 0 ||
2064                           szTemp == 0 )                           szTemp == 0 )
2065                  {                  {
2066                          throw std::runtime_error("out of memory");                          throw std::runtime_error("out of memory");
2067                  }                  }
2068                  *this = szTemp;                  *this = szTemp;
2069                  LocalFree(szTemp);                  LocalFree(szTemp);
2070                  va_end(argList);                  va_end(argList);
2071          }          }
2072    
2073          void FormatMessage(UINT nFormatId, ...) throw(std::exception)          void FormatMessage(UINT nFormatId, ...) throw(std::exception)
2074          {          {
2075                  MYTYPE sFormat;                  MYTYPE sFormat;
2076                  VERIFY(sFormat.LoadString(nFormatId) != 0);                  VERIFY(sFormat.LoadString(nFormatId) != 0);
2077                  va_list argList;                  va_list argList;
2078                  va_start(argList, nFormatId);                  va_start(argList, nFormatId);
2079                  PMYSTR szTemp;                  PMYSTR szTemp;
2080                  if ( ssfmtmsg(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ALLOCATE_BUFFER,                  if ( ssfmtmsg(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ALLOCATE_BUFFER,
2081                                             sFormat, 0, 0,                                             sFormat, 0, 0,
2082                                             reinterpret_cast<PMYSTR>(&szTemp), 0, &argList) == 0 ||                                             reinterpret_cast<PMYSTR>(&szTemp), 0, &argList) == 0 ||
2083                          szTemp == 0)                          szTemp == 0)
2084                  {                  {
2085                          throw std::runtime_error("out of memory");                          throw std::runtime_error("out of memory");
2086                  }                  }
2087                  *this = szTemp;                  *this = szTemp;
2088                  LocalFree(szTemp);                  LocalFree(szTemp);
2089                  va_end(argList);                  va_end(argList);
2090          }          }
2091  #endif  #endif
2092    
2093    
2094          // -------------------------------------------------------------------------          // -------------------------------------------------------------------------
2095          // GetXXXX -- Direct access to character buffer          // GetXXXX -- Direct access to character buffer
2096          // -------------------------------------------------------------------------          // -------------------------------------------------------------------------
2097          CT GetAt(int nIdx) const          CT GetAt(int nIdx) const
2098          {          {
2099                  return at(static_cast<MYSIZE>(nIdx));                  return at(static_cast<MYSIZE>(nIdx));
2100          }          }
2101    
2102          CT* GetBuffer(int nMinLen=-1)          CT* GetBuffer(int nMinLen=-1)
2103          {          {
2104                  return GetBuf(nMinLen);                  return GetBuf(nMinLen);
2105          }          }
2106    
2107          CT* GetBufferSetLength(int nLen)          CT* GetBufferSetLength(int nLen)
2108          {          {
2109                  return BufferSet(nLen);                  return BufferSet(nLen);
2110          }          }
2111    
2112          // GetLength() -- MFC docs say this is the # of BYTES but          // GetLength() -- MFC docs say this is the # of BYTES but
2113          // in truth it is the number of CHARACTERs (chars or wchar_ts)          // in truth it is the number of CHARACTERs (chars or wchar_ts)
2114          int GetLength() const          int GetLength() const
2115          {          {
2116                  return static_cast<int>(length());                  return static_cast<int>(length());
2117          }          }
2118    
2119                    
2120          int Insert(int nIdx, CT ch)          int Insert(int nIdx, CT ch)
2121          {          {
2122                  if ( static_cast<MYSIZE>(nIdx) > size() -1 )                  if ( static_cast<MYSIZE>(nIdx) > size() -1 )
2123                          append(1, ch);                          append(1, ch);
2124                  else                  else
2125                          insert(static_cast<MYSIZE>(nIdx), 1, ch);                          insert(static_cast<MYSIZE>(nIdx), 1, ch);
2126    
2127                  return GetLength();                  return GetLength();
2128          }          }
2129          int Insert(int nIdx, PCMYSTR sz)          int Insert(int nIdx, PCMYSTR sz)
2130          {          {
2131                  if ( nIdx >= size() )                  if ( nIdx >= size() )
2132                          append(sz, sslen(sz));                          append(sz, sslen(sz));
2133                  else                  else
2134                          insert(static_cast<MYSIZE>(nIdx), sz);                          insert(static_cast<MYSIZE>(nIdx), sz);
2135    
2136                  return GetLength();                  return GetLength();
2137          }          }
2138    
2139          bool IsEmpty() const          bool IsEmpty() const
2140          {          {
2141                  return empty();                  return empty();
2142          }          }
2143    
2144          MYTYPE Left(int nCount) const          MYTYPE Left(int nCount) const
2145          {          {
2146                  return substr(0, static_cast<MYSIZE>(nCount));                  return substr(0, static_cast<MYSIZE>(nCount));
2147          }          }
2148    
2149          #ifndef SS_ANSI          #ifndef SS_ANSI
2150          bool LoadString(UINT nId)          bool LoadString(UINT nId)
2151          {          {
2152                  return this->Load(nId);                  return this->Load(nId);
2153          }          }
2154          #endif          #endif
2155    
2156          void MakeLower()          void MakeLower()
2157          {          {
2158                  ToLower();                  ToLower();
2159          }          }
2160    
2161          void MakeReverse()          void MakeReverse()
2162          {          {
2163                  std::reverse(begin(), end());                  std::reverse(begin(), end());
2164          }          }
2165    
2166          void MakeUpper()          void MakeUpper()
2167          {          {
2168                  ToUpper();                  ToUpper();
2169          }          }
2170    
2171          MYTYPE Mid(int nFirst ) const          MYTYPE Mid(int nFirst ) const
2172          {          {
2173                  return substr(static_cast<MYSIZE>(nFirst));                  return substr(static_cast<MYSIZE>(nFirst));
2174          }          }
2175    
2176          MYTYPE Mid(int nFirst, int nCount) const          MYTYPE Mid(int nFirst, int nCount) const
2177          {          {
2178                  return substr(static_cast<MYSIZE>(nFirst), static_cast<MYSIZE>(nCount));                  return substr(static_cast<MYSIZE>(nFirst), static_cast<MYSIZE>(nCount));
2179          }          }
2180    
2181          void ReleaseBuffer(int nNewLen=-1)          void ReleaseBuffer(int nNewLen=-1)
2182          {          {
2183                  RelBuf(nNewLen);                  RelBuf(nNewLen);
2184          }          }
2185    
2186          int Remove(CT ch)          int Remove(CT ch)
2187          {          {
2188                  MYSIZE nIdx             = 0;                  MYSIZE nIdx             = 0;
2189                  int nRemoved    = 0;                  int nRemoved    = 0;
2190                  while ( (nIdx=find_first_of(ch)) != MYBASE::npos )                  while ( (nIdx=find_first_of(ch)) != MYBASE::npos )
2191                  {                  {
2192                          erase(nIdx, 1);                          erase(nIdx, 1);
2193                          nRemoved++;                          nRemoved++;
2194                  }                  }
2195                  return nRemoved;                  return nRemoved;
2196          }          }
2197    
2198          int Replace(CT chOld, CT chNew)          int Replace(CT chOld, CT chNew)
2199          {          {
2200                  int nReplaced   = 0;                  int nReplaced   = 0;
2201                  for ( MYITER iter=begin(); iter != end(); iter++ )                  for ( MYITER iter=begin(); iter != end(); iter++ )
2202                  {                  {
2203                          if ( *iter == chOld )                          if ( *iter == chOld )
2204                          {                          {
2205                                  *iter = chNew;                                  *iter = chNew;
2206                                  nReplaced++;                                  nReplaced++;
2207                          }                          }
2208                  }                  }
2209                  return nReplaced;                  return nReplaced;
2210          }          }
2211    
2212          int Replace(PCMYSTR szOld, PCMYSTR szNew)          int Replace(PCMYSTR szOld, PCMYSTR szNew)
2213          {          {
2214                  int nReplaced           = 0;                  int nReplaced           = 0;
2215                  MYSIZE nIdx                     = 0;                  MYSIZE nIdx                     = 0;
2216                  MYSIZE nOldLen          = sslen(szOld);                  MYSIZE nOldLen          = sslen(szOld);
2217                  if ( 0 == nOldLen )                  if ( 0 == nOldLen )
2218                          return 0;                          return 0;
2219    
2220                  static const CT ch      = CT(0);                  static const CT ch      = CT(0);
2221                  MYSIZE nNewLen          = sslen(szNew);                  MYSIZE nNewLen          = sslen(szNew);
2222                  PCMYSTR szRealNew       = szNew == 0 ? &ch : szNew;                  PCMYSTR szRealNew       = szNew == 0 ? &ch : szNew;
2223    
2224                  while ( (nIdx=find(szOld, nIdx)) != MYBASE::npos )                  while ( (nIdx=find(szOld, nIdx)) != MYBASE::npos )
2225                  {                  {
2226                          replace(begin()+nIdx, begin()+nIdx+nOldLen, szRealNew);                          replace(begin()+nIdx, begin()+nIdx+nOldLen, szRealNew);
2227                          nReplaced++;                          nReplaced++;
2228                          nIdx += nNewLen;                          nIdx += nNewLen;
2229                  }                  }
2230                  return nReplaced;                  return nReplaced;
2231          }          }
2232    
2233          int ReverseFind(CT ch) const          int ReverseFind(CT ch) const
2234          {          {
2235                  MYSIZE nIdx     = find_last_of(ch);                  MYSIZE nIdx     = find_last_of(ch);
2236                  return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);                  return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);
2237          }          }
2238    
2239          // ReverseFind overload that's not in CString but might be useful          // ReverseFind overload that's not in CString but might be useful
2240          int ReverseFind(PCMYSTR szFind, MYSIZE pos=MYBASE::npos) const          int ReverseFind(PCMYSTR szFind, MYSIZE pos=MYBASE::npos) const
2241          {          {
2242                  MYSIZE nIdx     = rfind(0 == szFind ? MYTYPE() : szFind, pos);                  MYSIZE nIdx     = rfind(0 == szFind ? MYTYPE() : szFind, pos);
2243                  return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);                  return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);
2244          }          }
2245    
2246          MYTYPE Right(int nCount) const          MYTYPE Right(int nCount) const
2247          {          {
2248                  nCount = SSMIN(nCount, static_cast<int>(size()));                  nCount = SSMIN(nCount, static_cast<int>(size()));
2249                  return substr(size()-static_cast<MYSIZE>(nCount));                  return substr(size()-static_cast<MYSIZE>(nCount));
2250          }          }
2251    
2252          void SetAt(int nIndex, CT ch)          void SetAt(int nIndex, CT ch)
2253          {          {
2254                  ASSERT(size() > static_cast<MYSIZE>(nIndex));                  ASSERT(size() > static_cast<MYSIZE>(nIndex));
2255                  at(static_cast<MYSIZE>(nIndex))         = ch;                  at(static_cast<MYSIZE>(nIndex))         = ch;
2256          }          }
2257    
2258          #ifndef SS_ANSI          #ifndef SS_ANSI
2259                  BSTR SetSysString(BSTR* pbstr) const                  BSTR SetSysString(BSTR* pbstr) const
2260                  {                  {
2261                          ostring os;                          ostring os;
2262                          ssasn(os, *this);                          ssasn(os, *this);
2263                          if ( !::SysReAllocStringLen(pbstr, os.c_str(), os.length()) )                          if ( !::SysReAllocStringLen(pbstr, os.c_str(), os.length()) )
2264                                  throw std::runtime_error("out of memory");                                  throw std::runtime_error("out of memory");
2265    
2266                          ASSERT(*pbstr != 0);                          ASSERT(*pbstr != 0);
2267                          return *pbstr;                          return *pbstr;
2268                  }                  }
2269          #endif          #endif
2270    
2271          MYTYPE SpanExcluding(PCMYSTR szCharSet) const          MYTYPE SpanExcluding(PCMYSTR szCharSet) const
2272          {          {
2273                  return Left(find_first_of(szCharSet));                  return Left(find_first_of(szCharSet));
2274          }          }
2275    
2276          MYTYPE SpanIncluding(PCMYSTR szCharSet) const          MYTYPE SpanIncluding(PCMYSTR szCharSet) const
2277          {          {
2278                  return Left(find_first_not_of(szCharSet));                  return Left(find_first_not_of(szCharSet));
2279          }          }
2280    
2281          #if !defined(UNICODE) && !defined(SS_ANSI)          #if !defined(UNICODE) && !defined(SS_ANSI)
2282    
2283                  // CString's OemToAnsi and AnsiToOem functions are available only in                  // CString's OemToAnsi and AnsiToOem functions are available only in
2284                  // Unicode builds.  However since we're a template we also need a                  // Unicode builds.  However since we're a template we also need a
2285                  // runtime check of CT and a reinterpret_cast to account for the fact                  // runtime check of CT and a reinterpret_cast to account for the fact
2286                  // that CStdStringW gets instantiated even in non-Unicode builds.                  // that CStdStringW gets instantiated even in non-Unicode builds.
2287    
2288                  void AnsiToOem()                  void AnsiToOem()
2289                  {                  {
2290                          if ( sizeof(CT) == sizeof(char) && !empty() )                          if ( sizeof(CT) == sizeof(char) && !empty() )
2291                          {                          {
2292                                  ::CharToOem(reinterpret_cast<PCSTR>(c_str()),                                  ::CharToOem(reinterpret_cast<PCSTR>(c_str()),
2293                                                          reinterpret_cast<PSTR>(GetBuf()));                                                          reinterpret_cast<PSTR>(GetBuf()));
2294                          }                          }
2295                          else                          else
2296                          {                          {
2297                                  ASSERT(false);                                  ASSERT(false);
2298                          }                          }
2299                  }                  }
2300    
2301                  void OemToAnsi()                  void OemToAnsi()
2302                  {                  {
2303                          if ( sizeof(CT) == sizeof(char) && !empty() )                          if ( sizeof(CT) == sizeof(char) && !empty() )
2304                          {                          {
2305                                  ::OemToChar(reinterpret_cast<PCSTR>(c_str()),                                  ::OemToChar(reinterpret_cast<PCSTR>(c_str()),
2306                                                          reinterpret_cast<PSTR>(GetBuf()));                                                          reinterpret_cast<PSTR>(GetBuf()));
2307                          }                          }
2308                          else                          else
2309                          {                          {
2310                                  ASSERT(false);                                  ASSERT(false);
2311                          }                          }
2312                  }                  }
2313    
2314          #endif          #endif
2315                    
2316    
2317          // -------------------------------------------------------------------------          // -------------------------------------------------------------------------
2318          // Trim and its variants          // Trim and its variants
2319          // -------------------------------------------------------------------------          // -------------------------------------------------------------------------
2320          MYTYPE& Trim()          MYTYPE& Trim()
2321          {          {
2322                  return TrimLeft().TrimRight();                  return TrimLeft().TrimRight();
2323          }          }
2324    
2325          MYTYPE& TrimLeft()          MYTYPE& TrimLeft()
2326          {          {
2327                  erase(begin(), std::find_if(begin(),end(),NotSpace<CT>(std::locale())));                  erase(begin(), std::find_if(begin(),end(),NotSpace<CT>(std::locale())));
2328                  return *this;                  return *this;
2329          }          }
2330    
2331          MYTYPE&  TrimLeft(CT tTrim)          MYTYPE&  TrimLeft(CT tTrim)
2332          {          {
2333                  erase(0, find_first_not_of(tTrim));                  erase(0, find_first_not_of(tTrim));
2334                  return *this;                  return *this;
2335          }          }
2336    
2337          MYTYPE&  TrimLeft(PCMYSTR szTrimChars)          MYTYPE&  TrimLeft(PCMYSTR szTrimChars)
2338          {          {
2339                  erase(0, find_first_not_of(szTrimChars));                  erase(0, find_first_not_of(szTrimChars));
2340                  return *this;                  return *this;
2341          }          }
2342    
2343          MYTYPE& TrimRight()          MYTYPE& TrimRight()
2344          {          {
2345                  std::locale loc;                  std::locale loc;
2346                  MYRITER it = std::find_if(rbegin(), rend(), NotSpace<CT>(loc));                  MYRITER it = std::find_if(rbegin(), rend(), NotSpace<CT>(loc));
2347                  if ( rend() != it )                  if ( rend() != it )
2348                          erase(rend() - it);                          erase(rend() - it);
2349    
2350                  erase(it != rend() ? find_last_of(*it) + 1 : 0);                  erase(it != rend() ? find_last_of(*it) + 1 : 0);
2351                  return *this;                  return *this;
2352          }          }
2353    
2354          MYTYPE&  TrimRight(CT tTrim)          MYTYPE&  TrimRight(CT tTrim)
2355          {          {
2356                  MYSIZE nIdx     = find_last_not_of(tTrim);                  MYSIZE nIdx     = find_last_not_of(tTrim);
2357                  erase(MYBASE::npos == nIdx ? 0 : ++nIdx);                  erase(MYBASE::npos == nIdx ? 0 : ++nIdx);
2358                  return *this;                  return *this;
2359          }          }
2360    
2361          MYTYPE&  TrimRight(PCMYSTR szTrimChars)          MYTYPE&  TrimRight(PCMYSTR szTrimChars)
2362          {          {
2363                  MYSIZE nIdx     = find_last_not_of(szTrimChars);                  MYSIZE nIdx     = find_last_not_of(szTrimChars);
2364                  erase(MYBASE::npos == nIdx ? 0 : ++nIdx);                  erase(MYBASE::npos == nIdx ? 0 : ++nIdx);
2365                  return *this;                  return *this;
2366          }          }
2367    
2368          void                    FreeExtra()          void                    FreeExtra()
2369          {          {
2370                  MYTYPE mt;                  MYTYPE mt;
2371                  swap(mt);                  swap(mt);
2372                  if ( !mt.empty() )                  if ( !mt.empty() )
2373                          assign(mt.c_str(), mt.size());                          assign(mt.c_str(), mt.size());
2374          }          }
2375    
2376          // I have intentionally not implemented the following CString          // I have intentionally not implemented the following CString
2377          // functions.   You cannot make them work without taking advantage          // functions.   You cannot make them work without taking advantage
2378          // of implementation specific behavior.  However if you absolutely          // of implementation specific behavior.  However if you absolutely
2379          // MUST have them, uncomment out these lines for "sort-of-like"          // MUST have them, uncomment out these lines for "sort-of-like"
2380          // their behavior.  You're on your own.          // their behavior.  You're on your own.
2381    
2382  //      CT*                             LockBuffer()    { return GetBuf(); }// won't really lock  //      CT*                             LockBuffer()    { return GetBuf(); }// won't really lock
2383  //      void                    UnlockBuffer(); { }     // why have UnlockBuffer w/o LockBuffer?  //      void                    UnlockBuffer(); { }     // why have UnlockBuffer w/o LockBuffer?
2384    
2385          // Array-indexing operators.  Required because we defined an implicit cast          // Array-indexing operators.  Required because we defined an implicit cast
2386          // to operator const CT* (Thanks to Julian Selman for pointing this out)          // to operator const CT* (Thanks to Julian Selman for pointing this out)
2387          CT& operator[](int nIdx)          CT& operator[](int nIdx)
2388          {          {
2389                  return MYBASE::operator[](static_cast<MYSIZE>(nIdx));                  return MYBASE::operator[](static_cast<MYSIZE>(nIdx));
2390          }          }
2391    
2392          const CT& operator[](int nIdx) const          const CT& operator[](int nIdx) const
2393          {          {
2394                  return MYBASE::operator[](static_cast<MYSIZE>(nIdx));                  return MYBASE::operator[](static_cast<MYSIZE>(nIdx));
2395          }          }
2396    
2397          CT& operator[](unsigned int nIdx)          CT& operator[](unsigned int nIdx)
2398          {          {
2399                  return MYBASE::operator[](static_cast<MYSIZE>(nIdx));                  return MYBASE::operator[](static_cast<MYSIZE>(nIdx));
2400          }          }
2401    
2402          const CT& operator[](unsigned int nIdx) const          const CT& operator[](unsigned int nIdx) const
2403          {          {
2404                  return MYBASE::operator[](static_cast<MYSIZE>(nIdx));                  return MYBASE::operator[](static_cast<MYSIZE>(nIdx));
2405          }          }
2406    
2407          operator const CT*() const          operator const CT*() const
2408          {          {
2409                  return c_str();                  return c_str();
2410          }          }
2411    
2412          // IStream related functions.  Useful in IPersistStream implementations          // IStream related functions.  Useful in IPersistStream implementations
2413    
2414  #ifdef SS_INC_COMDEF  #ifdef SS_INC_COMDEF
2415    
2416          // struct SSSHDR - useful for non Std C++ persistence schemes.          // struct SSSHDR - useful for non Std C++ persistence schemes.
2417          typedef struct SSSHDR          typedef struct SSSHDR
2418          {          {
2419                  BYTE    byCtrl;                  BYTE    byCtrl;
2420                  ULONG   nChars;                  ULONG   nChars;
2421          } SSSHDR;       // as in "Standard String Stream Header"          } SSSHDR;       // as in "Standard String Stream Header"
2422    
2423          #define SSSO_UNICODE    0x01    // the string is a wide string          #define SSSO_UNICODE    0x01    // the string is a wide string
2424          #define SSSO_COMPRESS   0x02    // the string is compressed          #define SSSO_COMPRESS   0x02    // the string is compressed
2425    
2426          // -------------------------------------------------------------------------          // -------------------------------------------------------------------------
2427          // FUNCTION: StreamSize          // FUNCTION: StreamSize
2428          // REMARKS:          // REMARKS:
2429          //              Returns how many bytes it will take to StreamSave() this CStdString          //              Returns how many bytes it will take to StreamSave() this CStdString
2430          //              object to an IStream.          //              object to an IStream.
2431          // -------------------------------------------------------------------------          // -------------------------------------------------------------------------
2432          ULONG StreamSize() const          ULONG StreamSize() const
2433          {          {
2434                  // Control header plus string                  // Control header plus string
2435                  ASSERT(size()*sizeof(CT) < 0xffffffffUL - sizeof(SSSHDR));                  ASSERT(size()*sizeof(CT) < 0xffffffffUL - sizeof(SSSHDR));
2436                  return (size() * sizeof(CT)) + sizeof(SSSHDR);                  return (size() * sizeof(CT)) + sizeof(SSSHDR);
2437          }          }
2438    
2439          // -------------------------------------------------------------------------          // -------------------------------------------------------------------------
2440          // FUNCTION: StreamSave          // FUNCTION: StreamSave
2441          // REMARKS:          // REMARKS:
2442          //              Saves this CStdString object to a COM IStream.          //              Saves this CStdString object to a COM IStream.
2443          // -------------------------------------------------------------------------          // -------------------------------------------------------------------------
2444          HRESULT StreamSave(IStream* pStream) const          HRESULT StreamSave(IStream* pStream) const
2445          {          {
2446                  ASSERT(size()*sizeof(CT) < 0xffffffffUL - sizeof(SSSHDR));                  ASSERT(size()*sizeof(CT) < 0xffffffffUL - sizeof(SSSHDR));
2447                  HRESULT hr              = E_FAIL;                  HRESULT hr              = E_FAIL;
2448                  ASSERT(pStream != 0);                  ASSERT(pStream != 0);
2449                  SSSHDR hdr;                  SSSHDR hdr;
2450                  hdr.byCtrl              = sizeof(CT) == 2 ? SSSO_UNICODE : 0;                  hdr.byCtrl              = sizeof(CT) == 2 ? SSSO_UNICODE : 0;
2451                  hdr.nChars              = size();                  hdr.nChars              = size();
2452    
2453    
2454                  if ( FAILED(hr=pStream->Write(&hdr, sizeof(SSSHDR), 0)) )                  if ( FAILED(hr=pStream->Write(&hdr, sizeof(SSSHDR), 0)) )
2455                          TRACE(_T("StreamSave: Cannot write control header, ERR=0x%X\n"),hr);                          TRACE(_T("StreamSave: Cannot write control header, ERR=0x%X\n"),hr);
2456                  else if ( empty() )                  else if ( empty() )
2457                          ;               // nothing to write                          ;               // nothing to write
2458                  else if ( FAILED(hr=pStream->Write(c_str(), size()*sizeof(CT), 0)) )                  else if ( FAILED(hr=pStream->Write(c_str(), size()*sizeof(CT), 0)) )
2459                          TRACE(_T("StreamSave: Cannot write string to stream 0x%X\n"), hr);                          TRACE(_T("StreamSave: Cannot write string to stream 0x%X\n"), hr);
2460    
2461                  return hr;                  return hr;
2462          }          }
2463    
2464    
2465          // -------------------------------------------------------------------------          // -------------------------------------------------------------------------
2466          // FUNCTION: StreamLoad          // FUNCTION: StreamLoad
2467          // REMARKS:          // REMARKS:
2468          //              This method loads the object from an IStream.          //              This method loads the object from an IStream.
2469          // -------------------------------------------------------------------------          // -------------------------------------------------------------------------
2470          HRESULT StreamLoad(IStream* pStream)          HRESULT StreamLoad(IStream* pStream)
2471          {          {
2472                  ASSERT(pStream != 0);                  ASSERT(pStream != 0);
2473                  SSSHDR hdr;                  SSSHDR hdr;
2474                  HRESULT hr                      = E_FAIL;                  HRESULT hr                      = E_FAIL;
2475    
2476                  if ( FAILED(hr=pStream->Read(&hdr, sizeof(SSSHDR), 0)) )                  if ( FAILED(hr=pStream->Read(&hdr, sizeof(SSSHDR), 0)) )
2477                  {                  {
2478                          TRACE(_T("StreamLoad: Cant read control header, ERR=0x%X\n"), hr);                          TRACE(_T("StreamLoad: Cant read control header, ERR=0x%X\n"), hr);
2479                  }                  }
2480                  else if ( hdr.nChars > 0 )                  else if ( hdr.nChars > 0 )
2481                  {                  {
2482                          ULONG nRead             = 0;                          ULONG nRead             = 0;
2483                          PMYSTR pMyBuf   = BufferSet(hdr.nChars);                          PMYSTR pMyBuf   = BufferSet(hdr.nChars);
2484    
2485                          // If our character size matches the character size of the string                          // If our character size matches the character size of the string
2486                          // we're trying to read, then we can read it directly into our                          // we're trying to read, then we can read it directly into our
2487                          // buffer. Otherwise, we have to read into an intermediate buffer                          // buffer. Otherwise, we have to read into an intermediate buffer
2488                          // and convert.                          // and convert.
2489                                                    
2490                          if ( (hdr.byCtrl & SSSO_UNICODE) != 0 )                          if ( (hdr.byCtrl & SSSO_UNICODE) != 0 )
2491                          {                          {
2492                                  ULONG nBytes    = hdr.nChars * sizeof(wchar_t);                                  ULONG nBytes    = hdr.nChars * sizeof(wchar_t);
2493                                  if ( sizeof(CT) == sizeof(wchar_t) )                                  if ( sizeof(CT) == sizeof(wchar_t) )
2494                                  {                                  {
2495                                          if ( FAILED(hr=pStream->Read(pMyBuf, nBytes, &nRead)) )                                          if ( FAILED(hr=pStream->Read(pMyBuf, nBytes, &nRead)) )
2496                                                  TRACE(_T("StreamLoad: Cannot read string: 0x%X\n"), hr);                                                  TRACE(_T("StreamLoad: Cannot read string: 0x%X\n"), hr);
2497                                  }                                  }
2498                                  else                                  else
2499                                  {                                        {      
2500                                          PWSTR pBufW = reinterpret_cast<PWSTR>(_alloca((nBytes)+1));                                          PWSTR pBufW = reinterpret_cast<PWSTR>(_alloca((nBytes)+1));
2501                                          if ( FAILED(hr=pStream->Read(pBufW, nBytes, &nRead)) )                                          if ( FAILED(hr=pStream->Read(pBufW, nBytes, &nRead)) )
2502                                                  TRACE(_T("StreamLoad: Cannot read string: 0x%X\n"), hr);                                                  TRACE(_T("StreamLoad: Cannot read string: 0x%X\n"), hr);
2503                                          else                                          else
2504                                                  sscpy(pMyBuf, pBufW, hdr.nChars);                                                  sscpy(pMyBuf, pBufW, hdr.nChars);
2505                                  }                                  }
2506                          }                          }
2507                          else                          else
2508                          {                          {
2509                                  ULONG nBytes    = hdr.nChars * sizeof(char);                                  ULONG nBytes    = hdr.nChars * sizeof(char);
2510                                  if ( sizeof(CT) == sizeof(char) )                                  if ( sizeof(CT) == sizeof(char) )
2511                                  {                                  {
2512                                          if ( FAILED(hr=pStream->Read(pMyBuf, nBytes, &nRead)) )                                          if ( FAILED(hr=pStream->Read(pMyBuf, nBytes, &nRead)) )
2513                                                  TRACE(_T("StreamLoad: Cannot read string: 0x%X\n"), hr);                                                  TRACE(_T("StreamLoad: Cannot read string: 0x%X\n"), hr);
2514                                  }                                  }
2515                                  else                                  else
2516                                  {                                  {
2517                                          PSTR pBufA = reinterpret_cast<PSTR>(_alloca(nBytes));                                          PSTR pBufA = reinterpret_cast<PSTR>(_alloca(nBytes));
2518                                          if ( FAILED(hr=pStream->Read(pBufA, hdr.nChars, &nRead)) )                                          if ( FAILED(hr=pStream->Read(pBufA, hdr.nChars, &nRead)) )
2519                                                  TRACE(_T("StreamLoad: Cannot read string: 0x%X\n"), hr);                                                  TRACE(_T("StreamLoad: Cannot read string: 0x%X\n"), hr);
2520                                          else                                          else
2521                                                  sscpy(pMyBuf, pBufA, hdr.nChars);                                                  sscpy(pMyBuf, pBufA, hdr.nChars);
2522                                  }                                  }
2523                          }                          }
2524                  }                  }
2525                  else                  else
2526                  {                  {
2527                          this->erase();                          this->erase();
2528                  }                  }
2529                  return hr;                  return hr;
2530          }          }
2531  #endif // #ifdef SS_INC_COMDEF  #endif // #ifdef SS_INC_COMDEF
2532    
2533  #ifndef SS_ANSI  #ifndef SS_ANSI
2534    
2535          // SetResourceHandle/GetResourceHandle.  In MFC builds, these map directly          // SetResourceHandle/GetResourceHandle.  In MFC builds, these map directly
2536          // to AfxSetResourceHandle and AfxGetResourceHandle.  In non-MFC builds they          // to AfxSetResourceHandle and AfxGetResourceHandle.  In non-MFC builds they
2537          // point to a single static HINST so that those who call the member          // point to a single static HINST so that those who call the member
2538          // functions that take resource IDs can provide an alternate HINST of a DLL          // functions that take resource IDs can provide an alternate HINST of a DLL
2539          // to search.  This is not exactly the list of HMODULES that MFC provides          // to search.  This is not exactly the list of HMODULES that MFC provides
2540          // but it's better than nothing.          // but it's better than nothing.
2541    
2542          #ifdef _MFC_VER          #ifdef _MFC_VER
2543                  static void SetResourceHandle(HMODULE hNew)                  static void SetResourceHandle(HMODULE hNew)
2544                  {                  {
2545                          AfxSetResourceHandle(hNew);                          AfxSetResourceHandle(hNew);
2546                  }                  }
2547                  static HMODULE GetResourceHandle()                  static HMODULE GetResourceHandle()
2548                  {                  {
2549                          return AfxGetResourceHandle();                          return AfxGetResourceHandle();
2550                  }                  }
2551          #else          #else
2552                  static void SetResourceHandle(HMODULE hNew)                  static void SetResourceHandle(HMODULE hNew)
2553                  {                  {
2554                          SSResourceHandle() = hNew;                          SSResourceHandle() = hNew;
2555                  }                  }
2556                  static HMODULE GetResourceHandle()                  static HMODULE GetResourceHandle()
2557                  {                  {
2558                          return SSResourceHandle();                          return SSResourceHandle();
2559                  }                  }
2560          #endif          #endif
2561    
2562  #endif  #endif
2563  };  };
2564    
2565    
2566    
2567  // -----------------------------------------------------------------------------  // -----------------------------------------------------------------------------
2568  // CStdStr friend addition functions defined as inline  // CStdStr friend addition functions defined as inline
2569  // -----------------------------------------------------------------------------  // -----------------------------------------------------------------------------
2570  template<typename CT>  template<typename CT>
2571  inline  inline
2572  CStdStr<CT> operator+(const  CStdStr<CT>& str1, const  CStdStr<CT>& str2)  CStdStr<CT> operator+(const  CStdStr<CT>& str1, const  CStdStr<CT>& str2)
2573  {  {
2574          CStdStr<CT> strRet(SSREF(str1));          CStdStr<CT> strRet(SSREF(str1));
2575          strRet.append(str2);          strRet.append(str2);
2576          return strRet;          return strRet;
2577  }  }
2578    
2579  template<typename CT>    template<typename CT>  
2580  inline  inline
2581  CStdStr<CT> operator+(const  CStdStr<CT>& str, CT t)  CStdStr<CT> operator+(const  CStdStr<CT>& str, CT t)
2582  {  {
2583          // this particular overload is needed for disabling reference counting          // this particular overload is needed for disabling reference counting
2584          // though it's only an issue from line 1 to line 2          // though it's only an issue from line 1 to line 2
2585    
2586          CStdStr<CT> strRet(SSREF(str)); // 1          CStdStr<CT> strRet(SSREF(str)); // 1
2587          strRet.append(1, t);                            // 2          strRet.append(1, t);                            // 2
2588          return strRet;          return strRet;
2589  }  }
2590    
2591  template<typename CT>  template<typename CT>
2592  inline  inline
2593  CStdStr<CT> operator+(const  CStdStr<CT>& str, PCSTR pA)  CStdStr<CT> operator+(const  CStdStr<CT>& str, PCSTR pA)
2594  {  {
2595          return CStdStr<CT>(str) + CStdStr<CT>(pA);          return CStdStr<CT>(str) + CStdStr<CT>(pA);
2596  }  }
2597    
2598  template<typename CT>  template<typename CT>
2599  inline  inline
2600  CStdStr<CT> operator+(PCSTR pA, const  CStdStr<CT>& str)  CStdStr<CT> operator+(PCSTR pA, const  CStdStr<CT>& str)
2601  {  {
2602          CStdStr<CT> strRet(pA);          CStdStr<CT> strRet(pA);
2603          strRet.append(str);          strRet.append(str);
2604          return strRet;          return strRet;
2605  }  }
2606    
2607  template<typename CT>  template<typename CT>
2608  inline  inline
2609  CStdStr<CT> operator+(const CStdStr<CT>& str, PCWSTR pW)  CStdStr<CT> operator+(const CStdStr<CT>& str, PCWSTR pW)
2610  {  {
2611          return CStdStr<CT>(SSREF(str)) + CStdStr<CT>(pW);          return CStdStr<CT>(SSREF(str)) + CStdStr<CT>(pW);
2612  }  }
2613    
2614  template<typename CT>  template<typename CT>
2615  inline  inline
2616  CStdStr<CT> operator+(PCWSTR pW, const CStdStr<CT>& str)  CStdStr<CT> operator+(PCWSTR pW, const CStdStr<CT>& str)
2617  {  {
2618          CStdStr<CT> strRet(pW);          CStdStr<CT> strRet(pW);
2619          strRet.append(str);          strRet.append(str);
2620          return strRet;          return strRet;
2621  }  }
2622    
2623  #ifdef SS_INC_COMDEF  #ifdef SS_INC_COMDEF
2624          template<typename CT>          template<typename CT>
2625          inline          inline
2626          CStdStr<CT> operator+(const _bstr_t& bstr, const CStdStr<CT>& str)          CStdStr<CT> operator+(const _bstr_t& bstr, const CStdStr<CT>& str)
2627          {          {
2628                  return static_cast<const CT*>(bstr) + str;                  return static_cast<const CT*>(bstr) + str;
2629          }          }
2630    
2631          template<typename CT>          template<typename CT>
2632          inline          inline
2633          CStdStr<CT> operator+(const CStdStr<CT>& str, const _bstr_t& bstr)          CStdStr<CT> operator+(const CStdStr<CT>& str, const _bstr_t& bstr)
2634          {          {
2635                  return str + static_cast<const CT*>(bstr);                  return str + static_cast<const CT*>(bstr);
2636          }          }
2637  #endif  #endif
2638    
2639    
2640    
2641    
2642  // -----------------------------------------------------------------------------  // -----------------------------------------------------------------------------
2643  // These versions of operator+ provided by Scott Hathaway in order to allow  // These versions of operator+ provided by Scott Hathaway in order to allow
2644  // CStdString to build on Sun Unix systems.  // CStdString to build on Sun Unix systems.
2645  // -----------------------------------------------------------------------------  // -----------------------------------------------------------------------------
2646    
2647  #if defined(__SUNPRO_CC_COMPAT) || defined(__SUNPRO_CC)  #if defined(__SUNPRO_CC_COMPAT) || defined(__SUNPRO_CC)
2648    
2649  // Made non-template versions due to "undefined" errors on Sun Forte compiler  // Made non-template versions due to "undefined" errors on Sun Forte compiler
2650  // when linking with friend template functions  // when linking with friend template functions
2651  inline  inline
2652  CStdStr<wchar_t> operator+(const CStdStr<wchar_t>& str1,  CStdStr<wchar_t> operator+(const CStdStr<wchar_t>& str1,
2653                                                     const CStdStr<wchar_t>& str2)                                                     const CStdStr<wchar_t>& str2)
2654  {  {
2655          CStdStr<wchar_t> strRet(SSREF(str1));          CStdStr<wchar_t> strRet(SSREF(str1));
2656          strRet.append(str2);          strRet.append(str2);
2657          return strRet;          return strRet;
2658  }  }
2659    
2660  inline  inline
2661  CStdStr<wchar_t> operator+(const CStdStr<wchar_t>& str, wchar_t t)  CStdStr<wchar_t> operator+(const CStdStr<wchar_t>& str, wchar_t t)
2662  {  {
2663          // this particular overload is needed for disabling reference counting          // this particular overload is needed for disabling reference counting
2664          // though it's only an issue from line 1 to line 2          // though it's only an issue from line 1 to line 2
2665    
2666          CStdStr<wchar_t> strRet(SSREF(str));    // 1          CStdStr<wchar_t> strRet(SSREF(str));    // 1
2667          strRet.append(1, t);                                    // 2          strRet.append(1, t);                                    // 2
2668          return strRet;          return strRet;
2669  }  }
2670    
2671  inline  inline
2672  CStdStr<wchar_t> operator+(const CStdStr<wchar_t>& str, PCWSTR pW)  CStdStr<wchar_t> operator+(const CStdStr<wchar_t>& str, PCWSTR pW)
2673  {  {
2674          return CStdStr<wchar_t>(str) + CStdStr<wchar_t>(pW);          return CStdStr<wchar_t>(str) + CStdStr<wchar_t>(pW);
2675  }  }
2676    
2677  inline  inline
2678  CStdStr<wchar_t> operator+(PCWSTR pA, const  CStdStr<wchar_t>& str)  CStdStr<wchar_t> operator+(PCWSTR pA, const  CStdStr<wchar_t>& str)
2679  {  {
2680          CStdStr<wchar_t> strRet(pA);          CStdStr<wchar_t> strRet(pA);
2681          strRet.append(str);          strRet.append(str);
2682          return strRet;          return strRet;
2683  }  }
2684    
2685  inline  inline
2686  CStdStr<wchar_t> operator+(const CStdStr<wchar_t>& str, PCSTR pW)  CStdStr<wchar_t> operator+(const CStdStr<wchar_t>& str, PCSTR pW)
2687  {  {
2688          return CStdStr<wchar_t>(SSREF(str)) + CStdStr<wchar_t>(pW);          return CStdStr<wchar_t>(SSREF(str)) + CStdStr<wchar_t>(pW);
2689  }  }
2690    
2691  inline  inline
2692  CStdStr<wchar_t> operator+(PCSTR pW, const CStdStr<wchar_t>& str)  CStdStr<wchar_t> operator+(PCSTR pW, const CStdStr<wchar_t>& str)
2693  {  {
2694          CStdStr<wchar_t> strRet(pW);          CStdStr<wchar_t> strRet(pW);
2695          strRet.append(str);          strRet.append(str);
2696          return strRet;          return strRet;
2697  }  }
2698    
2699  inline  inline
2700  CStdStr<char> operator+(const  CStdStr<char>& str1, const  CStdStr<char>& str2)  CStdStr<char> operator+(const  CStdStr<char>& str1, const  CStdStr<char>& str2)
2701  {  {
2702          CStdStr<char> strRet(SSREF(str1));          CStdStr<char> strRet(SSREF(str1));
2703          strRet.append(str2);          strRet.append(str2);
2704          return strRet;          return strRet;
2705  }  }
2706    
2707  inline  inline
2708  CStdStr<char> operator+(const  CStdStr<char>& str, char t)  CStdStr<char> operator+(const  CStdStr<char>& str, char t)
2709  {  {
2710          // this particular overload is needed for disabling reference counting          // this particular overload is needed for disabling reference counting
2711          // though it's only an issue from line 1 to line 2          // though it's only an issue from line 1 to line 2
2712    
2713          CStdStr<char> strRet(SSREF(str));       // 1          CStdStr<char> strRet(SSREF(str));       // 1
2714          strRet.append(1, t);                            // 2          strRet.append(1, t);                            // 2
2715          return strRet;          return strRet;
2716  }  }
2717    
2718  inline  inline
2719  CStdStr<char> operator+(const  CStdStr<char>& str, PCSTR pA)  CStdStr<char> operator+(const  CStdStr<char>& str, PCSTR pA)
2720  {  {
2721          return CStdStr<char>(str) + CStdStr<char>(pA);          return CStdStr<char>(str) + CStdStr<char>(pA);
2722  }  }
2723    
2724  inline  inline
2725  CStdStr<char> operator+(PCSTR pA, const  CStdStr<char>& str)  CStdStr<char> operator+(PCSTR pA, const  CStdStr<char>& str)
2726  {  {
2727          CStdStr<char> strRet(pA);          CStdStr<char> strRet(pA);
2728          strRet.append(str);          strRet.append(str);
2729          return strRet;          return strRet;
2730  }  }
2731    
2732  inline  inline
2733  CStdStr<char> operator+(const CStdStr<char>& str, PCWSTR pW)  CStdStr<char> operator+(const CStdStr<char>& str, PCWSTR pW)
2734  {  {
2735          return CStdStr<char>(SSREF(str)) + CStdStr<char>(pW);          return CStdStr<char>(SSREF(str)) + CStdStr<char>(pW);
2736  }  }
2737    
2738  inline  inline
2739  CStdStr<char> operator+(PCWSTR pW, const CStdStr<char>& str)  CStdStr<char> operator+(PCWSTR pW, const CStdStr<char>& str)
2740  {  {
2741          CStdStr<char> strRet(pW);          CStdStr<char> strRet(pW);
2742          strRet.append(str);          strRet.append(str);
2743          return strRet;          return strRet;
2744  }  }
2745    
2746    
2747  #endif // defined(__SUNPRO_CC_COMPAT) || defined(__SUNPRO_CC)  #endif // defined(__SUNPRO_CC_COMPAT) || defined(__SUNPRO_CC)
2748    
2749    
2750  // =============================================================================  // =============================================================================
2751  //                                              END OF CStdStr INLINE FUNCTION DEFINITIONS  //                                              END OF CStdStr INLINE FUNCTION DEFINITIONS
2752  // =============================================================================  // =============================================================================
2753    
2754  //      Now typedef our class names based upon this humongous template  //      Now typedef our class names based upon this humongous template
2755    
2756  typedef CStdStr<char>           CStdStringA;    // a better std::string  typedef CStdStr<char>           CStdStringA;    // a better std::string
2757  typedef CStdStr<wchar_t>        CStdStringW;    // a better std::wstring  typedef CStdStr<wchar_t>        CStdStringW;    // a better std::wstring
2758  typedef CStdStr<OLECHAR>        CStdStringO;    // almost always CStdStringW  typedef CStdStr<OLECHAR>        CStdStringO;    // almost always CStdStringW
2759    
2760  #ifndef SS_ANSI  #ifndef SS_ANSI
2761          // SSResourceHandle: our MFC-like resource handle          // SSResourceHandle: our MFC-like resource handle
2762          inline HMODULE& SSResourceHandle()          inline HMODULE& SSResourceHandle()
2763          {          {
2764                  static HMODULE hModuleSS        = GetModuleHandle(0);                  static HMODULE hModuleSS        = GetModuleHandle(0);
2765                  return hModuleSS;                  return hModuleSS;
2766          }          }
2767  #endif  #endif
2768    
2769    
2770  // In MFC builds, define some global serialization operators  // In MFC builds, define some global serialization operators
2771  // Special operators that allow us to serialize CStdStrings to CArchives.  // Special operators that allow us to serialize CStdStrings to CArchives.
2772  // Note that we use an intermediate CString object in order to ensure that  // Note that we use an intermediate CString object in order to ensure that
2773  // we use the exact same format.  // we use the exact same format.
2774    
2775  #ifdef _MFC_VER  #ifdef _MFC_VER
2776          inline CArchive& AFXAPI operator<<(CArchive& ar, const CStdStringA& strA)          inline CArchive& AFXAPI operator<<(CArchive& ar, const CStdStringA& strA)
2777          {          {
2778                  CString strTemp = strA;                  CString strTemp = strA;
2779                  return ar << strTemp;                  return ar << strTemp;
2780          }          }
2781          inline CArchive& AFXAPI operator<<(CArchive& ar, const CStdStringW& strW)          inline CArchive& AFXAPI operator<<(CArchive& ar, const CStdStringW& strW)
2782          {          {
2783                  CString strTemp = strW;                  CString strTemp = strW;
2784                  return ar << strTemp;                  return ar << strTemp;
2785          }          }
2786    
2787          inline CArchive& AFXAPI operator>>(CArchive& ar, CStdStringA& strA)          inline CArchive& AFXAPI operator>>(CArchive& ar, CStdStringA& strA)
2788          {          {
2789                  CString strTemp;                  CString strTemp;
2790                  ar >> strTemp;                  ar >> strTemp;
2791                  strA = strTemp;                  strA = strTemp;
2792                  return ar;                  return ar;
2793          }          }
2794          inline CArchive& AFXAPI operator>>(CArchive& ar, CStdStringW& strW)          inline CArchive& AFXAPI operator>>(CArchive& ar, CStdStringW& strW)
2795          {          {
2796                  CString strTemp;                  CString strTemp;
2797                  ar >> strTemp;                  ar >> strTemp;
2798                  strW = strTemp;                  strW = strTemp;
2799                  return ar;                  return ar;
2800          }          }
2801  #endif  // #ifdef _MFC_VER -- (i.e. is this MFC?)  #endif  // #ifdef _MFC_VER -- (i.e. is this MFC?)
2802    
2803    
2804    
2805  // -----------------------------------------------------------------------------  // -----------------------------------------------------------------------------
2806  // HOW TO EXPORT CSTDSTRING FROM A DLL  // HOW TO EXPORT CSTDSTRING FROM A DLL
2807  //  //
2808  // If you want to export CStdStringA and CStdStringW from a DLL, then all you  // If you want to export CStdStringA and CStdStringW from a DLL, then all you
2809  // need to  // need to
2810  //              1.      make sure that all components link to the same DLL version  //              1.      make sure that all components link to the same DLL version
2811  //                      of the CRT (not the static one).  //                      of the CRT (not the static one).
2812  //              2.      Uncomment the 3 lines of code below  //              2.      Uncomment the 3 lines of code below
2813  //              3.      #define 2 macros per the instructions in MS KnowledgeBase  //              3.      #define 2 macros per the instructions in MS KnowledgeBase
2814  //                      article Q168958.  The macros are:  //                      article Q168958.  The macros are:
2815  //  //
2816  //              MACRO           DEFINTION WHEN EXPORTING                DEFINITION WHEN IMPORTING  //              MACRO           DEFINTION WHEN EXPORTING                DEFINITION WHEN IMPORTING
2817  //              -----           ------------------------                -------------------------  //              -----           ------------------------                -------------------------
2818  //              SSDLLEXP        (nothing, just #define it)              extern  //              SSDLLEXP        (nothing, just #define it)              extern
2819  //              SSDLLSPEC       __declspec(dllexport)                   __declspec(dllimport)  //              SSDLLSPEC       __declspec(dllexport)                   __declspec(dllimport)
2820  //  //
2821  //              Note that these macros must be available to ALL clients who want to  //              Note that these macros must be available to ALL clients who want to
2822  //              link to the DLL and use the class.  If they  //              link to the DLL and use the class.  If they
2823  // -----------------------------------------------------------------------------  // -----------------------------------------------------------------------------
2824  //#pragma warning(disable:4231) // non-standard extension ("extern template")  //#pragma warning(disable:4231) // non-standard extension ("extern template")
2825  //      SSDLLEXP template class SSDLLSPEC CStdStr<char>;  //      SSDLLEXP template class SSDLLSPEC CStdStr<char>;
2826  //      SSDLLEXP template class SSDLLSPEC CStdStr<wchar_t>;  //      SSDLLEXP template class SSDLLSPEC CStdStr<wchar_t>;
2827    
2828    
2829  // -----------------------------------------------------------------------------  // -----------------------------------------------------------------------------
2830  // GLOBAL FUNCTION:  WUFormat  // GLOBAL FUNCTION:  WUFormat
2831  //              CStdStringA WUFormat(UINT nId, ...);  //              CStdStringA WUFormat(UINT nId, ...);
2832  //              CStdStringA WUFormat(PCSTR szFormat, ...);  //              CStdStringA WUFormat(PCSTR szFormat, ...);
2833  //  //
2834  // REMARKS:  // REMARKS:
2835  //              This function allows the caller for format and return a CStdStringA  //              This function allows the caller for format and return a CStdStringA
2836  //              object with a single line of code.  //              object with a single line of code.
2837  // -----------------------------------------------------------------------------  // -----------------------------------------------------------------------------
2838  #ifdef SS_ANSI  #ifdef SS_ANSI
2839  #else  #else
2840          inline CStdStringA WUFormatA(UINT nId, ...)          inline CStdStringA WUFormatA(UINT nId, ...)
2841          {          {
2842                  va_list argList;                  va_list argList;
2843                  va_start(argList, nId);                  va_start(argList, nId);
2844    
2845                  CStdStringA strFmt;                  CStdStringA strFmt;
2846                  CStdStringA strOut;                  CStdStringA strOut;
2847                  if ( strFmt.Load(nId) )                  if ( strFmt.Load(nId) )
2848                          strOut.FormatV(strFmt, argList);                          strOut.FormatV(strFmt, argList);
2849    
2850                  va_end(argList);                  va_end(argList);
2851                  return strOut;                  return strOut;
2852          }          }
2853          inline CStdStringA WUFormatA(PCSTR szFormat, ...)          inline CStdStringA WUFormatA(PCSTR szFormat, ...)
2854          {          {
2855                  va_list argList;                  va_list argList;
2856                  va_start(argList, szFormat);                  va_start(argList, szFormat);
2857                  CStdStringA strOut;                  CStdStringA strOut;
2858                  strOut.FormatV(szFormat, argList);                  strOut.FormatV(szFormat, argList);
2859                  va_end(argList);                  va_end(argList);
2860                  return strOut;                  return strOut;
2861          }          }
2862    
2863          inline CStdStringW WUFormatW(UINT nId, ...)          inline CStdStringW WUFormatW(UINT nId, ...)
2864          {          {
2865                  va_list argList;                  va_list argList;
2866                  va_start(argList, nId);                  va_start(argList, nId);
2867    
2868                  CStdStringW strFmt;                  CStdStringW strFmt;
2869                  CStdStringW strOut;                  CStdStringW strOut;
2870                  if ( strFmt.Load(nId) )                  if ( strFmt.Load(nId) )
2871                          strOut.FormatV(strFmt, argList);                          strOut.FormatV(strFmt, argList);
2872    
2873                  va_end(argList);                  va_end(argList);
2874                  return strOut;                  return strOut;
2875          }          }
2876          inline CStdStringW WUFormatW(PCWSTR szwFormat, ...)          inline CStdStringW WUFormatW(PCWSTR szwFormat, ...)
2877          {          {
2878                  va_list argList;                  va_list argList;
2879                  va_start(argList, szwFormat);                  va_start(argList, szwFormat);
2880                  CStdStringW strOut;                  CStdStringW strOut;
2881                  strOut.FormatV(szwFormat, argList);                  strOut.FormatV(szwFormat, argList);
2882                  va_end(argList);                  va_end(argList);
2883                  return strOut;                  return strOut;
2884          }          }
2885  #endif // #ifdef SS_ANSI  #endif // #ifdef SS_ANSI
2886    
2887  #ifdef SS_ANSI  #ifdef SS_ANSI
2888  #else  #else
2889          // -------------------------------------------------------------------------          // -------------------------------------------------------------------------
2890          // FUNCTION: WUSysMessage          // FUNCTION: WUSysMessage
2891          //       CStdStringA WUSysMessageA(DWORD dwError, DWORD dwLangId=SS_DEFLANGID);          //       CStdStringA WUSysMessageA(DWORD dwError, DWORD dwLangId=SS_DEFLANGID);
2892          //       CStdStringW WUSysMessageW(DWORD dwError, DWORD dwLangId=SS_DEFLANGID);          //       CStdStringW WUSysMessageW(DWORD dwError, DWORD dwLangId=SS_DEFLANGID);
2893          //                    //          
2894          // DESCRIPTION:          // DESCRIPTION:
2895          //       This function simplifies the process of obtaining a string equivalent          //       This function simplifies the process of obtaining a string equivalent
2896          //       of a system error code returned from GetLastError().  You simply          //       of a system error code returned from GetLastError().  You simply
2897          //       supply the value returned by GetLastError() to this function and the          //       supply the value returned by GetLastError() to this function and the
2898          //       corresponding system string is returned in the form of a CStdStringA.          //       corresponding system string is returned in the form of a CStdStringA.
2899          //          //
2900          // PARAMETERS:          // PARAMETERS:
2901          //       dwError - a DWORD value representing the error code to be translated          //       dwError - a DWORD value representing the error code to be translated
2902          //       dwLangId - the language id to use.  defaults to english.          //       dwLangId - the language id to use.  defaults to english.
2903          //          //
2904          // RETURN VALUE:          // RETURN VALUE:
2905          //       a CStdStringA equivalent of the error code.  Currently, this function          //       a CStdStringA equivalent of the error code.  Currently, this function
2906          //       only returns either English of the system default language strings.            //       only returns either English of the system default language strings.  
2907          // -------------------------------------------------------------------------          // -------------------------------------------------------------------------
2908          #define SS_DEFLANGID MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT)          #define SS_DEFLANGID MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT)
2909          inline CStdStringA WUSysMessageA(DWORD dwError, DWORD dwLangId=SS_DEFLANGID)          inline CStdStringA WUSysMessageA(DWORD dwError, DWORD dwLangId=SS_DEFLANGID)
2910          {          {
2911                  CHAR szBuf[512];                  CHAR szBuf[512];
2912    
2913                  if ( 0 != ::FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError,                  if ( 0 != ::FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError,
2914                                                                     dwLangId, szBuf, 511, NULL) )                                                                     dwLangId, szBuf, 511, NULL) )
2915                          return WUFormatA("%s (0x%X)", szBuf, dwError);                          return WUFormatA("%s (0x%X)", szBuf, dwError);
2916                  else                  else
2917                          return WUFormatA("Unknown error (0x%X)", dwError);                          return WUFormatA("Unknown error (0x%X)", dwError);
2918          }          }
2919          inline CStdStringW WUSysMessageW(DWORD dwError, DWORD dwLangId=SS_DEFLANGID)          inline CStdStringW WUSysMessageW(DWORD dwError, DWORD dwLangId=SS_DEFLANGID)
2920          {          {
2921                  WCHAR szBuf[512];                  WCHAR szBuf[512];
2922    
2923                  if ( 0 != ::FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError,                  if ( 0 != ::FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError,
2924                                                                     dwLangId, szBuf, 511, NULL) )                                                                     dwLangId, szBuf, 511, NULL) )
2925                          return WUFormatW(L"%s (0x%X)", szBuf, dwError);                          return WUFormatW(L"%s (0x%X)", szBuf, dwError);
2926                  else                  else
2927                          return WUFormatW(L"Unknown error (0x%X)", dwError);                          return WUFormatW(L"Unknown error (0x%X)", dwError);
2928          }          }
2929  #endif  #endif
2930    
2931  // Define TCHAR based friendly names for some of these functions  // Define TCHAR based friendly names for some of these functions
2932    
2933  #ifdef UNICODE  #ifdef UNICODE
2934          #define CStdString                              CStdStringW          #define CStdString                              CStdStringW
2935          #define WUSysMessage                    WUSysMessageW          #define WUSysMessage                    WUSysMessageW
2936          #define WUFormat                                WUFormatW          #define WUFormat                                WUFormatW
2937  #else  #else
2938          #define CStdString                              CStdStringA          #define CStdString                              CStdStringA
2939          #define WUSysMessage                    WUSysMessageA          #define WUSysMessage                    WUSysMessageA
2940          #define WUFormat                                WUFormatA          #define WUFormat                                WUFormatA
2941  #endif  #endif
2942    
2943  // ...and some shorter names for the space-efficient  // ...and some shorter names for the space-efficient
2944    
2945  #define WUSysMsg                                        WUSysMessage  #define WUSysMsg                                        WUSysMessage
2946  #define WUSysMsgA                                       WUSysMessageA  #define WUSysMsgA                                       WUSysMessageA
2947  #define WUSysMsgW                                       WUSysMessageW  #define WUSysMsgW                                       WUSysMessageW
2948  #define WUFmtA                                          WUFormatA  #define WUFmtA                                          WUFormatA
2949  #define WUFmtW                                          WUFormatW  #define WUFmtW                                          WUFormatW
2950  #define WUFmt                                           WUFormat  #define WUFmt                                           WUFormat
2951  #define WULastErrMsg()                          WUSysMessage(::GetLastError())  #define WULastErrMsg()                          WUSysMessage(::GetLastError())
2952  #define WULastErrMsgA()                         WUSysMessageA(::GetLastError())  #define WULastErrMsgA()                         WUSysMessageA(::GetLastError())
2953  #define WULastErrMsgW()                         WUSysMessageW(::GetLastError())  #define WULastErrMsgW()                         WUSysMessageW(::GetLastError())
2954    
2955    
2956  // -----------------------------------------------------------------------------  // -----------------------------------------------------------------------------
2957  // FUNCTIONAL COMPARATORS:  // FUNCTIONAL COMPARATORS:
2958  // REMARKS:  // REMARKS:
2959  //              These structs are derived from the std::binary_function template.  They  //              These structs are derived from the std::binary_function template.  They
2960  //              give us functional classes (which may be used in Standard C++ Library  //              give us functional classes (which may be used in Standard C++ Library
2961  //              collections and algorithms) that perform case-insensitive comparisons of  //              collections and algorithms) that perform case-insensitive comparisons of
2962  //              CStdString objects.  This is useful for maps in which the key may be the  //              CStdString objects.  This is useful for maps in which the key may be the
2963  //               proper string but in the wrong case.  //               proper string but in the wrong case.
2964  // -----------------------------------------------------------------------------  // -----------------------------------------------------------------------------
2965  #define StdStringLessNoCaseW            SSLNCW  // avoid VC compiler warning 4786  #define StdStringLessNoCaseW            SSLNCW  // avoid VC compiler warning 4786
2966  #define StdStringEqualsNoCaseW          SSENCW            #define StdStringEqualsNoCaseW          SSENCW          
2967  #define StdStringLessNoCaseA            SSLNCA            #define StdStringLessNoCaseA            SSLNCA          
2968  #define StdStringEqualsNoCaseA          SSENCA            #define StdStringEqualsNoCaseA          SSENCA          
2969    
2970  #ifdef UNICODE  #ifdef UNICODE
2971          #define StdStringLessNoCase             SSLNCW                    #define StdStringLessNoCase             SSLNCW          
2972          #define StdStringEqualsNoCase   SSENCW                    #define StdStringEqualsNoCase   SSENCW          
2973  #else  #else
2974          #define StdStringLessNoCase             SSLNCA                    #define StdStringLessNoCase             SSLNCA          
2975          #define StdStringEqualsNoCase   SSENCA                    #define StdStringEqualsNoCase   SSENCA          
2976  #endif  #endif
2977    
2978  struct StdStringLessNoCaseW  struct StdStringLessNoCaseW
2979          : std::binary_function<CStdStringW, CStdStringW, bool>          : std::binary_function<CStdStringW, CStdStringW, bool>
2980  {  {
2981          inline          inline
2982          bool operator()(const CStdStringW& sLeft, const CStdStringW& sRight) const          bool operator()(const CStdStringW& sLeft, const CStdStringW& sRight) const
2983          { return ssicmp(sLeft.c_str(), sRight.c_str()) < 0; }          { return ssicmp(sLeft.c_str(), sRight.c_str()) < 0; }
2984  };  };
2985  struct StdStringEqualsNoCaseW  struct StdStringEqualsNoCaseW
2986          : std::binary_function<CStdStringW, CStdStringW, bool>          : std::binary_function<CStdStringW, CStdStringW, bool>
2987  {  {
2988          inline          inline
2989          bool operator()(const CStdStringW& sLeft, const CStdStringW& sRight) const          bool operator()(const CStdStringW& sLeft, const CStdStringW& sRight) const
2990          { return ssicmp(sLeft.c_str(), sRight.c_str()) == 0; }          { return ssicmp(sLeft.c_str(), sRight.c_str()) == 0; }
2991  };  };
2992  struct StdStringLessNoCaseA  struct StdStringLessNoCaseA
2993          : std::binary_function<CStdStringA, CStdStringA, bool>          : std::binary_function<CStdStringA, CStdStringA, bool>
2994  {  {
2995          inline          inline
2996          bool operator()(const CStdStringA& sLeft, const CStdStringA& sRight) const          bool operator()(const CStdStringA& sLeft, const CStdStringA& sRight) const
2997          { return ssicmp(sLeft.c_str(), sRight.c_str()) < 0; }          { return ssicmp(sLeft.c_str(), sRight.c_str()) < 0; }
2998  };  };
2999  struct StdStringEqualsNoCaseA  struct StdStringEqualsNoCaseA
3000          : std::binary_function<CStdStringA, CStdStringA, bool>          : std::binary_function<CStdStringA, CStdStringA, bool>
3001  {  {
3002          inline          inline
3003          bool operator()(const CStdStringA& sLeft, const CStdStringA& sRight) const          bool operator()(const CStdStringA& sLeft, const CStdStringA& sRight) const
3004          { return ssicmp(sLeft.c_str(), sRight.c_str()) == 0; }          { return ssicmp(sLeft.c_str(), sRight.c_str()) == 0; }
3005  };  };
3006    
3007  // If we had to define our own version of TRACE above, get rid of it now  // If we had to define our own version of TRACE above, get rid of it now
3008    
3009  #ifdef TRACE_DEFINED_HERE  #ifdef TRACE_DEFINED_HERE
3010          #undef TRACE          #undef TRACE
3011          #undef TRACE_DEFINED_HERE          #undef TRACE_DEFINED_HERE
3012  #endif  #endif
3013    
3014    
3015  #endif  // #ifndef STDSTRING_H  #endif  // #ifndef STDSTRING_H

Legend:
Removed from v.929  
changed lines
  Added in v.930

  ViewVC Help
Powered by ViewVC 1.1.26