/[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 930 by astrand, Thu Jun 30 14:14:56 2005 UTC revision 992 by astrand, Sun Aug 28 12:56:38 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    //
5    //              If you find any bugs in this code, please let me know:
6    //
7    //                              jmoleary@earthlink.net
8    //                              http://www.joeo.net/stdstring.htm (a bit outdated)
9    //
10    //      The latest version of this code should always be available at the
11    //      following link:
12    //
13    //              http://www.joeo.net/code/StdString.zip (Dec 6, 2003)
14    //
15    //
16  //  REMARKS:  //  REMARKS:
17  //              This header file declares the CStdStr template.  This template derives  //              This header file declares the CStdStr template.  This template derives
18  //              the Standard C++ Library basic_string<> template and add to it the  //              the Standard C++ Library basic_string<> template and add to it the
19  //              the following conveniences:  //              the following conveniences:
20  //                      - The full MFC CString set of functions (including implicit cast)  //                      - The full MFC CString set of functions (including implicit cast)
21  //                      - writing to/reading from COM IStream interfaces  //                      - writing to/reading from COM IStream interfaces
22  //                      - Functional objects for use in STL algorithms  //                      - Functional objects for use in STL algorithms
23  //  //
24  //              From this template, we intstantiate two classes:  CStdStringA and  //              From this template, we intstantiate two classes:  CStdStringA and
25  //              CStdStringW.  The name "CStdString" is just a #define of one of these,  //              CStdStringW.  The name "CStdString" is just a #define of one of these,
26  //              based upone the _UNICODE macro setting  //              based upone the UNICODE macro setting
27  //  //
28  //              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
29  //              conversion macros.  Our version looks exactly like the Microsoft's to  //              conversion macros.  Our version looks exactly like the Microsoft's to
30  //              facilitate portability.  //              facilitate portability.
31  //  //
32  //      NOTE:  //      NOTE:
33  //              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
34  //              afx.h or atlbase.h first, as appropriate.  //              afx.h or atlbase.h first, as appropriate.
35  //  //
36  //      PEOPLE WHO HAVE CONTRIBUTED TO THIS CLASS:  //      PEOPLE WHO HAVE CONTRIBUTED TO THIS CLASS:
37  //  //
38  //              Several people have helped me iron out problems and othewise improve  //              Several people have helped me iron out problems and othewise improve
39  //              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
40  //              has undergone two major rewrites.  Many of the improvements became  //              has undergone two major rewrites.  Many of the improvements became
41  //              necessary after I rewrote the code as a template.  Others helped me  //              necessary after I rewrote the code as a template.  Others helped me
42  //              improve the CString facade.  //              improve the CString facade.
43  //  //
44  //              Anyway, these people are (in chronological order):  //              Anyway, these people are (in chronological order):
45  //  //
46  //                      - Pete the Plumber (???)  //                      - Pete the Plumber (???)
47  //                      - Julian Selman  //                      - Julian Selman
48  //                      - Chris (of Melbsys)  //                      - Chris (of Melbsys)
49  //                      - Dave Plummer  //                      - Dave Plummer
50  //                      - John C Sipos  //                      - John C Sipos
51  //                      - Chris Sells  //                      - Chris Sells
52  //                      - Nigel Nunn  //                      - Nigel Nunn
53  //                      - Fan Xia  //                      - Fan Xia
54  //                      - Matthew Williams  //                      - Matthew Williams
55  //                      - Carl Engman  //                      - Carl Engman
56  //                      - Mark Zeren  //                      - Mark Zeren
57  //                      - Craig Watson  //                      - Craig Watson
58  //                      - Rich Zuris  //                      - Rich Zuris
59  //                      - Karim Ratib  //                      - Karim Ratib
60  //                      - Chris Conti  //                      - Chris Conti
61  //                      - Baptiste Lepilleur  //                      - Baptiste Lepilleur
62  //                      - Greg Pickles  //                      - Greg Pickles
63  //                      - Jim Cline  //                      - Jim Cline
64  //                      - Jeff Kohn  //                      - Jeff Kohn
65  //                      - Todd Heckel  //                      - Todd Heckel
66  //                      - Ullrich Pollähne  //                      - Ullrich Pollähne
67  //                      - Joe Vitaterna  //                      - Joe Vitaterna
68  //                      - Joe Woodbury  //                      - Joe Woodbury
69  //                      - Aaron (no last name)  //                      - Aaron (no last name)
70  //                      - Joldakowski (???)  //                      - Joldakowski (???)
71  //                      - Scott Hathaway  //                      - Scott Hathaway
72  //                      - Eric Nitzche  //                      - Eric Nitzche
73  //                      - Pablo Presedo  //                      - Pablo Presedo
74  //  //                      - Farrokh Nejadlotfi
75  //      REVISION HISTORY  //                      - Jason Mills
76  //        2001-APR-27 - StreamLoad was calculating the number of BYTES in one  //                      - Igor Kholodov
77  //                                      case, not characters.  Thanks to Pablo Presedo for this.  //                      - Mike Crusader
78    //                      - John James
79    //                      - Wang Haifeng
80    //                      - Tim Dowty
81    //          - Arnt Witteveen
82    //          - Glen Maynard
83    //          - Paul DeMarco
84    //          - Bagira (full name?)
85    //          - Ronny Schulz
86    //          - Jakko Van Hunen
87    //                      - Charles Godwin
88    //                      - Henk Demper
89    //                      - Greg Marr
90    //                      - Bill Carducci
91    //                      - Brian Groose
92    //                      - MKingman
93    //                      - Don Beusee
94    //
95    //      REVISION HISTORY
96    //
97    //        2005-JAN-10 - Thanks to Don Beusee for pointing out the danger in mapping
98    //                                      length-checked formatting functions to non-length-checked
99    //                                      CRT equivalents.  Also thanks to him for motivating me to
100    //                                      optimize my implementation of Replace()
101    //
102    //        2004-APR-22 - A big, big thank you to "MKingman" (whoever you are) for
103    //                                      finally spotting a silly little error in StdCodeCvt that
104    //                                      has been causing me (and users of CStdString) problems for
105    //                                      years in some relatively rare conversions.  I had reversed
106    //                                      two length arguments.
107    //
108    //    2003-NOV-24 - Thanks to a bunch of people for helping me clean up many
109    //                                      compiler warnings (and yes, even a couple of actual compiler
110    //                                      errors).  These include Henk Demper for figuring out how
111    //                                      to make the Intellisense work on with CStdString on VC6,
112    //                                      something I was never able to do.  Greg Marr pointed out
113    //                                      a compiler warning about an unreferenced symbol and a
114    //                                      problem with my version of Load in MFC builds.  Bill
115    //                                      Carducci took a lot of time with me to help me figure out
116    //                                      why some implementations of the Standard C++ Library were
117    //                                      returning error codes for apparently successful conversions
118    //                                      between ASCII and UNICODE.  Finally thanks to Brian Groose
119    //                                      for helping me fix compiler signed unsigned warnings in
120    //                                      several functions.
121    //
122    //    2003-JUL-10 - Thanks to Charles Godwin for making me realize my 'FmtArg'
123    //                                      fixes had inadvertently broken the DLL-export code (which is
124    //                  normally commented out.  I had to move it up higher.  Also
125    //                                      this helped me catch a bug in ssicoll that would prevent
126    //                  compilation, otherwise.
127    //
128    //    2003-MAR-14 - Thanks to Jakko Van Hunen for pointing out a copy-and-paste
129    //                  bug in one of the overloads of FmtArg.
130    //
131    //    2003-MAR-10 - Thanks to Ronny Schulz for (twice!) sending me some changes
132    //                  to help CStdString build on SGI and for pointing out an
133    //                  error in placement of my preprocessor macros for ssfmtmsg.
134    //
135    //    2002-NOV-26 - Thanks to Bagira for pointing out that my implementation of
136    //                  SpanExcluding was not properly handling the case in which
137    //                  the string did NOT contain any of the given characters
138    //
139    //    2002-OCT-21 - Many thanks to Paul DeMarco who was invaluable in helping me
140    //                  get this code working with Borland's free compiler as well
141    //                  as the Dev-C++ compiler (available free at SourceForge).
142    //
143    //    2002-SEP-13 - Thanks to Glen Maynard who helped me get rid of some loud
144    //                  but harmless warnings that were showing up on g++.  Glen
145    //                  also pointed out that some pre-declarations of FmtArg<>
146    //                  specializations were unnecessary (and no good on G++)
147    //
148    //    2002-JUN-26 - Thanks to Arnt Witteveen for pointing out that I was using
149    //                  static_cast<> in a place in which I should have been using
150    //                  reinterpret_cast<> (the ctor for unsigned char strings).
151    //                  That's what happens when I don't unit-test properly!
152    //                  Arnt also noticed that CString was silently correcting the
153    //                  'nCount' argument to Left() and Right() where CStdString was
154    //                  not (and crashing if it was bad).  That is also now fixed!
155    //
156    //        2002-FEB-25 - Thanks to Tim Dowty for pointing out (and giving me the fix
157    //                                      for) a conversion problem with non-ASCII MBCS characters.
158    //                                      CStdString is now used in my favorite commercial MP3 player!
159    //
160    //        2001-DEC-06 - Thanks to Wang Haifeng for spotting a problem in one of the
161    //                                      assignment operators (for _bstr_t) that would cause compiler
162    //                                      errors when refcounting protection was turned off.
163    //
164    //        2001-NOV-27 - Remove calls to operator!= which involve reverse_iterators
165    //                                      due to a conflict with the rel_ops operator!=.  Thanks to
166    //                                      John James for pointing this out.
167    //
168    //    2001-OCT-29 - Added a minor range checking fix for the Mid function to
169    //                                      make it as forgiving as CString's version is.  Thanks to
170    //                                      Igor Kholodov for noticing this.
171    //                                - Added a specialization of std::swap for CStdString.  Thanks
172    //                                      to Mike Crusader for suggesting this!  It's commented out
173    //                                      because you're not supposed to inject your own code into the
174    //                                      'std' namespace.  But if you don't care about that, it's
175    //                                      there if you want it
176    //                                - Thanks to Jason Mills for catching a case where CString was
177    //                                      more forgiving in the Delete() function than I was.
178    //
179    //        2001-JUN-06 - I was violating the Standard name lookup rules stated
180    //                                      in [14.6.2(3)].  None of the compilers I've tried so
181    //                                      far apparently caught this but HP-UX aCC 3.30 did.  The
182    //                                      fix was to add 'this->' prefixes in many places.
183    //                                      Thanks to Farrokh Nejadlotfi for this!
184    //
185    //        2001-APR-27 - StreamLoad was calculating the number of BYTES in one
186    //                                      case, not characters.  Thanks to Pablo Presedo for this.
187  //  //
188  //    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
189  //                                      source string was empty.  Fixed thanks to Eric Nitzsche.  //                                      source string was empty.  Fixed thanks to Eric Nitzsche.
190  //  //
191  //    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
192  //                                      ability to build CStdString on Sun Unix systems.  He  //                                      ability to build CStdString on Sun Unix systems.  He
193  //                                      sent me detailed build reports about what works and what  //                                      sent me detailed build reports about what works and what
194  //                                      does not.  If CStdString compiles on your Unix box, you  //                                      does not.  If CStdString compiles on your Unix box, you
195  //                                      can thank Scott for it.  //                                      can thank Scott for it.
196  //  //
197  //        2000-DEC-29 - Joldakowski noticed one overload of Insert failed to do  //        2000-DEC-29 - Joldakowski noticed one overload of Insert failed to do a
198  //                                      range check as CString's does.  Now fixed -- thanks!  //                                      range check as CString's does.  Now fixed -- thanks!
199  //  //
200  //        2000-NOV-07 - Aaron pointed out that I was calling static member  //        2000-NOV-07 - Aaron pointed out that I was calling static member
201  //                                      functions of char_traits via a temporary.  This was not  //                                      functions of char_traits via a temporary.  This was not
202  //                                      technically wrong, but it was unnecessary and caused  //                                      technically wrong, but it was unnecessary and caused
203  //                                      problems for poor old buggy VC5.  Thanks Aaron!  //                                      problems for poor old buggy VC5.  Thanks Aaron!
204  //  //
205  //        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
206  //                                      what the CString::Find code really ends up doing.   I was  //                                      what the CString::Find code really ends up doing.   I was
207  //                                      trying to match the docs.  Now I match the CString code  //                                      trying to match the docs.  Now I match the CString code
208  //                                - Joe also caught me truncating strings for GetBuffer() calls  //                                - Joe also caught me truncating strings for GetBuffer() calls
209  //                                      when the supplied length was less than the current length.  //                                      when the supplied length was less than the current length.
210  //  //
211  //        2000-MAY-25 - Better support for STLPORT's Standard library distribution  //        2000-MAY-25 - Better support for STLPORT's Standard library distribution
212  //                                - Got rid of the NSP macro - it interfered with Koenig lookup  //                                - Got rid of the NSP macro - it interfered with Koenig lookup
213  //                                - Thanks to Joe Woodbury for catching a TrimLeft() bug that  //                                - Thanks to Joe Woodbury for catching a TrimLeft() bug that
214  //                                      I introduced in January.  Empty strings were not getting  //                                      I introduced in January.  Empty strings were not getting
215  //                                      trimmed  //                                      trimmed
216  //  //
217  //        2000-APR-17 - Thanks to Joe Vitaterna for pointing out that ReverseFind  //        2000-APR-17 - Thanks to Joe Vitaterna for pointing out that ReverseFind
218  //                                      is supposed to be a const function.  //                                      is supposed to be a const function.
219  //  //
220  //        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
221  //                                      of the overloads of assign.  //                                      of the overloads of assign.
222  //  //
223  //    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!
224  //                                      Thanks to Todd Heckel for helping out with this.  //                                      Thanks to Todd Heckel for helping out with this.
225  //  //
226  //        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
227  //                                      Trim() function more efficient.  //                                      Trim() function more efficient.
228  //                                - 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
229  //                                      in one of the addition operators that takes _bstr_t.  //                                      in one of the addition operators that takes _bstr_t.
230  //                                - Got rid of the .CPP file -  you only need StdString.h now!  //                                - Got rid of the .CPP file -  you only need StdString.h now!
231  //  //
232  //        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
233  //                                      with my implementation of CStdString::FormatV in which  //                                      with my implementation of CStdString::FormatV in which
234  //                                      resulting string might not be properly NULL terminated.  //                                      resulting string might not be properly NULL terminated.
235  //  //
236  //        1999-DEC-06 - Chris Conti pointed yet another basic_string<> assignment  //        1999-DEC-06 - Chris Conti pointed yet another basic_string<> assignment
237  //                                      bug that MS has not fixed.  CStdString did nothing to fix  //                                      bug that MS has not fixed.  CStdString did nothing to fix
238  //                                      it either but it does now!  The bug was: create a string  //                                      it either but it does now!  The bug was: create a string
239  //                                      longer than 31 characters, get a pointer to it (via c_str())  //                                      longer than 31 characters, get a pointer to it (via c_str())
240  //                                      and then assign that pointer to the original string object.  //                                      and then assign that pointer to the original string object.
241  //                                      The resulting string would be empty.  Not with CStdString!  //                                      The resulting string would be empty.  Not with CStdString!
242  //  //
243  //        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
244  //                                      supposed to shrink it.  Fixed.  Thanks to Chris Conti.  //                                      supposed to shrink it.  Fixed.  Thanks to Chris Conti.
245  //                                - Some of the Q172398 fixes were not checking for assignment-  //                                - Some of the Q172398 fixes were not checking for assignment-
246  //                                      to-self.  Fixed.  Thanks to Baptiste Lepilleur.  //                                      to-self.  Fixed.  Thanks to Baptiste Lepilleur.
247  //  //
248  //        1999-AUG-20 - Improved Load() function to be more efficient by using  //        1999-AUG-20 - Improved Load() function to be more efficient by using
249  //                                      SizeOfResource().  Thanks to Rich Zuris for this.  //                                      SizeOfResource().  Thanks to Rich Zuris for this.
250  //                                - Corrected resource ID constructor, again thanks to Rich.  //                                - Corrected resource ID constructor, again thanks to Rich.
251  //                                - Fixed a bug that occurred with UNICODE characters above  //                                - Fixed a bug that occurred with UNICODE characters above
252  //                                      the first 255 ANSI ones.  Thanks to Craig Watson.  //                                      the first 255 ANSI ones.  Thanks to Craig Watson.
253  //                                - Added missing overloads of TrimLeft() and TrimRight().  //                                - Added missing overloads of TrimLeft() and TrimRight().
254  //                                      Thanks to Karim Ratib for pointing them out  //                                      Thanks to Karim Ratib for pointing them out
255  //  //
256  //        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.
257  //  //
258  //        1999-JUL-10 - Improved MFC/ATL independence of conversion macros  //        1999-JUL-10 - Improved MFC/ATL independence of conversion macros
259  //                                - Added SS_NO_REFCOUNT macro to allow you to disable any  //                                - Added SS_NO_REFCOUNT macro to allow you to disable any
260  //                                      reference-counting your basic_string<> impl. may do.  //                                      reference-counting your basic_string<> impl. may do.
261  //                                - Improved ReleaseBuffer() to be as forgiving as CString.  //                                - Improved ReleaseBuffer() to be as forgiving as CString.
262  //                                      Thanks for Fan Xia for helping me find this and to  //                                      Thanks for Fan Xia for helping me find this and to
263  //                                      Matthew Williams for pointing it out directly.  //                                      Matthew Williams for pointing it out directly.
264  //  //
265  //        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
266  //                                      ToLower/ToUpper.  They should call GetBuf() instead of  //                                      ToLower/ToUpper.  They should call GetBuf() instead of
267  //                                      data() in order to ensure the changed string buffer is not  //                                      data() in order to ensure the changed string buffer is not
268  //                                      reference-counted (in those implementations that refcount).  //                                      reference-counted (in those implementations that refcount).
269  //  //
270  //        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
271  //                                      a drop-in replacement for CString.  If you find this useful,  //                                      a drop-in replacement for CString.  If you find this useful,
272  //                                      you can thank Chris Sells for finally convincing me to give  //                                      you can thank Chris Sells for finally convincing me to give
273  //                                      in and implement it.  //                                      in and implement it.
274  //                                - Changed operators << and >> (for MFC CArchive) to serialize  //                                - Changed operators << and >> (for MFC CArchive) to serialize
275  //                                      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
276  //                                      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
277  //                                      no idea why you would want to do this but you can.  //                                      no idea why you would want to do this but you can.
278  //  //
279  //        1999-JUN-21 - Changed the CStdString class into the CStdStr template.  //        1999-JUN-21 - Changed the CStdString class into the CStdStr template.
280  //                                - Fixed FormatV() to correctly decrement the loop counter.  //                                - Fixed FormatV() to correctly decrement the loop counter.
281  //                                      This was harmless bug but a bug nevertheless.  Thanks to  //                                      This was harmless bug but a bug nevertheless.  Thanks to
282  //                                      Chris (of Melbsys) for pointing it out  //                                      Chris (of Melbsys) for pointing it out
283  //                                - Changed Format() to try a normal stack-based array before  //                                - Changed Format() to try a normal stack-based array before
284  //                                      using to _alloca().  //                                      using to _alloca().
285  //                                - Updated the text conversion macros to properly use code  //                                - Updated the text conversion macros to properly use code
286  //                                      pages and to fit in better in MFC/ATL builds.  In other  //                                      pages and to fit in better in MFC/ATL builds.  In other
287  //                                      words, I copied Microsoft's conversion stuff again.  //                                      words, I copied Microsoft's conversion stuff again.
288  //                                - Added equivalents of CString::GetBuffer, GetBufferSetLength  //                                - Added equivalents of CString::GetBuffer, GetBufferSetLength
289  //                                - new sscpy() replacement of CStdString::CopyString()  //                                - new sscpy() replacement of CStdString::CopyString()
290  //                                - a Trim() function that combines TrimRight() and TrimLeft().  //                                - a Trim() function that combines TrimRight() and TrimLeft().
291  //  //
292  //        1999-MAR-13 - Corrected the "NotSpace" functional object to use _istpace()  //        1999-MAR-13 - Corrected the "NotSpace" functional object to use _istpace()
293  //                                      instead of _isspace()   Thanks to Dave Plummer for this.  //                                      instead of _isspace()   Thanks to Dave Plummer for this.
294  //  //
295  //        1999-FEB-26 - Removed errant line (left over from testing) that #defined  //        1999-FEB-26 - Removed errant line (left over from testing) that #defined
296  //                                      _MFC_VER.  Thanks to John C Sipos for noticing this.  //                                      _MFC_VER.  Thanks to John C Sipos for noticing this.
297  //  //
298  //        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
299  //                                      caused infinite recursion and stack overflow  //                                      caused infinite recursion and stack overflow
300  //                                - Added member functions to simplify the process of  //                                - Added member functions to simplify the process of
301  //                                      persisting CStdStrings to/from DCOM IStream interfaces  //                                      persisting CStdStrings to/from DCOM IStream interfaces
302  //                                - Added functional objects (e.g. StdStringLessNoCase) that  //                                - Added functional objects (e.g. StdStringLessNoCase) that
303  //                                      allow CStdStrings to be used as keys STL map objects with  //                                      allow CStdStrings to be used as keys STL map objects with
304  //                                      case-insensitive comparison  //                                      case-insensitive comparison
305  //                                - Added array indexing operators (i.e. operator[]).  I  //                                - Added array indexing operators (i.e. operator[]).  I
306  //                                      originally assumed that these were unnecessary and would be  //                                      originally assumed that these were unnecessary and would be
307  //                                      inherited from basic_string.  However, without them, Visual  //                                      inherited from basic_string.  However, without them, Visual
308  //                                      C++ complains about ambiguous overloads when you try to use  //                                      C++ complains about ambiguous overloads when you try to use
309  //                                      them.  Thanks to Julian Selman to pointing this out.  //                                      them.  Thanks to Julian Selman to pointing this out.
310  //  //
311  //        1998-FEB-?? - Added overloads of assign() function to completely account  //        1998-FEB-?? - Added overloads of assign() function to completely account
312  //                                      for Q172398 bug.  Thanks to "Pete the Plumber" for this  //                                      for Q172398 bug.  Thanks to "Pete the Plumber" for this
313  //  //
314  //        1998-FEB-?? - Initial submission  //        1998-FEB-?? - Initial submission
315  //  //
316  // COPYRIGHT:  // COPYRIGHT:
317  //              1999 Joseph M. O'Leary.  This code is free.  Use it anywhere you want.  //              2002 Joseph M. O'Leary.  This code is 100% free.  Use it anywhere you
318  //              Rewrite it, restructure it, whatever.  Please don't blame me if it makes  //      want.  Rewrite it, restructure it, whatever.  If you can write software
319  //              your $30 billion dollar satellite explode in orbit.  If you redistribute  //      that makes money off of it, good for you.  I kinda like capitalism.
320  //              it in any form, I'd appreciate it if you would leave this notice here.  //      Please don't blame me if it causes your $30 billion dollar satellite
321  //  //      explode in orbit.  If you redistribute it in any form, I'd appreciate it
322  //              If you find any bugs, please let me know:  //      if you would leave this notice here.
 //  
 //                              jmoleary@earthlink.net  
 //                              http://home.earthlink.net/~jmoleary  
323  // =============================================================================  // =============================================================================
324    
325  // Avoid multiple inclusion the VC++ way,  // Avoid multiple inclusion the VC++ way,
# Line 209  Line 327 
327  // Turn off unavoidable compiler warnings  // Turn off unavoidable compiler warnings
328    
329  #if defined(_MSC_VER) && (_MSC_VER > 1100)  #if defined(_MSC_VER) && (_MSC_VER > 1100)
330          #pragma once  #pragma once
331          #pragma component(browser, off, references, "CStdString")  #pragma component(browser, off, references, "CStdString")
332          #pragma warning (disable : 4290) // C++ Exception Specification ignored  #pragma warning (disable : 4290)        // C++ Exception Specification ignored
333          #pragma warning (disable : 4127) // Conditional expression is constant  #pragma warning (disable : 4127)        // Conditional expression is constant
334          #pragma warning (disable : 4097) // typedef name used as synonym for class name  #pragma warning (disable : 4097)        // typedef name used as synonym for class name
335    #endif
336    
337    // Borland warnings to turn off
338    
339    #ifdef __BORLANDC__
340    #pragma option push -w-inl
341    //      #pragma warn -inl   // Turn off inline function warnings
342  #endif  #endif
343    
344  #ifndef STDSTRING_H  #ifndef STDSTRING_H
345  #define STDSTRING_H  #define STDSTRING_H
346    
347  // MACRO: SS_NO_REFCOUNT:  // SS_IS_INTRESOURCE
348  //              turns off reference counting at the assignment level  // -----------------
349  //              I define this by default.  comment it out if you don't want it.  //              A copy of IS_INTRESOURCE from VC7.  Because old VC6 version of winuser.h
350    //              doesn't have this.
351    
352    #define SS_IS_INTRESOURCE(_r) (false)
353    
354    #if !defined (SS_ANSI) && defined(_MSC_VER)
355    #undef SS_IS_INTRESOURCE
356    #if defined(_WIN64)
357    #define SS_IS_INTRESOURCE(_r) (((unsigned __int64)(_r) >> 16) == 0)
358    #else
359    #define SS_IS_INTRESOURCE(_r) (((unsigned long)(_r) >> 16) == 0)
360    #endif
361    #endif
362    
363    
364  #define SS_NO_REFCOUNT    // MACRO: SS_UNSIGNED
365    // ------------------
366    //      This macro causes the addition of a constructor and assignment operator
367    //      which take unsigned characters.  CString has such functions and in order
368    //      to provide maximum CString-compatability, this code needs them as well.
369    //      In practice you will likely never need these functions...
370    
371  // In non-Visual C++ and/or non-Win32 builds, we can't use some cool stuff.  //#define SS_UNSIGNED
372    
373  #if !defined(_MSC_VER) || !defined(_WIN32)  #ifdef SS_ALLOW_UNSIGNED_CHARS
374          #define SS_ANSI  #define SS_UNSIGNED
375  #endif  #endif
376    
377  // Avoid legacy code screw up: if _UNICODE is defined, UNICODE must be as well  // MACRO: SS_SAFE_FORMAT
378    // ---------------------
379    //      This macro provides limited compatability with a questionable CString
380    //      "feature".  You can define it in order to avoid a common problem that
381    //      people encounter when switching from CString to CStdString.
382    //
383    //      To illustrate the problem -- With CString, you can do this:
384    //
385    //          CString sName("Joe");
386    //          CString sTmp;
387    //          sTmp.Format("My name is %s", sName);                    // WORKS!
388    //
389    //      However if you were to try this with CStdString, your program would
390    //      crash.
391    //
392    //          CStdString sName("Joe");
393    //          CStdString sTmp;
394    //          sTmp.Format("My name is %s", sName);                    // CRASHES!
395    //
396    //      You must explicitly call c_str() or cast the object to the proper type
397    //
398    //          sTmp.Format("My name is %s", sName.c_str());            // WORKS!
399    //          sTmp.Format("My name is %s", static_cast<PCSTR>(sName));// WORKS!
400    //          sTmp.Format("My name is %s", (PCSTR)sName);                         // WORKS!
401    //
402    //      This is because it is illegal to pass anything but a POD type as a
403    //      variadic argument to a variadic function (i.e. as one of the "..."
404    //      arguments).  The type const char* is a POD type.  The type CStdString
405    //      is not.  Of course, neither is the type CString, but CString lets you do
406    //      it anyway due to the way they laid out the class in binary.  I have no
407    //      control over this in CStdString since I derive from whatever
408    //      implementation of basic_string is available.
409    //
410    //      However if you have legacy code (which does this) that you want to take
411    //      out of the MFC world and you don't want to rewrite all your calls to
412    //      Format(), then you can define this flag and it will no longer crash.
413    //
414    //      Note however that this ONLY works for Format(), not sprintf, fprintf,
415    //      etc.  If you pass a CStdString object to one of those functions, your
416    //      program will crash.  Not much I can do to get around this, short of
417    //      writing substitutes for those functions as well.
418    
419    #define SS_SAFE_FORMAT          // use new template style Format() function
420    
421    
422    // MACRO: SS_NO_IMPLICIT_CAST
423    // --------------------------
424    //      Some people don't like the implicit cast to const char* (or rather to
425    //      const CT*) that CStdString (and MFC's CString) provide.  That was the
426    //      whole reason I created this class in the first place, but hey, whatever
427    //      bakes your cake.  Just #define this macro to get rid of the the implicit
428    //      cast.
429    
430    //#define SS_NO_IMPLICIT_CAST // gets rid of operator const CT*()
431    
432    
433    // MACRO: SS_NO_REFCOUNT
434    // ---------------------
435    //              turns off reference counting at the assignment level.  Only needed
436    //              for the version of basic_string<> that comes with Visual C++ versions
437    //              6.0 or earlier, and only then in some heavily multithreaded scenarios.
438    //              Uncomment it if you feel you need it.
439    
440    //#define SS_NO_REFCOUNT
441    
442    // MACRO: SS_WIN32
443    // ---------------
444    //      When this flag is set, we are building code for the Win32 platform and
445    //      may use Win32 specific functions (such as LoadString).  This gives us
446    //      a couple of nice extras for the code.
447    //
448    //      Obviously, Microsoft's is not the only compiler available for Win32 out
449    //      there.  So I can't just check to see if _MSC_VER is defined to detect
450    //      if I'm building on Win32.  So for now, if you use MS Visual C++ or
451    //      Borland's compiler, I turn this on.  Otherwise you may turn it on
452    //      yourself, if you prefer
453    
454    #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(_WIN32)
455    #define SS_WIN32
456    #endif
457    
458    // MACRO: SS_ANSI
459    // --------------
460    //      When this macro is defined, the code attempts only to use ANSI/ISO
461    //      standard library functions to do it's work.  It will NOT attempt to use
462    //      any Win32 of Visual C++ specific functions -- even if they are
463    //      available.  You may define this flag yourself to prevent any Win32
464    //      of VC++ specific functions from being called.
465    
466    // If we're not on Win32, we MUST use an ANSI build
467    
468    #ifndef SS_WIN32
469    #if !defined(SS_NO_ANSI)
470    #define SS_ANSI
471    #endif
472    #endif
473    
474    // MACRO: SS_ALLOCA
475    // ----------------
476    //      Some implementations of the Standard C Library have a non-standard
477    //      function known as alloca().  This functions allows one to allocate a
478    //      variable amount of memory on the stack.  It is needed to implement
479    //      the ASCII/MBCS conversion macros.
480    //
481    //      I wanted to find some way to determine automatically if alloca() is
482    //              available on this platform via compiler flags but that is asking for
483    //              trouble.  The crude test presented here will likely need fixing on
484    //              other platforms.  Therefore I'll leave it up to you to fiddle with
485    //              this test to determine if it exists.  Just make sure SS_ALLOCA is or
486    //              is not defined as appropriate and you control this feature.
487    
488    #if defined(_MSC_VER) && !defined(SS_ANSI)
489    #define SS_ALLOCA
490    #endif
491    
492    // MACRO: SS_MBCS
493    // --------------
494    //              Setting this macro means you are using MBCS characters.  In MSVC
495    //              builds, this macro gets set automatically by detection of the
496    //              preprocessor flag _MBCS.  For other platforms you may set it manually
497    //              if you wish.  The only effect it currently has is to cause the
498    //              allocation of more space for wchar_t --> char conversions.
499    //              Note that MBCS does not mean UNICODE.
500    //
501    //      #define SS_MBCS
502    //
503    #ifdef _MBCS
504    #define SS_MBCS
505    #endif
506    
507    
508    
509    // Compiler Error regarding _UNICODE and UNICODE
510    // -----------------------------------------------
511    // Microsoft header files are screwy.  Sometimes they depend on a preprocessor
512    // flag named "_UNICODE".  Other times they check "UNICODE" (note the lack of
513    // leading underscore in the second version".  In several places, they silently
514    // "synchronize" these two flags this by defining one of the other was defined.
515    // In older version of this header, I used to try to do the same thing.
516    //
517    // However experience has taught me that this is a bad idea.  You get weird
518    // compiler errors that seem to indicate things like LPWSTR and LPTSTR not being
519    // equivalent in UNICODE builds, stuff like that (when they MUST be in a proper
520    // UNICODE  build).  You end up scratching your head and saying, "But that HAS
521    // to compile!".
522    //
523    // So what should you do if you get this error?
524    //
525    // Make sure that both macros (_UNICODE and UNICODE) are defined before this
526    // file is included.  You can do that by either
527    //
528    //              a) defining both yourself before any files get included
529    //              b) including the proper MS headers in the proper order
530    //              c) including this file before any other file, uncommenting
531    //                 the #defines below, and commenting out the #errors
532    //
533    //      Personally I recommend solution a) but it's your call.
534    
535    #ifdef _MSC_VER
536  #if defined (_UNICODE) && !defined (UNICODE)  #if defined (_UNICODE) && !defined (UNICODE)
537          #define UNICODE  #error UNICODE defined  but not UNICODE
538    //      #define UNICODE  // no longer silently fix this
539  #endif  #endif
540  #if defined (UNICODE) && !defined (_UNICODE)  #if defined (UNICODE) && !defined (_UNICODE)
541          #define _UNICODE  #error Warning, UNICODE defined  but not _UNICODE
542    //      #define _UNICODE  // no longer silently fix this
543    #endif
544  #endif  #endif
545    
546    
547  // -----------------------------------------------------------------------------  // -----------------------------------------------------------------------------
548  // 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
549  // 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
550  // -----------------------------------------------------------------------------  // -----------------------------------------------------------------------------
551  template<class Type>  template < class Type >
552  inline const Type& SSMIN(const Type& arg1, const Type& arg2)  inline const Type & SSMIN( const Type & arg1, const Type & arg2 )
553  {  {
554          return arg2 < arg1 ? arg2 : arg1;      return arg2 < arg1 ? arg2 : arg1;
555  }  }
556  template<class Type>  template < class Type >
557  inline const Type& SSMAX(const Type& arg1, const Type& arg2)  inline const Type & SSMAX( const Type & arg1, const Type & arg2 )
558  {  {
559          return arg2 > arg1 ? arg2 : arg1;      return arg2 > arg1 ? arg2 : arg1;
560  }  }
561    
562  // 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
# Line 260  inline const Type& SSMAX(const Type& arg Line 564  inline const Type& SSMAX(const Type& arg
564    
565  #if !defined(W32BASE_H)  #if !defined(W32BASE_H)
566    
567          // 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)
568    
569    #ifdef SS_ANSI
570    
571    // On Win32 we have TCHAR.H so just include it.  This is NOT violating
572    // the spirit of SS_ANSI as we are not calling any Win32 functions here.
573    
574    #ifdef SS_WIN32
575    
576    #include <TCHAR.H>
577    #include <WTYPES.H>
578    #ifndef STRICT
579    #define STRICT
580    #endif
581    
582    // ... but on non-Win32 platforms, we must #define the types we need.
583    
584    #else
585    
586    typedef const char *PCSTR;
587    typedef char *PSTR;
588    typedef const wchar_t *PCWSTR;
589    typedef wchar_t *PWSTR;
590    #ifdef UNICODE
591    typedef wchar_t TCHAR;
592    #else
593    typedef char TCHAR;
594    #endif
595    typedef wchar_t OLECHAR;
596    
597    #endif // #ifndef _WIN32
598    
599    
600    // Make sure ASSERT and verify are defined using only ANSI stuff
601    
602    #ifndef ASSERT
603    #include <assert.h>
604    #define ASSERT(f) assert((f))
605    #endif
606    #ifndef VERIFY
607    #ifdef _DEBUG
608    #define VERIFY(x) ASSERT((x))
609    #else
610    #define VERIFY(x) x
611    #endif
612    #endif
613    
614    #else // ...else SS_ANSI is NOT defined
615    
616    #include <TCHAR.H>
617    #include <WTYPES.H>
618    #ifndef STRICT
619    #define STRICT
620    #endif
621    
622          #ifdef SS_ANSI  // Make sure ASSERT and verify are defined
623    
624                  // On non-Win32 platforms, there is no TCHAR.H so define what we need  #ifndef ASSERT
625    #include <crtdbg.h>
626    #define ASSERT(f) _ASSERTE((f))
627    #endif
628    #ifndef VERIFY
629    #ifdef _DEBUG
630    #define VERIFY(x) ASSERT((x))
631    #else
632    #define VERIFY(x) x
633    #endif
634    #endif
635    
636                  #ifndef _WIN32  #endif // #ifdef SS_ANSI
637    
638                          typedef const char*             PCSTR;  #ifndef UNUSED
639                          typedef char*                   PSTR;  #define UNUSED(x) x
640                          typedef const wchar_t*  PCWSTR;  #endif
                         typedef wchar_t*                PWSTR;  
                         #ifdef UNICODE  
                                 typedef wchar_t         TCHAR;  
                         #else  
                                 typedef char            TCHAR;  
                         #endif  
                         typedef wchar_t                 OLECHAR;  
   
                 #else  
   
                         #include <TCHAR.H>  
                         #include <WTYPES.H>  
                         #ifndef STRICT  
                                 #define STRICT  
                         #endif  
   
                 #endif  // #ifndef _WIN32  
   
   
                 // Make sure ASSERT and verify are defined in an ANSI fashion  
   
                 #ifndef ASSERT  
                         #include <assert.h>  
                         #define ASSERT(f) assert((f))  
                 #endif  
                 #ifndef VERIFY  
                         #ifdef _DEBUG  
                                 #define VERIFY(x) ASSERT((x))  
                         #else  
                                 #define VERIFY(x) x  
                         #endif  
                 #endif  
   
         #else // #ifdef SS_ANSI  
   
                 #include <TCHAR.H>  
                 #include <WTYPES.H>  
                 #ifndef STRICT  
                         #define STRICT  
                 #endif  
   
                 // Make sure ASSERT and verify are defined  
   
                 #ifndef ASSERT  
                         #include <crtdbg.h>  
                         #define ASSERT(f) _ASSERTE((f))  
                 #endif  
                 #ifndef VERIFY  
                         #ifdef _DEBUG  
                                 #define VERIFY(x) ASSERT((x))  
                         #else  
                                 #define VERIFY(x) x  
                         #endif  
                 #endif  
   
         #endif // #ifdef SS_ANSI  
   
         #ifndef UNUSED  
                 #define UNUSED(x) x  
         #endif  
641    
642  #endif // #ifndef W32BASE_H  #endif // #ifndef W32BASE_H
643    
644  // Standard headers needed  // Standard headers needed
645    
646  #include <string>                       // basic_string  #include <string>               // basic_string
647  #include <algorithm>            // for_each, etc.  #include <algorithm>            // for_each, etc.
648  #include <functional>           // for StdStringLessNoCase, et al  #include <functional>           // for StdStringLessNoCase, et al
649  #include <locale>                       // for various facets  #include <locale>               // for various facets
650    
651  // 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
652  // 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.
653    // _bstr_t
654    
655  #if defined (_MSC_VER) && (_MSC_VER >= 1100)  #if defined (_MSC_VER) && (_MSC_VER >= 1100)
656          #include <comdef.h>  #include <comdef.h>
657          #define SS_INC_COMDEF           // signal that we #included MS comdef.h file  #define SS_INC_COMDEF           // signal that we #included MS comdef.h file
658          #define STDSTRING_INC_COMDEF  #define STDSTRING_INC_COMDEF
659          #define SS_NOTHROW __declspec(nothrow)  #define SS_NOTHROW __declspec(nothrow)
660  #else  #else
661          #define SS_NOTHROW  #define SS_NOTHROW
662  #endif  #endif
663    
664  #ifndef TRACE  #ifndef TRACE
665          #define TRACE_DEFINED_HERE  #define TRACE_DEFINED_HERE
666          #define TRACE  #define TRACE
667  #endif  #endif
668    
669  // 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
# Line 364  inline const Type& SSMAX(const Type& arg Line 672  inline const Type& SSMAX(const Type& arg
672  // as an LPCTSTR.  // as an LPCTSTR.
673    
674  #if !defined(PCTSTR) && !defined(PCTSTR_DEFINED)  #if !defined(PCTSTR) && !defined(PCTSTR_DEFINED)
675          typedef const TCHAR*                    PCTSTR;  typedef const TCHAR *PCTSTR;
676          #define PCTSTR_DEFINED  #define PCTSTR_DEFINED
677  #endif  #endif
678    
679  #if !defined(PCOLESTR) && !defined(PCOLESTR_DEFINED)  #if !defined(PCOLESTR) && !defined(PCOLESTR_DEFINED)
680          typedef const OLECHAR*                  PCOLESTR;  typedef const OLECHAR *PCOLESTR;
681          #define PCOLESTR_DEFINED  #define PCOLESTR_DEFINED
682  #endif  #endif
683    
684  #if !defined(POLESTR) && !defined(POLESTR_DEFINED)  #if !defined(POLESTR) && !defined(POLESTR_DEFINED)
685          typedef OLECHAR*                                POLESTR;  typedef OLECHAR *POLESTR;
686          #define POLESTR_DEFINED  #define POLESTR_DEFINED
687  #endif  #endif
688    
689  #if !defined(PCUSTR) && !defined(PCUSTR_DEFINED)  #if !defined(PCUSTR) && !defined(PCUSTR_DEFINED)
690          typedef const unsigned char*    PCUSTR;  typedef const unsigned char *PCUSTR;
691          typedef unsigned char*                  PUSTR;  typedef unsigned char *PUSTR;
692          #define PCUSTR_DEFINED  #define PCUSTR_DEFINED
693  #endif  #endif
694    
695    
696    // SGI compiler 7.3 doesnt know these  types - oh and btw, remember to use
697    // -LANG:std in the CXX Flags
698    #if defined(__sgi)
699    typedef unsigned long DWORD;
700    typedef void *LPCVOID;
701    #endif
702    
703    
704  // SS_USE_FACET macro and why we need it:  // SS_USE_FACET macro and why we need it:
705  //  //
706  // 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
# Line 401  inline const Type& SSMAX(const Type& arg Line 718  inline const Type& SSMAX(const Type& arg
718  //  //
719  // 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
720  // 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.
721    
722  #ifndef schMSG  #ifndef schMSG
723          #define schSTR(x)          #x  #define schSTR(x)    #x
724          #define schSTR2(x)      schSTR(x)  #define schSTR2(x) schSTR(x)
725          #define schMSG(desc) message(__FILE__ "(" schSTR2(__LINE__) "):" #desc)  #define schMSG(desc) message(__FILE__ "(" schSTR2(__LINE__) "):" #desc)
726  #endif  #endif
727    
728  #ifndef SS_USE_FACET  #ifndef SS_USE_FACET
729          // STLPort #defines a macro (__STL_NO_EXPLICIT_FUNCTION_TMPL_ARGS) for  
730          // all MSVC builds, erroneously in my opinion.  It causes problems for  // STLPort #defines a macro (__STL_NO_EXPLICIT_FUNCTION_TMPL_ARGS) for
731          // my SS_ANSI builds.  In my code, I always comment out that line.  You'll  // all MSVC builds, erroneously in my opinion.  It causes problems for
732          // find it in   \stlport\config\stl_msvc.h  // my SS_ANSI builds.  In my code, I always comment out that line.  You'll
733          #if defined(__SGI_STL_PORT) && (__SGI_STL_PORT >= 0x400 )  // find it in   \stlport\config\stl_msvc.h
734                  #if defined(__STL_NO_EXPLICIT_FUNCTION_TMPL_ARGS) && defined(_MSC_VER)  
735                          #ifdef SS_ANSI  #if defined(__SGI_STL_PORT) && (__SGI_STL_PORT >= 0x400 )
736                                  #pragma schMSG(__STL_NO_EXPLICIT_FUNCTION_TMPL_ARGS defined!!)  
737                          #endif  #if defined(__STL_NO_EXPLICIT_FUNCTION_TMPL_ARGS) && defined(_MSC_VER)
738                  #endif  #ifdef SS_ANSI
739                  #define SS_USE_FACET(loc, fac) std::use_facet<fac >(loc)  #pragma schMSG(__STL_NO_EXPLICIT_FUNCTION_TMPL_ARGS defined!!)
740          #elif defined(_MSC_VER )  #endif
741                  #define SS_USE_FACET(loc, fac) _USE(loc, fac)  #endif
742    #define SS_USE_FACET(loc, fac) std::use_facet<fac >(loc)
743          // ...and  
744          #elif defined(_RWSTD_NO_TEMPLATE_ON_RETURN_TYPE)  #elif defined(_MSC_VER )
745          #define SS_USE_FACET(loc, fac) std::use_facet(loc, (fac*)0)  
746          #else  #define SS_USE_FACET(loc, fac) std::_USE(loc, fac)
747                  #define SS_USE_FACET(loc, fac) std::use_facet<fac >(loc)  
748          #endif  // ...and
749    #elif defined(_RWSTD_NO_TEMPLATE_ON_RETURN_TYPE)
750    
751    #define SS_USE_FACET(loc, fac) std::use_facet(loc, (fac*)0)
752    
753    #else
754    
755    #define SS_USE_FACET(loc, fac) std::use_facet<fac >(loc)
756    
757    #endif
758    
759  #endif  #endif
760    
761  // =============================================================================  // =============================================================================
762  // 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.
763  // =============================================================================  // =============================================================================
764    
765    #include <wchar.h>              // Added to Std Library with Amendment #1.
766    
767  // First define the conversion helper functions.  We define these regardless of  // First define the conversion helper functions.  We define these regardless of
768  // any preprocessor macro settings since their names won't collide.  // any preprocessor macro settings since their names won't collide.
769    
770    // Not sure if we need all these headers.   I believe ANSI says we do.
771    
772    #include <stdio.h>
773    #include <stdarg.h>
774    #include <wctype.h>
775    #include <ctype.h>
776    #include <stdlib.h>
777    #ifndef va_start
778    #include <varargs.h>
779    #endif
780    
781    // StdCodeCvt - made to look like Win32 functions WideCharToMultiByte
782    //                              and MultiByteToWideChar but uses locales in SS_ANSI
783    //                              builds.  There are a number of overloads.
784    //              First argument is the destination buffer.
785    //              Second argument is the source buffer
786    //#if defined (SS_ANSI) || !defined (SS_WIN32)
787    
788    // 'SSCodeCvt' - shorthand name for the codecvt facet we use
789    
790    typedef std::codecvt < wchar_t, char, mbstate_t > SSCodeCvt;
791    
792    inline PWSTR StdCodeCvt( PWSTR pDstW, int nDst, PCSTR pSrcA, int nSrc,
793                             const std::locale & loc = std::locale() )
794    {
795        ASSERT( 0 != pSrcA );
796        ASSERT( 0 != pDstW );
797        
798        pDstW[ 0 ] = '\0';
799        
800        if ( nSrc > 0 ) {
801            PCSTR pNextSrcA = pSrcA;
802            PWSTR pNextDstW = pDstW;
803            SSCodeCvt::result res = SSCodeCvt::ok;
804            const SSCodeCvt & conv = SS_USE_FACET( loc, SSCodeCvt );
805            SSCodeCvt::state_type st = {
806                                           0};
807            res = conv.in( st,
808                           pSrcA, pSrcA + nSrc, pNextSrcA,
809                           pDstW, pDstW + nDst, pNextDstW );
810                          
811            ASSERT( SSCodeCvt::ok == res );
812            ASSERT( SSCodeCvt::error != res );
813            ASSERT( pNextDstW >= pDstW );
814            ASSERT( pNextSrcA >= pSrcA );
815            
816            // Null terminate the converted string
817            
818            if ( pNextDstW - pDstW > nDst )
819                * ( pDstW + nDst ) = '\0';
820            else
821                *pNextDstW = '\0';
822        }
823        return pDstW;
824    }
825    inline PWSTR StdCodeCvt( PWSTR pDstW, int nDst, PCUSTR pSrcA, int nSrc,
826                             const std::locale & loc = std::locale() )
827    {
828        return StdCodeCvt( pDstW, nDst, ( PCSTR ) pSrcA, nSrc, loc );
829    }
830    
831    inline PSTR StdCodeCvt( PSTR pDstA, int nDst, PCWSTR pSrcW, int nSrc,
832                            const std::locale & loc = std::locale() )
833    {
834        ASSERT( 0 != pDstA );
835        ASSERT( 0 != pSrcW );
836        
837        pDstA[ 0 ] = '\0';
838        
839        if ( nSrc > 0 ) {
840            PSTR pNextDstA = pDstA;
841            PCWSTR pNextSrcW = pSrcW;
842            SSCodeCvt::result res = SSCodeCvt::ok;
843            const SSCodeCvt & conv = SS_USE_FACET( loc, SSCodeCvt );
844            SSCodeCvt::state_type st = {
845                                           0};
846            res = conv.out( st,
847                            pSrcW, pSrcW + nSrc, pNextSrcW,
848                            pDstA, pDstA + nDst, pNextDstA );
849                            
850            ASSERT( SSCodeCvt::error != res );
851            ASSERT( SSCodeCvt::ok == res );   // strict, comment out for sanity
852            ASSERT( pNextDstA >= pDstA );
853            ASSERT( pNextSrcW >= pSrcW );
854            
855            // Null terminate the converted string
856            
857            if ( pNextDstA - pDstA > nDst )
858                * ( pDstA + nDst ) = '\0';
859            else
860                *pNextDstA = '\0';
861        }
862        return pDstA;
863    }
864    inline PUSTR StdCodeCvt( PUSTR pDstA, int nDst, PCWSTR pSrcW, int nSrc,
865                             const std::locale & loc = std::locale() )
866    {
867        return ( PUSTR ) StdCodeCvt( ( PSTR ) pDstA, nDst, pSrcW, nSrc, loc );
868    }
869    
870  #ifdef SS_ANSI // Are we doing things the standard, non-Win32 way?...  /*
871    #else   // ...or are we doing things assuming win32 and Visual C++?
872    
873     inline PWSTR StdCodeCvt(PWSTR pDstW, int nDst, PCSTR pSrcA, int nSrc, UINT acp=CP_ACP)
874     {
875      ASSERT(0 != pSrcA);
876      ASSERT(0 != pDstW);
877      pW[0] = '\0';
878      MultiByteToWideChar(acp, 0, pSrcA, nSrc, pDstW, nDst);
879      return pW;
880     }
881     inline PWSTR StdCodeCvt(PWSTR pDstW, nDst, PCUSTR pSrcA, int nSrc, UINT acp=CP_ACP)
882     {
883      return StdCodeCvt(pDstW, nDst, (PCSTR)pSrcA, nSrc, acp);
884     }
885    
886     inline PSTR StdCodeCvt(PSTR pDstA, nDst PCWSTR pSrcW, int nSrc, UINT acp=CP_ACP)
887     {
888      ASSERT(0 != pDstA);
889      ASSERT(0 != pSrcW);
890      pA[0] = '\0';
891      WideCharToMultiByte(acp, 0, pSrcW, nSrc, pDstA, nDst, 0, 0);
892      return pA;
893     }
894     inline PUSTR StdCodeCvt(PUSTR pDstA, nDst, PCWSTR pSrcW, int nSrc, UINT acp=CP_ACP)
895     {
896      return (PUSTR)StdCodeCvt((PSTR)pDstA, nDst, pSrcW, nSrc, acp);
897     }
898    
899    #endif
900    */
901    
902          typedef std::codecvt<wchar_t, char, mbstate_t> SSCodeCvt;  // Unicode/MBCS conversion macros are only available on implementations of
903    // the "C" library that have the non-standard _alloca function.  As far as I
904    // know that's only Microsoft's though I've heard that the function exists
905    // elsewhere.
906    
907          // Not sure if we need all these headers.   I believe ANSI says we do.  #if defined(SS_ALLOCA) && !defined SS_NO_CONVERSION
908    
909          #include <stdio.h>  #include <malloc.h>             // needed for _alloca
         #include <stdarg.h>  
         #include <wchar.h>  
         #ifndef va_start  
                 #include <varargs.h>  
         #endif  
   
         // StdCodeCvt - made to look like Win32 functions WideCharToMultiByte annd  
         //              MultiByteToWideChar but uses locales in SS_ANSI builds  
         inline PWSTR StdCodeCvt(PWSTR pW, PCSTR pA, int nChars,  
                 const std::locale& loc=std::locale())  
         {  
                 ASSERT(0 != pA);  
                 ASSERT(0 != pW);  
                 pW[0] = '\0';  
                 PCSTR pBadA                             = 0;  
                 PWSTR pBadW                             = 0;  
                 SSCodeCvt::result res   = SSCodeCvt::ok;  
                 const SSCodeCvt& conv   = SS_USE_FACET(loc, SSCodeCvt);  
         SSCodeCvt::state_type st= { 0 };  
                 res                                             = conv.in(st,  
                                                                                   pA, pA + nChars, pBadA,  
                                                                                   pW, pW + nChars, pBadW);  
                 ASSERT(SSCodeCvt::ok == res);  
                 return pW;  
         }  
         inline PWSTR StdCodeCvt(PWSTR pW, PCUSTR pA, int nChars,  
                 const std::locale& loc=std::locale())  
         {  
                 return StdCodeCvt(pW, (PCSTR)pA, nChars, loc);  
         }  
   
         inline PSTR StdCodeCvt(PSTR pA, PCWSTR pW, int nChars,  
                 const std::locale& loc=std::locale())  
         {  
                 ASSERT(0 != pA);  
                 ASSERT(0 != pW);  
                 pA[0] = '\0';  
                 PSTR pBadA                              = 0;  
                 PCWSTR pBadW                    = 0;  
                 SSCodeCvt::result res   = SSCodeCvt::ok;  
                 const SSCodeCvt& conv   = SS_USE_FACET(loc, SSCodeCvt);  
         SSCodeCvt::state_type st= { 0 };  
                 res                                             = conv.out(st,  
                                                                                    pW, pW + nChars, pBadW,  
                                                                                    pA, pA + nChars, pBadA);  
                 ASSERT(SSCodeCvt::ok == res);  
                 return pA;  
         }  
         inline PUSTR StdCodeCvt(PUSTR pA, PCWSTR pW, int nChars,  
                 const std::locale& loc=std::locale())  
         {  
                 return (PUSTR)StdCodeCvt((PSTR)pA, pW, nChars, loc);  
         }  
910    
911  #else   // ...or are we doing things assuming win32 and Visual C++?  // Define our conversion macros to look exactly like Microsoft's to
912    // facilitate using this stuff both with and without MFC/ATL
913    
914          #include <malloc.h>     // needed for _alloca  #ifdef _CONVERSION_USES_THREAD_LOCALE
915    
916          inline PWSTR StdCodeCvt(PWSTR pW, PCSTR pA, int nChars, UINT acp=CP_ACP)  #ifndef _DEBUG
917          {  #define SSCVT int _cvt; _cvt; UINT _acp=GetACP(); \
918                  ASSERT(0 != pA);         _acp; PCWSTR _pw; _pw; PCSTR _pa; _pa
919                  ASSERT(0 != pW);  #else
920                  pW[0] = '\0';  #define SSCVT int _cvt = 0; _cvt; UINT _acp=GetACP();\
921                  MultiByteToWideChar(acp, 0, pA, -1, pW, nChars);          _acp; PCWSTR _pw=0; _pw; PCSTR _pa=0; _pa
922                  return pW;  #endif
923          }  #define SSA2W(pa) (\
924          inline PWSTR StdCodeCvt(PWSTR pW, PCUSTR pA, int nChars, UINT acp=CP_ACP)        ((_pa = pa) == 0) ? 0 : (\
925          {         _cvt = (sslen(_pa)),\
926                  return StdCodeCvt(pW, (PCSTR)pA, nChars, acp);         StdCodeCvt((PWSTR) _alloca((_cvt+1)*2), (_cvt+1)*2, \
927          }         _pa, _cvt, _acp)))
928    #define SSW2A(pw) (\
929          inline PSTR StdCodeCvt(PSTR pA, PCWSTR pW, int nChars, UINT acp=CP_ACP)        ((_pw = pw) == 0) ? 0 : (\
930          {         _cvt = sslen(_pw), \
931                  ASSERT(0 != pA);         StdCodeCvt((LPSTR) _alloca((_cvt+1)*2), (_cvt+1)*2, \
932                  ASSERT(0 != pW);       _pw, _cvt, _acp)))
933                  pA[0] = '\0';  #else
                 WideCharToMultiByte(acp, 0, pW, -1, pA, nChars, 0, 0);  
                 return pA;  
         }  
         inline PUSTR StdCodeCvt(PUSTR pA, PCWSTR pW, int nChars, UINT acp=CP_ACP)  
         {  
                 return (PUSTR)StdCodeCvt((PSTR)pA, pW, nChars, acp);  
         }  
   
         // Define our conversion macros to look exactly like Microsoft's to  
         // facilitate using this stuff both with and without MFC/ATL  
   
         #ifdef _CONVERSION_USES_THREAD_LOCALE  
                 #ifndef _DEBUG  
                         #define SSCVT int _cvt; _cvt; UINT _acp=GetACP(); \  
                                 _acp; PCWSTR _pw; _pw; PCSTR _pa; _pa  
                 #else  
                         #define SSCVT int _cvt = 0; _cvt; UINT _acp=GetACP();\  
                                  _acp; PCWSTR _pw=0; _pw; PCSTR _pa=0; _pa  
                 #endif  
         #else  
                 #ifndef _DEBUG  
                         #define SSCVT int _cvt; _cvt; UINT _acp=CP_ACP; _acp;\  
                                  PCWSTR _pw; _pw; PCSTR _pa; _pa  
                 #else  
                         #define SSCVT int _cvt = 0; _cvt; UINT _acp=CP_ACP; \  
                                 _acp; PCWSTR _pw=0; _pw; PCSTR _pa=0; _pa  
                 #endif  
         #endif  
   
         #ifdef _CONVERSION_USES_THREAD_LOCALE  
                 #define SSA2W(pa) (\  
                         ((_pa = pa) == 0) ? 0 : (\  
                                 _cvt = (strlen(_pa)+1),\  
                                 StdCodeCvt((PWSTR) _alloca(_cvt*2), _pa, _cvt, _acp)))  
                 #define SSW2A(pw) (\  
                         ((_pw = pw) == 0) ? 0 : (\  
                                 _cvt = (wcslen(_pw)+1)*2,\  
                                 StdW2AHelper((LPSTR) _alloca(_cvt), _pw, _cvt, _acp)))  
         #else  
                 #define SSA2W(pa) (\  
                         ((_pa = pa) == 0) ? 0 : (\  
                                 _cvt = (strlen(_pa)+1),\  
                                 StdCodeCvt((PWSTR) _alloca(_cvt*2), _pa, _cvt)))  
                 #define SSW2A(pw) (\  
                         ((_pw = pw) == 0) ? 0 : (\  
                                 _cvt = (wcslen(_pw)+1)*2,\  
                                 StdCodeCvt((LPSTR) _alloca(_cvt), _pw, _cvt)))  
         #endif  
   
         #define SSA2CW(pa) ((PCWSTR)SSA2W((pa)))  
         #define SSW2CA(pw) ((PCSTR)SSW2A((pw)))  
   
         #ifdef UNICODE  
                 #define SST2A   SSW2A  
                 #define SSA2T   SSA2W  
                 #define SST2CA  SSW2CA  
                 #define SSA2CT  SSA2CW  
                 inline PWSTR    SST2W(PTSTR p)                  { return p; }  
                 inline PTSTR    SSW2T(PWSTR p)                  { return p; }  
                 inline PCWSTR   SST2CW(PCTSTR p)                { return p; }  
                 inline PCTSTR   SSW2CT(PCWSTR p)                { return p; }  
         #else  
                 #define SST2W   SSA2W  
                 #define SSW2T   SSW2A  
                 #define SST2CW  SSA2CW  
                 #define SSW2CT  SSW2CA  
                 inline PSTR             SST2A(PTSTR p)                  { return p; }  
                 inline PTSTR    SSA2T(PSTR p)                   { return p; }  
                 inline PCSTR    SST2CA(PCTSTR p)                { return p; }  
                 inline PCTSTR   SSA2CT(PCSTR p)                 { return p; }  
         #endif // #ifdef UNICODE  
   
         #if defined(UNICODE)  
         // in these cases the default (TCHAR) is the same as OLECHAR  
                 inline PCOLESTR SST2COLE(PCTSTR p)              { return p; }  
                 inline PCTSTR   SSOLE2CT(PCOLESTR p)    { return p; }  
                 inline POLESTR  SST2OLE(PTSTR p)                { return p; }  
                 inline PTSTR    SSOLE2T(POLESTR p)              { return p; }  
         #elif defined(OLE2ANSI)  
         // in these cases the default (TCHAR) is the same as OLECHAR  
                 inline PCOLESTR SST2COLE(PCTSTR p)              { return p; }  
                 inline PCTSTR   SSOLE2CT(PCOLESTR p)    { return p; }  
                 inline POLESTR  SST2OLE(PTSTR p)                { return p; }  
                 inline PTSTR    SSOLE2T(POLESTR p)              { return p; }  
         #else  
                 //CharNextW doesn't work on Win95 so we use this  
                 #define SST2COLE(pa)    SSA2CW((pa))  
                 #define SST2OLE(pa)             SSA2W((pa))  
                 #define SSOLE2CT(po)    SSW2CA((po))  
                 #define SSOLE2T(po)             SSW2A((po))  
         #endif  
   
         #ifdef OLE2ANSI  
                 #define SSW2OLE         SSW2A  
                 #define SSOLE2W         SSA2W  
                 #define SSW2COLE        SSW2CA  
                 #define SSOLE2CW        SSA2CW  
                 inline POLESTR          SSA2OLE(PSTR p)         { return p; }  
                 inline PSTR                     SSOLE2A(POLESTR p)      { return p; }  
                 inline PCOLESTR         SSA2COLE(PCSTR p)       { return p; }  
                 inline PCSTR            SSOLE2CA(PCOLESTR p){ return p; }  
         #else  
                 #define SSA2OLE         SSA2W  
                 #define SSOLE2A         SSW2A  
                 #define SSA2COLE        SSA2CW  
                 #define SSOLE2CA        SSW2CA  
                 inline POLESTR          SSW2OLE(PWSTR p)        { return p; }  
                 inline PWSTR            SSOLE2W(POLESTR p)      { return p; }  
                 inline PCOLESTR         SSW2COLE(PCWSTR p)      { return p; }  
                 inline PCWSTR           SSOLE2CW(PCOLESTR p){ return p; }  
         #endif  
   
         // Above we've defined macros that look like MS' but all have  
         // an 'SS' prefix.  Now we need the real macros.  We'll either  
         // get them from the macros above or from MFC/ATL.  If  
         // SS_NO_CONVERSION is #defined, we'll forgo them  
   
         #ifndef SS_NO_CONVERSION  
   
                 #if defined (USES_CONVERSION)  
   
                         #define _NO_STDCONVERSION       // just to be consistent  
   
                 #else  
   
                         #ifdef _MFC_VER  
   
                                 #include <afxconv.h>  
                                 #define _NO_STDCONVERSION // just to be consistent  
   
                         #else  
   
                                 #define USES_CONVERSION SSCVT  
                                 #define A2CW                    SSA2CW  
                                 #define W2CA                    SSW2CA  
                                 #define T2A                             SST2A  
                                 #define A2T                             SSA2T  
                                 #define T2W                             SST2W  
                                 #define W2T                             SSW2T  
                                 #define T2CA                    SST2CA  
                                 #define A2CT                    SSA2CT  
                                 #define T2CW                    SST2CW  
                                 #define W2CT                    SSW2CT  
                                 #define ocslen                  sslen  
                                 #define ocscpy                  sscpy  
                                 #define T2COLE                  SST2COLE  
                                 #define OLE2CT                  SSOLE2CT  
                                 #define T2OLE                   SST2COLE  
                                 #define OLE2T                   SSOLE2CT  
                                 #define A2OLE                   SSA2OLE  
                                 #define OLE2A                   SSOLE2A  
                                 #define W2OLE                   SSW2OLE  
                                 #define OLE2W                   SSOLE2W  
                                 #define A2COLE                  SSA2COLE  
                                 #define OLE2CA                  SSOLE2CA  
                                 #define W2COLE                  SSW2COLE  
                                 #define OLE2CW                  SSOLE2CW  
                   
                         #endif // #ifdef _MFC_VER  
                 #endif // #ifndef USES_CONVERSION  
         #endif // #ifndef SS_NO_CONVERSION  
   
         // Define ostring - generic name for std::basic_string<OLECHAR>  
   
         #if !defined(ostring) && !defined(OSTRING_DEFINED)  
                 typedef std::basic_string<OLECHAR> ostring;  
                 #define OSTRING_DEFINED  
         #endif  
934    
935  #endif // #ifndef SS_ANSI  #ifndef _DEBUG
936    #define SSCVT int _cvt; _cvt; UINT _acp=CP_ACP; _acp;\
937            PCWSTR _pw; _pw; PCSTR _pa; _pa
938    #else
939    #define SSCVT int _cvt = 0; _cvt; UINT _acp=CP_ACP; \
940           _acp; PCWSTR _pw=0; _pw; PCSTR _pa=0; _pa
941    #endif
942    #define SSA2W(pa) (\
943          ((_pa = pa) == 0) ? 0 : (\
944           _cvt = (sslen(_pa)),\
945           StdCodeCvt((PWSTR) _alloca((_cvt+1)*2), (_cvt+1)*2, \
946         _pa, _cvt)))
947    #define SSW2A(pw) (\
948          ((_pw = pw) == 0) ? 0 : (\
949           _cvt = (sslen(_pw)),\
950           StdCodeCvt((LPSTR) _alloca((_cvt+1)*2), (_cvt+1)*2, \
951         _pw, _cvt)))
952    #endif
953    
954  // StdCodeCvt when there's no conversion to be done  #define SSA2CW(pa) ((PCWSTR)SSA2W((pa)))
955  inline PSTR StdCodeCvt(PSTR pDst, PCSTR pSrc, int nChars)  #define SSW2CA(pw) ((PCSTR)SSW2A((pw)))
956    
957    #ifdef UNICODE
958    #define SST2A SSW2A
959    #define SSA2T SSA2W
960    #define SST2CA SSW2CA
961    #define SSA2CT SSA2CW
962    // (Did you get a compiler error here about not being able to convert
963    // PTSTR into PWSTR?  Then your _UNICODE and UNICODE flags are messed
964    // up.  Best bet: #define BOTH macros before including any MS headers.)
965    inline PWSTR SST2W( PTSTR p )
966    {
967        return p;
968    }
969    inline PTSTR SSW2T( PWSTR p )
970    {
971        return p;
972    }
973    inline PCWSTR SST2CW( PCTSTR p )
974    {
975        return p;
976    }
977    inline PCTSTR SSW2CT( PCWSTR p )
978    {
979        return p;
980    }
981    #else
982    #define SST2W SSA2W
983    #define SSW2T SSW2A
984    #define SST2CW SSA2CW
985    #define SSW2CT SSW2CA
986    inline PSTR SST2A( PTSTR p )
987    {
988        return p;
989    }
990    inline PTSTR SSA2T( PSTR p )
991  {  {
992          pDst[0]                         = '\0';      return p;
993          std::char_traits<char>::copy(pDst, pSrc, nChars);  }
994          if ( nChars > 0 )  inline PCSTR SST2CA( PCTSTR p )
995                  pDst[nChars]    = '\0';  {
996        return p;
997    }
998    inline PCTSTR SSA2CT( PCSTR p )
999    {
1000        return p;
1001    }
1002    #endif // #ifdef UNICODE
1003    
1004          return pDst;  #if defined(UNICODE)
1005    // in these cases the default (TCHAR) is the same as OLECHAR
1006    inline PCOLESTR SST2COLE( PCTSTR p )
1007    {
1008        return p;
1009    }
1010    inline PCTSTR SSOLE2CT( PCOLESTR p )
1011    {
1012        return p;
1013    }
1014    inline POLESTR SST2OLE( PTSTR p )
1015    {
1016        return p;
1017    }
1018    inline PTSTR SSOLE2T( POLESTR p )
1019    {
1020        return p;
1021    }
1022    #elif defined(OLE2ANSI)
1023    // in these cases the default (TCHAR) is the same as OLECHAR
1024    inline PCOLESTR SST2COLE( PCTSTR p )
1025    {
1026        return p;
1027  }  }
1028  inline PSTR StdCodeCvt(PSTR pDst, PCUSTR pSrc, int nChars)  inline PCTSTR SSOLE2CT( PCOLESTR p )
1029  {  {
1030          return StdCodeCvt(pDst, (PCSTR)pSrc, nChars);      return p;
1031  }  }
1032  inline PUSTR StdCodeCvt(PUSTR pDst, PCSTR pSrc, int nChars)  inline POLESTR SST2OLE( PTSTR p )
1033  {  {
1034          return (PUSTR)StdCodeCvt((PSTR)pDst, pSrc, nChars);      return p;
1035  }  }
1036    inline PTSTR SSOLE2T( POLESTR p )
1037    {
1038        return p;
1039    }
1040    #else
1041    //CharNextW doesn't work on Win95 so we use this
1042    #define SST2COLE(pa) SSA2CW((pa))
1043    #define SST2OLE(pa)  SSA2W((pa))
1044    #define SSOLE2CT(po) SSW2CA((po))
1045    #define SSOLE2T(po)  SSW2A((po))
1046    #endif
1047    
1048  inline PWSTR StdCodeCvt(PWSTR pDst, PCWSTR pSrc, int nChars)  #ifdef OLE2ANSI
1049    #define SSW2OLE  SSW2A
1050    #define SSOLE2W  SSA2W
1051    #define SSW2COLE SSW2CA
1052    #define SSOLE2CW SSA2CW
1053    inline POLESTR SSA2OLE( PSTR p )
1054    {
1055        return p;
1056    }
1057    inline PSTR SSOLE2A( POLESTR p )
1058    {
1059        return p;
1060    }
1061    inline PCOLESTR SSA2COLE( PCSTR p )
1062    {
1063        return p;
1064    }
1065    inline PCSTR SSOLE2CA( PCOLESTR p )
1066    {
1067        return p;
1068    }
1069    #else
1070    #define SSA2OLE  SSA2W
1071    #define SSOLE2A  SSW2A
1072    #define SSA2COLE SSA2CW
1073    #define SSOLE2CA SSW2CA
1074    inline POLESTR SSW2OLE( PWSTR p )
1075    {
1076        return p;
1077    }
1078    inline PWSTR SSOLE2W( POLESTR p )
1079  {  {
1080          pDst[0]                         = '\0';      return p;
1081          std::char_traits<wchar_t>::copy(pDst, pSrc, nChars);  }
1082          if ( nChars > 0 )  inline PCOLESTR SSW2COLE( PCWSTR p )
1083                  pDst[nChars]    = '\0';  {
1084        return p;
1085    }
1086    inline PCWSTR SSOLE2CW( PCOLESTR p )
1087    {
1088        return p;
1089    }
1090    #endif
1091    
1092    // Above we've defined macros that look like MS' but all have
1093    // an 'SS' prefix.  Now we need the real macros.  We'll either
1094    // get them from the macros above or from MFC/ATL.
1095    
1096    #if defined (USES_CONVERSION)
1097    
1098    #define _NO_STDCONVERSION       // just to be consistent
1099    
1100    #else
1101    
1102    #ifdef _MFC_VER
1103    
1104    #include <afxconv.h>
1105    #define _NO_STDCONVERSION       // just to be consistent
1106    
1107          return pDst;  #else
1108    
1109    #define USES_CONVERSION SSCVT
1110    #define A2CW   SSA2CW
1111    #define W2CA   SSW2CA
1112    #define T2A    SST2A
1113    #define A2T    SSA2T
1114    #define T2W    SST2W
1115    #define W2T    SSW2T
1116    #define T2CA   SST2CA
1117    #define A2CT   SSA2CT
1118    #define T2CW   SST2CW
1119    #define W2CT   SSW2CT
1120    #define ocslen   sslen
1121    #define ocscpy   sscpy
1122    #define T2COLE   SST2COLE
1123    #define OLE2CT   SSOLE2CT
1124    #define T2OLE   SST2COLE
1125    #define OLE2T   SSOLE2CT
1126    #define A2OLE   SSA2OLE
1127    #define OLE2A   SSOLE2A
1128    #define W2OLE   SSW2OLE
1129    #define OLE2W   SSOLE2W
1130    #define A2COLE   SSA2COLE
1131    #define OLE2CA   SSOLE2CA
1132    #define W2COLE   SSW2COLE
1133    #define OLE2CW   SSOLE2CW
1134    
1135    #endif // #ifdef _MFC_VER
1136    #endif // #ifndef USES_CONVERSION
1137    #endif // #ifndef SS_NO_CONVERSION
1138    
1139    // Define ostring - generic name for std::basic_string<OLECHAR>
1140    
1141    #if !defined(ostring) && !defined(OSTRING_DEFINED)
1142    typedef std::basic_string < OLECHAR > ostring;
1143    #define OSTRING_DEFINED
1144    #endif
1145    
1146    // StdCodeCvt when there's no conversion to be done
1147    inline PSTR StdCodeCvt( PSTR pDst, int nDst, PCSTR pSrc, int nSrc )
1148    {
1149        int nChars = SSMIN( nSrc, nDst );
1150        
1151        if ( nChars > 0 ) {
1152            pDst[ 0 ] = '\0';
1153            std::basic_string < char >::traits_type::copy( pDst, pSrc, nChars );
1154            //              std::char_traits<char>::copy(pDst, pSrc, nChars);
1155            pDst[ nChars ] = '\0';
1156        }
1157        
1158        return pDst;
1159    }
1160    inline PSTR StdCodeCvt( PSTR pDst, int nDst, PCUSTR pSrc, int nSrc )
1161    {
1162        return StdCodeCvt( pDst, nDst, ( PCSTR ) pSrc, nSrc );
1163    }
1164    inline PUSTR StdCodeCvt( PUSTR pDst, int nDst, PCSTR pSrc, int nSrc )
1165    {
1166        return ( PUSTR ) StdCodeCvt( ( PSTR ) pDst, nDst, pSrc, nSrc );
1167    }
1168    
1169    inline PWSTR StdCodeCvt( PWSTR pDst, int nDst, PCWSTR pSrc, int nSrc )
1170    {
1171        int nChars = SSMIN( nSrc, nDst );
1172        
1173        if ( nChars > 0 ) {
1174            pDst[ 0 ] = '\0';
1175            std::basic_string < wchar_t >::traits_type::copy( pDst, pSrc, nChars );
1176            //              std::char_traits<wchar_t>::copy(pDst, pSrc, nChars);
1177            pDst[ nChars ] = '\0';
1178        }
1179        
1180        return pDst;
1181  }  }
1182    
1183    
1184  // Define tstring -- generic name for std::basic_string<TCHAR>  // Define tstring -- generic name for std::basic_string<TCHAR>
1185    
1186  #if !defined(tstring) && !defined(TSTRING_DEFINED)  #if !defined(tstring) && !defined(TSTRING_DEFINED)
1187          typedef std::basic_string<TCHAR> tstring;  typedef std::basic_string < TCHAR > tstring;
1188          #define TSTRING_DEFINED  #define TSTRING_DEFINED
1189  #endif  #endif
1190    
1191  // a very shorthand way of applying the fix for KB problem Q172398  // a very shorthand way of applying the fix for KB problem Q172398
1192  // (basic_string assignment bug)  // (basic_string assignment bug)
1193    
1194  #if defined ( _MSC_VER ) && ( _MSC_VER < 1200 )  #if defined ( _MSC_VER ) && ( _MSC_VER < 1200 )
1195          #define Q172398(x) (x).erase()  #define Q172398(x) (x).erase()
1196  #else  #else
1197          #define Q172398(x)  #define Q172398(x)
1198  #endif  #endif
1199    
1200  // =============================================================================  // =============================================================================
# Line 744  inline PWSTR StdCodeCvt(PWSTR pDst, PCWS Line 1204  inline PWSTR StdCodeCvt(PWSTR pDst, PCWS
1204  // to map to string functions.  However the CStdStr<> template cannot use  // to map to string functions.  However the CStdStr<> template cannot use
1205  // macro-based generic text mappings because its character types do not get  // macro-based generic text mappings because its character types do not get
1206  // resolved until template processing which comes AFTER macro processing.  In  // resolved until template processing which comes AFTER macro processing.  In
1207  // other words, UNICODE is of little help to us in the CStdStr template  // other words, the preprocessor macro UNICODE is of little help to us in the
1208    // CStdStr template
1209  //  //
1210  // Therefore, to keep the CStdStr declaration simple, we have these inline  // Therefore, to keep the CStdStr declaration simple, we have these inline
1211  // functions.  The template calls them often.  Since they are inline (and NOT  // functions.  The template calls them often.  Since they are inline (and NOT
1212  // 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
1213  // to nothing.  // to nothing.
1214  //  //
1215  // Without these functions, the CStdStr<> template would probably have to broken  // Without these functions, the CStdStr<> template would probably have to broken
1216  // 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,
1217  // 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
1218  // size of template parameter CT.  // size of template parameter CT.
1219  //  //
1220  // 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
1221  // 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
1222  // non-standard, but often significantly faster Visual C++ way.  // non-standard, but often significantly faster Visual C++ way.
# Line 764  inline PWSTR StdCodeCvt(PWSTR pDst, PCWS Line 1225  inline PWSTR StdCodeCvt(PWSTR pDst, PCWS
1225  // If they defined SS_NO_REFCOUNT, then we must convert all assignments  // If they defined SS_NO_REFCOUNT, then we must convert all assignments
1226    
1227  #ifdef SS_NO_REFCOUNT  #ifdef SS_NO_REFCOUNT
1228          #define SSREF(x) (x).c_str()  #define SSREF(x) (x).c_str()
1229  #else  #else
1230          #define SSREF(x) (x)  #define SSREF(x) (x)
1231  #endif  #endif
1232    
1233  // -----------------------------------------------------------------------------  // -----------------------------------------------------------------------------
1234  // sslen: strlen/wcslen wrappers  // sslen: strlen/wcslen wrappers
1235  // -----------------------------------------------------------------------------  // -----------------------------------------------------------------------------
1236  template<typename CT> inline int sslen(const CT* pT)  template < typename CT >
1237    inline int sslen( const CT * pT )
1238  {  {
1239          return 0 == pT ? 0 : std::char_traits<CT>::length(pT);      return 0 == pT ? 0 : ( int ) std::basic_string <
1240               CT > ::traits_type::length( pT );
1241        //      return 0 == pT ? 0 : std::char_traits<CT>::length(pT);
1242  }  }
1243  inline SS_NOTHROW int sslen(const std::string& s)  inline SS_NOTHROW int sslen( const std::string & s )
1244  {  {
1245          return s.length();      return static_cast < int >( s.length() );
1246  }  }
1247  inline SS_NOTHROW int sslen(const std::wstring& s)  inline SS_NOTHROW int sslen( const std::wstring & s )
1248  {  {
1249          return s.length();      return static_cast < int >( s.length() );
1250  }  }
1251    
   
1252  // -----------------------------------------------------------------------------  // -----------------------------------------------------------------------------
1253  // ssasn: assignment functions -- assign "sSrc" to "sDst"  // sstolower/sstoupper -- convert characters to upper/lower case
1254  // -----------------------------------------------------------------------------  // -----------------------------------------------------------------------------
1255  typedef std::string::size_type          SS_SIZETYPE; // just for shorthand, really  template < typename CT >
1256  typedef std::string::pointer            SS_PTRTYPE;    inline CT sstolower( const CT & t, const std::locale & loc = std::locale() )
 typedef std::wstring::size_type         SW_SIZETYPE;  
 typedef std::wstring::pointer           SW_PTRTYPE;    
   
 inline void     ssasn(std::string& sDst, const std::string& sSrc)  
 {  
         if ( sDst.c_str() != sSrc.c_str() )  
         {  
                 sDst.erase();  
                 sDst.assign(SSREF(sSrc));  
         }  
 }  
 inline void     ssasn(std::string& sDst, PCSTR pA)  
 {  
         // Watch out for NULLs, as always.  
   
         if ( 0 == pA )  
         {  
                 sDst.erase();  
         }  
   
         // If pA actually points to part of sDst, we must NOT erase(), but  
         // rather take a substring  
   
         else if ( pA >= sDst.c_str() && pA <= sDst.c_str() + sDst.size() )  
         {  
                 sDst =sDst.substr(static_cast<SS_SIZETYPE>(pA-sDst.c_str()));  
         }  
   
         // Otherwise (most cases) apply the assignment bug fix, if applicable  
         // and do the assignment  
   
         else  
         {  
                 Q172398(sDst);  
                 sDst.assign(pA);  
         }  
 }  
 inline void     ssasn(std::string& sDst, const std::wstring& sSrc)  
1257  {  {
1258  #ifdef SS_ANSI      return std::tolower < CT > ( t, loc );
         int nLen        = sSrc.size();  
         sDst.resize(0);  
         sDst.resize(nLen);  
         StdCodeCvt(const_cast<SS_PTRTYPE>(sDst.data()), sSrc.c_str(), nLen);  
 #else  
         SSCVT;  
         sDst.assign(SSW2CA(sSrc.c_str()));  
 #endif  
1259  }  }
1260  inline void     ssasn(std::string& sDst, PCWSTR pW)  
1261    template < typename CT >
1262    inline CT sstoupper( const CT & t, const std::locale & loc = std::locale() )
1263  {  {
1264  #ifdef SS_ANSI      return std::toupper < CT > ( t, loc );
         int nLen        = sslen(pW);  
         sDst.resize(0);  
         sDst.resize(nLen);  
         StdCodeCvt(const_cast<SS_PTRTYPE>(sDst.data()), pW, nLen);  
 #else  
         SSCVT;  
         sDst.assign(pW ? SSW2CA(pW) : "");  
 #endif  
 }  
 inline void ssasn(std::string& sDst, const int nNull)  
 {  
         UNUSED(nNull);  
         ASSERT(nNull==0);  
         sDst.assign("");  
 }        
 inline void     ssasn(std::wstring& sDst, const std::wstring& sSrc)  
 {  
         if ( sDst.c_str() != sSrc.c_str() )  
         {  
                 sDst.erase();  
                 sDst.assign(SSREF(sSrc));  
         }  
 }  
 inline void     ssasn(std::wstring& sDst, PCWSTR pW)  
 {  
         // Watch out for NULLs, as always.  
   
         if ( 0 == pW )  
         {  
                 sDst.erase();  
         }  
   
         // If pW actually points to part of sDst, we must NOT erase(), but  
         // rather take a substring  
   
         else if ( pW >= sDst.c_str() && pW <= sDst.c_str() + sDst.size() )  
         {  
                 sDst = sDst.substr(static_cast<SW_SIZETYPE>(pW-sDst.c_str()));  
         }  
   
         // Otherwise (most cases) apply the assignment bug fix, if applicable  
         // and do the assignment  
   
         else  
         {  
                 Q172398(sDst);  
                 sDst.assign(pW);  
         }  
1265  }  }
1266  #undef StrSizeType  
1267  inline void     ssasn(std::wstring& sDst, const std::string& sSrc)  // -----------------------------------------------------------------------------
1268  {  // ssasn: assignment functions -- assign "sSrc" to "sDst"
1269  #ifdef SS_ANSI  // -----------------------------------------------------------------------------
1270          int nLen        = sSrc.size();  typedef std::string::size_type SS_SIZETYPE;     // just for shorthand, really
1271          sDst.resize(0);  typedef std::string::pointer SS_PTRTYPE;
1272          sDst.resize(nLen);  typedef std::wstring::size_type SW_SIZETYPE;
1273          StdCodeCvt(const_cast<SW_PTRTYPE>(sDst.data()), sSrc.c_str(), nLen);  typedef std::wstring::pointer SW_PTRTYPE;
1274    
1275    inline void ssasn( std::string & sDst, const std::string & sSrc )
1276    {
1277        if ( sDst.c_str() != sSrc.c_str() ) {
1278            sDst.erase();
1279            sDst.assign( SSREF( sSrc ) );
1280        }
1281    }
1282    inline void ssasn( std::string & sDst, PCSTR pA )
1283    {
1284        // Watch out for NULLs, as always.
1285        
1286        if ( 0 == pA ) {
1287            sDst.erase();
1288        }
1289        
1290        // If pA actually points to part of sDst, we must NOT erase(), but
1291        // rather take a substring
1292        
1293        else if ( pA >= sDst.c_str() && pA <= sDst.c_str() + sDst.size() ) {
1294            sDst = sDst.substr( static_cast < SS_SIZETYPE > ( pA - sDst.c_str() ) );
1295        }
1296        
1297        // Otherwise (most cases) apply the assignment bug fix, if applicable
1298        // and do the assignment
1299        
1300        else {
1301            Q172398( sDst );
1302            sDst.assign( pA );
1303        }
1304    }
1305    inline void ssasn( std::string & sDst, const std::wstring & sSrc )
1306    {
1307        if ( sSrc.empty() ) {
1308            sDst.erase();
1309        } else {
1310            int nDst = static_cast < int >( sSrc.size() );
1311            
1312            // In MBCS builds, pad the buffer to account for the possibility of
1313            // some 3 byte characters.  Not perfect but should get most cases.
1314            
1315    #ifdef SS_MBCS
1316            
1317            nDst = static_cast < int >( static_cast < double >( nDst ) * 1.3 );
1318    #endif
1319            
1320            sDst.resize( nDst + 1 );
1321            PCSTR szCvt =
1322                StdCodeCvt( const_cast < SS_PTRTYPE > ( sDst.data() ), nDst,
1323                            sSrc.c_str(), static_cast < int >( sSrc.size() ) );
1324                            
1325            // In MBCS builds, we don't know how long the destination string will be.
1326            
1327    #ifdef SS_MBCS
1328            
1329            sDst.resize( sslen( szCvt ) );
1330  #else  #else
1331          SSCVT;          
1332          sDst.assign(SSA2CW(sSrc.c_str()));  szCvt;
1333  #endif          sDst.resize( sSrc.size() );
1334  }  #endif
1335  inline void     ssasn(std::wstring& sDst, PCSTR pA)          
1336  {      }
1337  #ifdef SS_ANSI  }
1338          int nLen        = sslen(pA);  inline void ssasn( std::string & sDst, PCWSTR pW )
1339          sDst.resize(0);  {
1340          sDst.resize(nLen);      int nSrc = sslen( pW );
1341          StdCodeCvt(const_cast<SW_PTRTYPE>(sDst.data()), pA, nLen);      if ( nSrc > 0 ) {
1342            int nSrc = sslen( pW );
1343            int nDst = nSrc;
1344            
1345            // In MBCS builds, pad the buffer to account for the possibility of
1346            // some 3 byte characters.  Not perfect but should get most cases.
1347            
1348    #ifdef SS_MBCS
1349            
1350            nDst = static_cast < int >( static_cast < double >( nDst ) * 1.3 );
1351    #endif
1352            
1353            sDst.resize( nDst + 1 );
1354            PCSTR szCvt =
1355                StdCodeCvt( const_cast < SS_PTRTYPE > ( sDst.data() ), nDst,
1356                            pW, nSrc );
1357                            
1358            // In MBCS builds, we don't know how long the destination string will be.
1359            
1360    #ifdef SS_MBCS
1361            
1362            sDst.resize( sslen( szCvt ) );
1363  #else  #else
1364          SSCVT;          
1365          sDst.assign(pA ? SSA2CW(pA) : L"");  sDst.resize( nDst );
1366  #endif          szCvt;
1367    #endif
1368            
1369        } else {
1370            sDst.erase();
1371        }
1372    }
1373    inline void ssasn( std::string & sDst, const int nNull )
1374    {
1375        UNUSED( nNull );
1376        ASSERT( nNull == 0 );
1377        sDst.assign( "" );
1378    }
1379    inline void ssasn( std::wstring & sDst, const std::wstring & sSrc )
1380    {
1381        if ( sDst.c_str() != sSrc.c_str() ) {
1382            sDst.erase();
1383            sDst.assign( SSREF( sSrc ) );
1384        }
1385    }
1386    inline void ssasn( std::wstring & sDst, PCWSTR pW )
1387    {
1388        // Watch out for NULLs, as always.
1389        
1390        if ( 0 == pW ) {
1391            sDst.erase();
1392        }
1393        
1394        // If pW actually points to part of sDst, we must NOT erase(), but
1395        // rather take a substring
1396        
1397        else if ( pW >= sDst.c_str() && pW <= sDst.c_str() + sDst.size() ) {
1398            sDst = sDst.substr( static_cast < SW_SIZETYPE > ( pW - sDst.c_str() ) );
1399        }
1400        
1401        // Otherwise (most cases) apply the assignment bug fix, if applicable
1402        // and do the assignment
1403        
1404        else {
1405            Q172398( sDst );
1406            sDst.assign( pW );
1407        }
1408  }  }
1409  inline void ssasn(std::wstring& sDst, const int nNull)  
1410    #undef StrSizeType
1411    inline void ssasn( std::wstring & sDst, const std::string & sSrc )
1412  {  {
1413          UNUSED(nNull);      if ( sSrc.empty() ) {
1414          ASSERT(nNull==0);          sDst.erase();
1415          sDst.assign(L"");      } else {
1416            int nSrc = static_cast < int >( sSrc.size() );
1417            int nDst = nSrc;
1418            
1419            sDst.resize( nSrc + 1 );
1420            PCWSTR szCvt =
1421                StdCodeCvt( const_cast < SW_PTRTYPE > ( sDst.data() ), nDst,
1422                            sSrc.c_str(), nSrc );
1423                            
1424            sDst.resize( sslen( szCvt ) );
1425        }
1426    }
1427    inline void ssasn( std::wstring & sDst, PCSTR pA )
1428    {
1429        int nSrc = sslen( pA );
1430        
1431        if ( 0 == nSrc ) {
1432            sDst.erase();
1433        } else {
1434            int nDst = nSrc;
1435            sDst.resize( nDst + 1 );
1436            PCWSTR szCvt =
1437                StdCodeCvt( const_cast < SW_PTRTYPE > ( sDst.data() ), nDst, pA,
1438                            nSrc );
1439                            
1440            sDst.resize( sslen( szCvt ) );
1441        }
1442    }
1443    inline void ssasn( std::wstring & sDst, const int nNull )
1444    {
1445        UNUSED( nNull );
1446        ASSERT( nNull == 0 );
1447        sDst.assign( L"" );
1448  }  }
1449    
1450    
1451  // -----------------------------------------------------------------------------  // -----------------------------------------------------------------------------
1452  // ssadd: string object concatenation -- add second argument to first  // ssadd: string object concatenation -- add second argument to first
1453  // -----------------------------------------------------------------------------  // -----------------------------------------------------------------------------
1454  inline void     ssadd(std::string& sDst, const std::wstring& sSrc)  inline void ssadd( std::string & sDst, const std::wstring & sSrc )
1455  {  {
1456  #ifdef SS_ANSI      int nSrc = static_cast < int >( sSrc.size() );
1457          int nLen        = sSrc.size();      
1458          sDst.resize(sDst.size() + nLen);      if ( nSrc > 0 ) {
1459          StdCodeCvt(const_cast<SS_PTRTYPE>(sDst.data()+nLen), sSrc.c_str(), nLen);          int nDst = static_cast < int >( sDst.size() );
1460            int nAdd = nSrc;
1461            
1462            // In MBCS builds, pad the buffer to account for the possibility of
1463            // some 3 byte characters.  Not perfect but should get most cases.
1464            
1465    #ifdef SS_MBCS
1466            
1467            nAdd = static_cast < int >( static_cast < double >( nAdd ) * 1.3 );
1468    #endif
1469            
1470            sDst.resize( nDst + nAdd + 1 );
1471            PCSTR szCvt =
1472                StdCodeCvt( const_cast < SS_PTRTYPE > ( sDst.data() + nDst ),
1473                            nAdd, sSrc.c_str(), nSrc );
1474                            
1475    #ifdef SS_MBCS
1476                            
1477            sDst.resize( nDst + sslen( szCvt ) );
1478  #else  #else
1479          SSCVT;          
1480          sDst.append(SSW2CA(sSrc.c_str()));  sDst.resize( nDst + nAdd );
1481  #endif          szCvt;
1482    #endif
1483            
1484        }
1485    }
1486    inline void ssadd( std::string & sDst, const std::string & sSrc )
1487    {
1488        sDst += sSrc;
1489    }
1490    inline void ssadd( std::string & sDst, PCWSTR pW )
1491    {
1492        int nSrc = sslen( pW );
1493        if ( nSrc > 0 ) {
1494            int nDst = static_cast < int >( sDst.size() );
1495            int nAdd = nSrc;
1496            
1497    #ifdef SS_MBCS
1498            
1499            nAdd = static_cast < int >( static_cast < double >( nAdd ) * 1.3 );
1500    #endif
1501            
1502            sDst.resize( nDst + nAdd + 1 );
1503            PCSTR szCvt =
1504                StdCodeCvt( const_cast < SS_PTRTYPE > ( sDst.data() + nDst ),
1505                            nAdd, pW, nSrc );
1506                            
1507    #ifdef SS_MBCS
1508                            
1509            sDst.resize( nDst + sslen( szCvt ) );
1510    #else
1511            
1512    sDst.resize( nDst + nSrc );
1513            szCvt;
1514    #endif
1515            
1516        }
1517    }
1518    inline void ssadd( std::string & sDst, PCSTR pA )
1519    {
1520        if ( pA ) {
1521            // If the string being added is our internal string or a part of our
1522            // internal string, then we must NOT do any reallocation without
1523            // first copying that string to another object (since we're using a
1524            // direct pointer)
1525            
1526            if ( pA >= sDst.c_str() && pA <= sDst.c_str() + sDst.length() ) {
1527                if ( sDst.capacity() <= sDst.size() + sslen( pA ) )
1528                    sDst.append( std::string( pA ) );
1529                else
1530                    sDst.append( pA );
1531            } else {
1532                sDst.append( pA );
1533            }
1534        }
1535    }
1536    inline void ssadd( std::wstring & sDst, const std::wstring & sSrc )
1537    {
1538        sDst += sSrc;
1539    }
1540    inline void ssadd( std::wstring & sDst, const std::string & sSrc )
1541    {
1542        if ( !sSrc.empty() ) {
1543            int nSrc = static_cast < int >( sSrc.size() );
1544            int nDst = static_cast < int >( sDst.size() );
1545            
1546            sDst.resize( nDst + nSrc + 1 );
1547            PCWSTR szCvt =
1548                StdCodeCvt( const_cast < SW_PTRTYPE > ( sDst.data() + nDst ),
1549                            nSrc, sSrc.c_str(), nSrc + 1 );
1550                            
1551    #ifdef SS_MBCS
1552                            
1553            sDst.resize( nDst + sslen( szCvt ) );
1554    #else
1555            
1556    sDst.resize( nDst + nSrc );
1557            szCvt;
1558    #endif
1559            
1560        }
1561    }
1562    inline void ssadd( std::wstring & sDst, PCSTR pA )
1563    {
1564        int nSrc = sslen( pA );
1565        
1566        if ( nSrc > 0 ) {
1567            int nDst = static_cast < int >( sDst.size() );
1568            
1569            sDst.resize( nDst + nSrc + 1 );
1570            PCWSTR szCvt =
1571                StdCodeCvt( const_cast < SW_PTRTYPE > ( sDst.data() + nDst ),
1572                            nSrc, pA, nSrc + 1 );
1573                            
1574    #ifdef SS_MBCS
1575                            
1576            sDst.resize( nDst + sslen( szCvt ) );
1577    #else
1578            
1579            sDst.resize( nDst + nSrc );
1580            szCvt;
1581    #endif
1582            
1583        }
1584    }
1585    inline void ssadd( std::wstring & sDst, PCWSTR pW )
1586    {
1587        if ( pW ) {
1588            // If the string being added is our internal string or a part of our
1589            // internal string, then we must NOT do any reallocation without
1590            // first copying that string to another object (since we're using a
1591            // direct pointer)
1592            
1593            if ( pW >= sDst.c_str() && pW <= sDst.c_str() + sDst.length() ) {
1594                if ( sDst.capacity() <= sDst.size() + sslen( pW ) )
1595                    sDst.append( std::wstring( pW ) );
1596                else
1597                    sDst.append( pW );
1598            } else {
1599                sDst.append( pW );
1600            }
1601        }
1602    }
1603    
1604    
1605    // -----------------------------------------------------------------------------
1606    // sscmp: comparison (case sensitive, not affected by locale)
1607    // -----------------------------------------------------------------------------
1608    template < typename CT >
1609    inline int sscmp( const CT * pA1, const CT * pA2 )
1610    {
1611        CT f;
1612        CT l;
1613        
1614        do {
1615            f = *( pA1++ );
1616            l = *( pA2++ );
1617        } while ( ( f ) && ( f == l ) );
1618        
1619        return ( int ) ( f - l );
1620    }
1621    
1622    // -----------------------------------------------------------------------------
1623    // ssicmp: comparison (case INsensitive, not affected by locale)
1624    // -----------------------------------------------------------------------------
1625    template < typename CT >
1626    inline int ssicmp( const CT * pA1, const CT * pA2 )
1627    {
1628        // Using the "C" locale = "not affected by locale"
1629        
1630        std::locale loc = std::locale::classic();
1631        const std::ctype < CT > &ct = SS_USE_FACET( loc, std::ctype < CT > );
1632        CT f;
1633        CT l;
1634        
1635        do {
1636            f = ct.tolower( *( pA1++ ) );
1637            l = ct.tolower( *( pA2++ ) );
1638        } while ( ( f ) && ( f == l ) );
1639        
1640        return ( int ) ( f - l );
1641  }  }
1642  inline void     ssadd(std::string& sDst, const std::string& sSrc)  
1643  {  // -----------------------------------------------------------------------------
1644          sDst.append(sSrc.c_str());  // ssupr/sslwr: Uppercase/Lowercase conversion functions
1645    // -----------------------------------------------------------------------------
1646    
1647    template < typename CT >
1648    inline void sslwr( CT * pT, size_t nLen, const std::locale & loc =
1649                           std::locale() )
1650    {
1651        SS_USE_FACET( loc, std::ctype < CT > ).tolower( pT, pT + nLen );
1652  }  }
1653  inline void     ssadd(std::string& sDst, PCWSTR pW)  template < typename CT >
1654    inline void ssupr( CT * pT, size_t nLen, const std::locale & loc =
1655                           std::locale() )
1656  {  {
1657  #ifdef SS_ANSI      SS_USE_FACET( loc, std::ctype < CT > ).toupper( pT, pT + nLen );
1658          int nLen        = sslen(pW);  }
1659          sDst.resize(sDst.size() + nLen);  
1660          StdCodeCvt(const_cast<SS_PTRTYPE>(sDst.data()+nLen), pW, nLen);  // -----------------------------------------------------------------------------
1661  #else  // vsprintf/vswprintf or _vsnprintf/_vsnwprintf equivalents.  In standard
1662          SSCVT;  // builds we can't use _vsnprintf/_vsnwsprintf because they're MS extensions.
1663          if ( 0 != pW )  //
1664                  sDst.append(SSW2CA(pW));  // -----------------------------------------------------------------------------
1665    // Borland's headers put some ANSI "C" functions in the 'std' namespace.
1666    // Promote them to the global namespace so we can use them here.
1667    
1668    #if defined(__BORLANDC__)
1669    using std::vsprintf;
1670    using std::vswprintf;
1671  #endif  #endif
1672    
1673    // GNU is supposed to have vsnprintf and vsnwprintf.  But only the newer
1674    // distributions do.
1675    
1676    #if defined(__GNUC__)
1677    
1678    inline int ssvsprintf( PSTR pA, size_t nCount, PCSTR pFmtA, va_list vl )
1679    {
1680        return vsnprintf( pA, nCount, pFmtA, vl );
1681  }  }
1682  inline void     ssadd(std::string& sDst, PCSTR pA)  inline int ssvsprintf( PWSTR pW, size_t nCount, PCWSTR pFmtW, va_list vl )
1683  {  {
1684          if ( pA )      return vswprintf( pW, nCount, pFmtW, vl );
                 sDst.append(pA);  
1685  }  }
1686  inline void     ssadd(std::wstring& sDst, const std::wstring& sSrc)  
1687    // Microsofties can use
1688    #elif defined(_MSC_VER) && !defined(SS_ANSI)
1689    
1690    inline int ssnprintf( PSTR pA, size_t nCount, PCSTR pFmtA, va_list vl )
1691  {  {
1692          sDst.append(sSrc.c_str());      return _vsnprintf( pA, nCount, pFmtA, vl );
1693  }  }
1694  inline void     ssadd(std::wstring& sDst, const std::string& sSrc)  inline int ssnprintf( PWSTR pW, size_t nCount, PCWSTR pFmtW, va_list vl )
1695  {  {
1696  #ifdef SS_ANSI      return _vsnwprintf( pW, nCount, pFmtW, vl );
         int nLen        = sSrc.size();  
         sDst.resize(sDst.size() + nLen);  
         StdCodeCvt(const_cast<SW_PTRTYPE>(sDst.data()+nLen), sSrc.c_str(), nLen);  
 #else  
         SSCVT;  
         sDst.append(SSA2CW(sSrc.c_str()));  
 #endif  
1697  }  }
1698  inline void     ssadd(std::wstring& sDst, PCSTR pA)  
1699    #elif !defined (SS_DANGEROUS_FORMAT)
1700    
1701    // GOT COMPILER PROBLEMS HERE?
1702    // ---------------------------
1703    // Does your compiler choke on one or more of the following 2 functions?  It
1704    // probably means that you don't have have either vsnprintf or vsnwprintf in
1705    // your version of the CRT.  This is understandable since neither is an ANSI
1706    // "C" function.  However it still leaves you in a dilemma.  In order to make
1707    // this code build, you're going to have to to use some non-length-checked
1708    // formatting functions that every CRT has:  vsprintf and vswprintf.
1709    //
1710    // This is very dangerous.  With the proper erroneous (or malicious) code, it
1711    // can lead to buffer overlows and crashing your PC.  Use at your own risk
1712    // In order to use them, just #define SS_DANGEROUS_FORMAT at the top of
1713    // this file.
1714    //
1715    // Even THEN you might not be all the way home due to some non-conforming
1716    // distributions.  More on this in the comments below.
1717    
1718    inline int ssnprintf( PSTR pA, size_t nCount, PCSTR pFmtA, va_list vl )
1719  {  {
1720  #ifdef SS_ANSI      return vsnprintf( pA, nCount, pFmtA, vl );
         int nLen        = sslen(pA);  
         sDst.resize(sDst.size() + nLen);  
         StdCodeCvt(const_cast<SW_PTRTYPE>(sDst.data()+nLen), pA, nLen);  
 #else  
         SSCVT;  
         if ( 0 != pA )  
                 sDst.append(SSA2CW(pA));  
 #endif  
1721  }  }
1722  inline void     ssadd(std::wstring& sDst, PCWSTR pW)  inline int ssnprintf( PWSTR pW, size_t nCount, PCWSTR pFmtW, va_list vl )
1723  {  {
1724          if ( pW )      return vsnwprintf( pW, nCount, pFmtW, vl );
                 sDst.append(pW);  
1725  }  }
1726    
1727    #else
1728    
1729    inline int ssvsprintf( PSTR pA, size_t /*nCount */ , PCSTR pFmtA, va_list vl )
1730    {
1731        return vsprintf( pA, pFmtA, vl );
1732    }
1733    
1734    inline int ssvsprintf( PWSTR pW, size_t nCount, PCWSTR pFmtW, va_list vl )
1735    {
1736        // JMO: Some distributions of the "C" have a version of vswprintf that
1737        // takes 3 arguments (e.g. Microsoft, Borland, GNU).  Others have a
1738        // version which takes 4 arguments (an extra "count" argument in the
1739        // second position.  The best stab I can take at this so far is that if
1740        // you are NOT running with MS, Borland, or GNU, then I'll assume you
1741        // have the version that takes 4 arguments.
1742        //
1743        // I'm sure that these checks don't catch every platform correctly so if
1744        // you get compiler errors on one of the lines immediately below, it's
1745        // probably because your implemntation takes a different number of
1746        // arguments.  You can comment out the offending line (and use the
1747        // alternate version) or you can figure out what compiler flag to check
1748        // and add that preprocessor check in.  Regardless, if you get an error
1749        // on these lines, I'd sure like to hear from you about it.
1750        //
1751        // Thanks to Ronny Schulz for the SGI-specific checks here.
1752    
1753        //      #if !defined(__MWERKS__) && !defined(__SUNPRO_CC_COMPAT) && !defined(__SUNPRO_CC)
1754    #if    !defined(_MSC_VER) \
1755            && !defined (__BORLANDC__) \
1756            && !defined(__GNUC__) \
1757            && !defined(__sgi)
1758    
1759        return vswprintf( pW, nCount, pFmtW, vl );
1760    
1761        // suddenly with the current SGI 7.3 compiler there is no such function as
1762        // vswprintf and the substitute needs explicit casts to compile
1763    
1764    #elif defined(__sgi)
1765    
1766    nCount;
1767    return vsprintf( ( char * ) pW, ( char * ) pFmtW, vl );
1768    
1769    #else
1770    
1771    nCount;
1772    return vswprintf( pW, pFmtW, vl );
1773    
 // -----------------------------------------------------------------------------  
 // ssicmp: comparison (case insensitive )  
 // -----------------------------------------------------------------------------  
 #ifdef SS_ANSI  
         template<typename CT>  
         inline int ssicmp(const CT* pA1, const CT* pA2)  
         {  
                 std::locale loc;  
                 const std::ctype<CT>& ct = SS_USE_FACET(loc, std::ctype<CT>);  
                 CT f;  
                 CT l;  
   
             do  
                         {  
                                 f = ct.tolower(*(pA1++));  
                                 l = ct.tolower(*(pA2++));  
             } while ( (f) && (f == l) );  
   
         return (int)(f - l);  
         }  
 #else  
         #ifdef _MBCS  
                 inline long sscmp(PCSTR pA1, PCSTR pA2)  
                 {  
                         return _mbscmp((PCUSTR)pA1, (PCUSTR)pA2);  
                 }  
                 inline long ssicmp(PCSTR pA1, PCSTR pA2)  
                 {  
                         return _mbsicmp((PCUSTR)pA1, (PCUSTR)pA2);  
                 }  
         #else  
                 inline long sscmp(PCSTR pA1, PCSTR pA2)  
                 {  
                         return strcmp(pA1, pA2);  
                 }  
                 inline long ssicmp(PCSTR pA1, PCSTR pA2)  
                 {  
                         return _stricmp(pA1, pA2);  
                 }  
         #endif  
         inline long sscmp(PCWSTR pW1, PCWSTR pW2)  
         {  
                 return wcscmp(pW1, pW2);  
         }  
         inline long ssicmp(PCWSTR pW1, PCWSTR pW2)  
         {  
                 return _wcsicmp(pW1, pW2);  
         }  
1774  #endif  #endif
1775    
1776  // -----------------------------------------------------------------------------  }
 // ssupr/sslwr: Uppercase/Lowercase conversion functions  
 // -----------------------------------------------------------------------------  
 #ifdef SS_ANSI  
         template<typename CT>  
         inline void sslwr(CT* pT, size_t nLen)  
         {  
                 SS_USE_FACET(std::locale(), std::ctype<CT>).tolower(pT, pT+nLen);  
         }  
         template<typename CT>  
         inline void ssupr(CT* pT, size_t nLen)  
         {  
                 SS_USE_FACET(std::locale(), std::ctype<CT>).toupper(pT, pT+nLen);  
         }  
 #else  // #else we must be on Win32  
         #ifdef _MBCS  
                 inline void     ssupr(PSTR pA, size_t /*nLen*/)  
                 {  
                         _mbsupr((PUSTR)pA);  
                 }  
                 inline void     sslwr(PSTR pA, size_t /*nLen*/)  
                 {  
                         _mbslwr((PUSTR)pA);  
                 }  
         #else  
                 inline void     ssupr(PSTR pA, size_t /*nLen*/)  
                 {  
                         _strupr(pA);  
                 }  
                 inline void     sslwr(PSTR pA, size_t /*nLen*/)  
                 {  
                         _strlwr(pA);  
                 }  
         #endif  
         inline void     ssupr(PWSTR pW, size_t /*nLen*/)          
         {  
                 _wcsupr(pW);  
         }  
         inline void     sslwr(PWSTR pW, size_t /*nLen*/)          
         {  
                 _wcslwr(pW);  
         }  
 #endif // #ifdef SS_ANSI  
1777    
 // -----------------------------------------------------------------------------  
 //  vsprintf/vswprintf or _vsnprintf/_vsnwprintf equivalents.  In standard  
 //  builds we can't use _vsnprintf/_vsnwsprintf because they're MS extensions.  
 // -----------------------------------------------------------------------------  
 #ifdef SS_ANSI  
         inline int ssvsprintf(PSTR pA, size_t /*nCount*/, PCSTR pFmtA, va_list vl)  
         {  
                 return vsprintf(pA, pFmtA, vl);  
         }  
         inline int ssvsprintf(PWSTR pW, size_t nCount, PCWSTR pFmtW, va_list vl)  
         {  
                 // JMO: It is beginning to seem like Microsoft Visual C++ is the only  
                 // CRT distribution whose version of vswprintf takes THREE arguments.  
                 // All others seem to take FOUR arguments.  Therefore instead of  
                 // checking for every possible distro here, I'll assume that unless  
                 // I am running with Microsoft's CRT, then vswprintf takes four  
                 // arguments.  If you get a compilation error here, then you can just  
                 // change this code to call the three-argument version.  
 //      #if !defined(__MWERKS__) && !defined(__SUNPRO_CC_COMPAT) && !defined(__SUNPRO_CC)  
         #ifndef _MSC_VER  
                 return vswprintf(pW, nCount, pFmtW, vl);  
         #else  
                 nCount;  
                 return vswprintf(pW, pFmtW, vl);  
         #endif  
         }  
 #else  
         inline int      ssnprintf(PSTR pA, size_t nCount, PCSTR pFmtA, va_list vl)  
         {  
                 return _vsnprintf(pA, nCount, pFmtA, vl);  
         }  
         inline int      ssnprintf(PWSTR pW, size_t nCount, PCWSTR pFmtW, va_list vl)  
         {  
                 return _vsnwprintf(pW, nCount, pFmtW, vl);  
         }  
1778  #endif  #endif
1779    
1780    
1781    
1782  // -----------------------------------------------------------------------------  // -----------------------------------------------------------------------------
1783  // ssload: Type safe, overloaded ::LoadString wrappers  // ssload: Type safe, overloaded ::LoadString wrappers
1784  // 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
1785  // thinking that with the message facet, there might eventually be one  // thinking that with the message facet, there might eventually be one
1786  // -----------------------------------------------------------------------------  // -----------------------------------------------------------------------------
1787  #ifdef SS_ANSI  #if defined (SS_WIN32) && !defined(SS_ANSI)
1788  #else  inline int ssload( HMODULE hInst, UINT uId, PSTR pBuf, int nMax )
1789          inline int ssload(HMODULE hInst, UINT uId, PSTR pBuf, int nMax)  {
1790          {      return ::LoadStringA( hInst, uId, pBuf, nMax );
1791                  return ::LoadStringA(hInst, uId, pBuf, nMax);  }
1792          }  inline int ssload( HMODULE hInst, UINT uId, PWSTR pBuf, int nMax )
1793          inline int ssload(HMODULE hInst, UINT uId, PWSTR pBuf, int nMax)  {
1794          {      return ::LoadStringW( hInst, uId, pBuf, nMax );
1795                  return ::LoadStringW(hInst, uId, pBuf, nMax);  }
         }  
1796  #endif  #endif
1797    
1798    
1799  // -----------------------------------------------------------------------------  // -----------------------------------------------------------------------------
1800  // sscoll/ssicoll: Collation wrappers  // sscoll/ssicoll: Collation wrappers
1801    //              Note -- with MSVC I have reversed the arguments order here because the
1802    //              functions appear to return the opposite of what they should
1803  // -----------------------------------------------------------------------------  // -----------------------------------------------------------------------------
1804  #ifdef SS_ANSI  template < typename CT >
1805          template <typename CT>  inline int sscoll( const CT * sz1, int nLen1, const CT * sz2, int nLen2 )
1806          inline int sscoll(const CT* sz1, int nLen1, const CT* sz2, int nLen2)  {
1807          {      const std::collate < CT > &coll =
1808                  const std::collate<CT>& coll =          SS_USE_FACET( std::locale(), std::collate < CT > );
1809                          SS_USE_FACET(std::locale(), std::collate<CT>);          
1810                  return coll.compare(sz1, sz1+nLen1, sz2, sz2+nLen2);      return coll.compare( sz2, sz2 + nLen2, sz1, sz1 + nLen1 );
1811          }  }
1812          template <typename CT>  template < typename CT >
1813          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 )
1814          {  {
1815                  const std::locale loc;      const std::locale loc;
1816                  const std::collate<CT>& coll = SS_USE_FACET(loc, std::collate<CT>);      const std::collate < CT > &coll = SS_USE_FACET( loc, std::collate < CT > );
1817        
1818                  // Some implementations seem to have trouble using the collate<>      // Some implementations seem to have trouble using the collate<>
1819                  // facet typedefs so we'll just default to basic_string and hope      // facet typedefs so we'll just default to basic_string and hope
1820                  // that's what the collate facet uses (which it generally should)      // that's what the collate facet uses (which it generally should)
1821        
1822  //              std::collate<CT>::string_type s1(sz1);      //      std::collate<CT>::string_type s1(sz1);
1823  //              std::collate<CT>::string_type s2(sz2);      //      std::collate<CT>::string_type s2(sz2);
1824                  std::basic_string<CT> s1(sz1);      const std::basic_string < CT > sEmpty;
1825                  std::basic_string<CT> s2(sz2);      std::basic_string < CT > s1( sz1 ? sz1 : sEmpty.c_str() );
1826        std::basic_string < CT > s2( sz2 ? sz2 : sEmpty.c_str() );
1827                  sslwr(const_cast<CT*>(s1.c_str()), nLen1);      
1828                  sslwr(const_cast<CT*>(s2.c_str()), nLen2);      sslwr( const_cast < CT * >( s1.c_str() ), nLen1, loc );
1829                  return coll.compare(s1.c_str(), s1.c_str()+nLen1,      sslwr( const_cast < CT * >( s2.c_str() ), nLen2, loc );
1830                                                          s2.c_str(), s2.c_str()+nLen2);      return coll.compare( s2.c_str(), s2.c_str() + nLen2,
1831          }                           s1.c_str(), s1.c_str() + nLen1 );
1832  #else  }
1833          #ifdef _MBCS  
                 inline int sscoll(PCSTR sz1, int /*nLen1*/, PCSTR sz2, int /*nLen2*/)  
                 {  
                         return _mbscoll((PCUSTR)sz1, (PCUSTR)sz2);  
                 }  
                 inline int ssicoll(PCSTR sz1, int /*nLen1*/, PCSTR sz2, int /*nLen2*/)  
                 {  
                         return _mbsicoll((PCUSTR)sz1, (PCUSTR)sz2);  
                 }  
         #else  
                 inline int sscoll(PCSTR sz1, int /*nLen1*/, PCSTR sz2, int /*nLen2*/)  
                 {  
                         return strcoll(sz1, sz2);  
                 }  
                 inline int ssicoll(PCSTR sz1, int /*nLen1*/, PCSTR sz2, int /*nLen2*/)  
                 {  
                         return _stricoll(sz1, sz2);  
                 }  
         #endif  
         inline int sscoll(PCWSTR sz1, int /*nLen1*/, PCWSTR sz2, int /*nLen2*/)  
         {  
                 return wcscoll(sz1, sz2);  
         }  
         inline int ssicoll(PCWSTR sz1, int /*nLen1*/, PCWSTR sz2, int /*nLen2*/)  
         {  
                 return _wcsicoll(sz1, sz2);  
         }  
 #endif  
1834    
1835    
1836  // -----------------------------------------------------------------------------  // -----------------------------------------------------------------------------
# Line 1211  inline void    ssadd(std::wstring& sDst, PC Line 1838  inline void    ssadd(std::wstring& sDst, PC
1838  // 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
1839  // be one if the message facet gets implemented  // be one if the message facet gets implemented
1840  // -----------------------------------------------------------------------------  // -----------------------------------------------------------------------------
1841  #ifdef SS_ANSI  #if defined (SS_WIN32) && !defined(SS_ANSI)
1842    inline DWORD ssfmtmsg( DWORD dwFlags, LPCVOID pSrc, DWORD dwMsgId,
1843                           DWORD dwLangId, PSTR pBuf, DWORD nSize,
1844                           va_list * vlArgs )
1845    {
1846        return FormatMessageA( dwFlags, pSrc, dwMsgId, dwLangId,
1847                               pBuf, nSize, vlArgs );
1848    }
1849    inline DWORD ssfmtmsg( DWORD dwFlags, LPCVOID pSrc, DWORD dwMsgId,
1850                           DWORD dwLangId, PWSTR pBuf, DWORD nSize,
1851                           va_list * vlArgs )
1852    {
1853        return FormatMessageW( dwFlags, pSrc, dwMsgId, dwLangId,
1854                               pBuf, nSize, vlArgs );
1855    }
1856  #else  #else
         inline DWORD ssfmtmsg(DWORD dwFlags, LPCVOID pSrc, DWORD dwMsgId,  
                                                   DWORD dwLangId, PSTR pBuf, DWORD nSize,  
                                                   va_list* vlArgs)  
         {  
                 return FormatMessageA(dwFlags, pSrc, dwMsgId, dwLangId,  
                                                           pBuf, nSize,vlArgs);  
         }  
         inline DWORD ssfmtmsg(DWORD dwFlags, LPCVOID pSrc, DWORD dwMsgId,  
                                                   DWORD dwLangId, PWSTR pBuf, DWORD nSize,  
                                                   va_list* vlArgs)  
         {  
                 return FormatMessageW(dwFlags, pSrc, dwMsgId, dwLangId,  
                                                           pBuf, nSize,vlArgs);  
         }  
1857  #endif  #endif
1858    
1859    
1860    
1861  // FUNCTION: sscpy.  Copies up to 'nMax' characters from pSrc to pDst.  // FUNCTION: sscpy.  Copies up to 'nMax' characters from pSrc to pDst.
1862  // -----------------------------------------------------------------------------  // -----------------------------------------------------------------------------
1863  // FUNCTION:  sscpy  // FUNCTION:  sscpy
1864  //              inline int sscpy(PSTR pDst, PCSTR pSrc, int nMax=-1);  //              inline int sscpy(PSTR pDst, PCSTR pSrc, int nMax=-1);
1865  //              inline int sscpy(PUSTR pDst,  PCSTR pSrc, int nMax=-1)  //              inline int sscpy(PUSTR pDst,  PCSTR pSrc, int nMax=-1)
1866  //              inline int sscpy(PSTR pDst, PCWSTR pSrc, int nMax=-1);  //              inline int sscpy(PSTR pDst, PCWSTR pSrc, int nMax=-1);
1867  //              inline int sscpy(PWSTR pDst, PCWSTR pSrc, int nMax=-1);  //              inline int sscpy(PWSTR pDst, PCWSTR pSrc, int nMax=-1);
1868  //              inline int sscpy(PWSTR pDst, PCSTR pSrc, int nMax=-1);  //              inline int sscpy(PWSTR pDst, PCSTR pSrc, int nMax=-1);
1869  //  //
1870  // DESCRIPTION:  // DESCRIPTION:
1871  //              This function is very much (but not exactly) like strcpy.  These  //              This function is very much (but not exactly) like strcpy.  These
1872  //              overloads simplify copying one C-style string into another by allowing  //              overloads simplify copying one C-style string into another by allowing
1873  //              the caller to specify two different types of strings if necessary.  //              the caller to specify two different types of strings if necessary.
1874  //  //
1875  //              The strings must NOT overlap  //              The strings must NOT overlap
1876  //  //
1877  //              "Character" is expressed in terms of the destination string, not  //              "Character" is expressed in terms of the destination string, not
1878  //              the source.  If no 'nMax' argument is supplied, then the number of  //              the source.  If no 'nMax' argument is supplied, then the number of
1879  //              characters copied will be sslen(pSrc).  A NULL terminator will  //              characters copied will be sslen(pSrc).  A NULL terminator will
1880  //              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
1881  //              characters.  The return value is the number of characters copied,  //              characters.  The return value is the number of characters copied,
1882  //              not including the NULL terminator.  //              not including the NULL terminator.
1883  //  //
1884  // PARAMETERS:  // PARAMETERS:
1885  //              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
1886  //                         MBCS string (in Win32 builds) or a wide string (wchar_t).  //                         MBCS string (in Win32 builds) or a wide string (wchar_t).
1887  //              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
1888  //              nMax - the maximum number of characters to be copied into szDest.  Note  //              nMax - the maximum number of characters to be copied into szDest.  Note
1889  //                         that this is expressed in whatever a "character" means to pDst.  //                         that this is expressed in whatever a "character" means to pDst.
1890  //                         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
1891  //                         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
1892  //                         large enough to hold least nMaxChars+1 characters.  //                         large enough to hold least nMaxChars+1 characters.
1893  //                         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
1894  //                         the routine to copy all the characters in pSrc, regardless of  //                         the routine to copy all the characters in pSrc, regardless of
1895  //                         how long it is.  //                         how long it is.
1896  //  //
1897  // RETURN VALUE: none  // RETURN VALUE: none
1898  // -----------------------------------------------------------------------------  // -----------------------------------------------------------------------------
1899  template<typename CT1, typename CT2>  template < typename CT1, typename CT2 >
1900  inline int sscpycvt(CT1* pDst, const CT2* pSrc, int nChars)  inline int sscpycvt( CT1 * pDst, const CT2 * pSrc, int nMax )
1901    {
1902        // Note -- we assume pDst is big enough to hold pSrc.  If not, we're in
1903        // big trouble.  No bounds checking.  Caveat emptor.
1904        
1905        int nSrc = sslen( pSrc );
1906        
1907        const CT1 *szCvt = StdCodeCvt( pDst, nMax, pSrc, nSrc );
1908        
1909        // If we're copying the same size characters, then all the "code convert"
1910        // just did was basically memcpy so the #of characters copied is the same
1911        // as the number requested.  I should probably specialize this function
1912        // template to achieve this purpose as it is silly to do a runtime check
1913        // of a fact known at compile time.  I'll get around to it.
1914        
1915        return sslen( szCvt );
1916    }
1917    
1918    inline int sscpycvt( PSTR pDst, PCSTR pSrc, int nMax )
1919  {  {
1920          StdCodeCvt(pDst, pSrc, nChars);      int nCount = nMax;
1921          pDst[SSMAX(nChars, 0)]  = '\0';      for ( ; nCount > 0 && *pSrc; ++pSrc, ++pDst, --nCount )
1922          return nChars;          std::basic_string < char >::traits_type::assign( *pDst, *pSrc );
1923            
1924        *pDst = '\0';
1925        return nMax - nCount;
1926    }
1927    inline int sscpycvt( PWSTR pDst, PCWSTR pSrc, int nMax )
1928    {
1929        int nCount = nMax;
1930        for ( ; nCount > 0 && *pSrc; ++pSrc, ++pDst, --nCount )
1931            std::basic_string < wchar_t >::traits_type::assign( *pDst, *pSrc );
1932            
1933        *pDst = L'\0';
1934        return nMax - nCount;
1935    }
1936    inline int sscpycvt( PWSTR pDst, PCSTR pSrc, int nMax )
1937    {
1938        // Note -- we assume pDst is big enough to hold pSrc.  If not, we're in
1939        // big trouble.  No bounds checking.  Caveat emptor.
1940        
1941        const PWSTR szCvt = StdCodeCvt( pDst, nMax, pSrc, nMax );
1942        return sslen( szCvt );
1943  }  }
1944    
1945  template<typename CT1, typename CT2>  template < typename CT1, typename CT2 >
1946  inline int sscpy(CT1* pDst, const CT2* pSrc, int nMax, int nLen)  inline int sscpy( CT1 * pDst, const CT2 * pSrc, int nMax, int nLen )
1947  {  {
1948          return sscpycvt(pDst, pSrc, SSMIN(nMax, nLen));      return sscpycvt( pDst, pSrc, SSMIN( nMax, nLen ) );
1949  }  }
1950  template<typename CT1, typename CT2>  template < typename CT1, typename CT2 >
1951  inline int sscpy(CT1* pDst, const CT2* pSrc, int nMax)  inline int sscpy( CT1 * pDst, const CT2 * pSrc, int nMax )
1952  {  {
1953          return sscpycvt(pDst, pSrc, SSMIN(nMax, sslen(pSrc)));      return sscpycvt( pDst, pSrc, SSMIN( nMax, sslen( pSrc ) ) );
1954  }  }
1955  template<typename CT1, typename CT2>  template < typename CT1, typename CT2 >
1956  inline int sscpy(CT1* pDst, const CT2* pSrc)  inline int sscpy( CT1 * pDst, const CT2 * pSrc )
1957  {  {
1958          return sscpycvt(pDst, pSrc, sslen(pSrc));      return sscpycvt( pDst, pSrc, sslen( pSrc ) );
1959  }  }
1960  template<typename CT1, typename CT2>  template < typename CT1, typename CT2 >
1961  inline int sscpy(CT1* pDst, const std::basic_string<CT2>& sSrc, int nMax)  inline int sscpy( CT1 * pDst, const std::basic_string < CT2 > &sSrc,
1962                      int nMax )
1963  {  {
1964          return sscpycvt(pDst, sSrc.c_str(), SSMIN(nMax, (int)sSrc.length()));      return sscpycvt( pDst, sSrc.c_str(), SSMIN( nMax, ( int ) sSrc.length() ) );
1965  }  }
1966  template<typename CT1, typename CT2>  template < typename CT1, typename CT2 >
1967  inline int sscpy(CT1* pDst, const std::basic_string<CT2>& sSrc)  inline int sscpy( CT1 * pDst, const std::basic_string < CT2 > &sSrc )
1968  {  {
1969          return sscpycvt(pDst, sSrc.c_str(), (int)sSrc.length());      return sscpycvt( pDst, sSrc.c_str(), ( int ) sSrc.length() );
1970  }  }
1971    
1972  #ifdef SS_INC_COMDEF  #ifdef SS_INC_COMDEF
1973          template<typename CT1>  template < typename CT1 >
1974          inline int sscpy(CT1* pDst, const _bstr_t& bs, int nMax)  inline int sscpy( CT1 * pDst, const _bstr_t & bs, int nMax )
1975          {  {
1976                  return sscpycvt(pDst, static_cast<PCOLESTR>(bs), SSMIN(nMax, (int)bs.length()));      return sscpycvt( pDst, static_cast < PCOLESTR > ( bs ),
1977          }                       SSMIN( nMax, static_cast < int >( bs.length() ) ) );
1978          template<typename CT1>  }
1979          inline int sscpy(CT1* pDst, const _bstr_t& bs)  template < typename CT1 >
1980          {  inline int sscpy( CT1 * pDst, const _bstr_t & bs )
1981                  return sscpy(pDst, bs, bs.length());  {
1982          }      return sscpy( pDst, bs, static_cast < int >( bs.length() ) );
1983    }
1984  #endif  #endif
1985    
1986    
# Line 1321  inline int sscpy(CT1* pDst, const std::b Line 1988  inline int sscpy(CT1* pDst, const std::b
1988  // Functional objects for changing case.  They also let you pass locales  // Functional objects for changing case.  They also let you pass locales
1989  // -----------------------------------------------------------------------------  // -----------------------------------------------------------------------------
1990    
1991  #ifdef SS_ANSI  template < typename CT >
1992          template<typename CT>  struct SSToUpper: public std::binary_function < CT, std::locale, CT >
1993          struct SSToUpper : public std::binary_function<CT, std::locale, CT>  {
1994          {      inline CT operator() ( const CT & t, const std::locale & loc ) const
1995                  inline CT operator()(const CT& t, const std::locale& loc) const      {
1996                  {          return sstoupper < CT > ( t, loc );
1997                          return std::toupper<CT>(t, loc);      }
1998                  }  };
1999          };  template < typename CT >
2000          template<typename CT>  struct SSToLower: public std::binary_function < CT, std::locale, CT >
2001          struct SSToLower : public std::binary_function<CT, std::locale, CT>  {
2002          {      inline CT operator() ( const CT & t, const std::locale & loc ) const
2003                  inline CT operator()(const CT& t, const std::locale& loc) const      {
2004                  {          return sstolower < CT > ( t, loc );
2005                          return std::tolower<CT>(t, loc);      }
2006                  }  };
         };  
 #endif  
2007    
2008  // This struct is used for TrimRight() and TrimLeft() function implementations.  // This struct is used for TrimRight() and TrimLeft() function implementations.
2009  //template<typename CT>  //template<typename CT>
2010  //struct NotSpace : public std::unary_function<CT, bool>  //struct NotSpace : public std::unary_function<CT, bool>
2011  //{  //{
2012  //      const std::locale& loc;  //      const std::locale& loc;
2013  //      inline NotSpace(const std::locale& locArg) : loc(locArg) {}  //      inline NotSpace(const std::locale& locArg) : loc(locArg) {}
2014  //      inline bool operator() (CT t) { return !std::isspace(t, loc); }  //      inline bool operator() (CT t) { return !std::isspace(t, loc); }
2015  //};  //};
2016  template<typename CT>  template < typename CT >
2017  struct NotSpace : public std::unary_function<CT, bool>  struct NotSpace: public std::unary_function < CT, bool >
2018  {  {
2019          const std::locale& loc;      // DINKUMWARE BUG:
2020          NotSpace(const std::locale& locArg) : loc(locArg) {}      // Note -- using std::isspace in a COM DLL gives us access violations
2021        // because it causes the dynamic addition of a function to be called
2022          // DINKUMWARE BUG:      // when the library shuts down.  Unfortunately the list is maintained
2023          // Note -- using std::isspace in a COM DLL gives us access violations      // in DLL memory but the function is in static memory.  So the COM DLL
2024          // because it causes the dynamic addition of a function to be called      // goes away along with the function that was supposed to be called,
2025          // when the library shuts down.  Unfortunately the list is maintained      // and then later when the DLL CRT shuts down it unloads the list and
2026          // in DLL memory but the function is in static memory.  So the COM DLL      // tries to call the long-gone function.
2027          // goes away along with the function that was supposed to be called,      // This is DinkumWare's implementation problem.  If you encounter this
2028          // and then later when the DLL CRT shuts down it unloads the list and      // problem, you may replace the calls here with good old isspace() and
2029          // tries to call the long-gone function.      // iswspace() from the CRT unless they specify SS_ANSI
2030          // This is DinkumWare's implementation problem.  Until then, we will      
2031          // use good old isspace and iswspace from the CRT unless they      const std::locale loc;
2032          // specify SS_ANSI      NotSpace( const std::locale & locArg = std::locale() ) : loc( locArg )
2033  #ifdef SS_ANSI      {}
2034          bool operator() (CT t) const { return !std::isspace(t, loc); }      bool operator() ( CT t ) const
2035  #else      {
2036          bool ssisp(char c) const { return FALSE != ::isspace((int) c); }          return !std::isspace( t, loc );
2037          bool ssisp(wchar_t c) const { return FALSE != ::iswspace((wint_t) c); }      }
         bool operator()(CT t) const  { return !ssisp(t); }  
 #endif  
2038  };  };
2039    
2040    
2041    
2042    
2043  //                      Now we can define the template (finally!)  //                      Now we can define the template (finally!)
2044  // =============================================================================  // =============================================================================
2045  // TEMPLATE: CStdStr  // TEMPLATE: CStdStr
2046  //              template<typename CT> class CStdStr : public std::basic_string<CT>  //              template<typename CT> class CStdStr : public std::basic_string<CT>
2047  //  //
2048  // REMARKS:  // REMARKS:
2049  //              This template derives from basic_string<CT> and adds some MFC CString-  //              This template derives from basic_string<CT> and adds some MFC CString-
2050  //              like functionality  //              like functionality
2051  //  //
2052  //              Basically, this is my attempt to make Standard C++ library strings as  //              Basically, this is my attempt to make Standard C++ library strings as
2053  //              easy to use as the MFC CString class.  //              easy to use as the MFC CString class.
2054  //  //
2055  //              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
2056  //              template argument (CT, the character type) is either char or wchar_t.    //              template argument (CT, the character type) is either char or wchar_t.
2057  // =============================================================================  // =============================================================================
2058    
2059  //#define CStdStr _SS   // avoid compiler warning 4786  //#define CStdStr _SS   // avoid compiler warning 4786
2060    
2061    //    template<typename ARG> ARG& FmtArg(ARG& arg)  { return arg; }
2062    //    PCSTR  FmtArg(const std::string& arg)  { return arg.c_str(); }
2063    //    PCWSTR FmtArg(const std::wstring& arg) { return arg.c_str(); }
2064    
2065    template < typename ARG >
2066    struct FmtArg
2067    {
2068        explicit FmtArg( const ARG & arg ) : a_( arg )
2069        {}
2070        const ARG & operator() () const
2071        {
2072            return a_;
2073        }
2074        const ARG & a_;
2075    private:
2076        FmtArg & operator=( const FmtArg & )
2077        {
2078            return * this;
2079        }
2080    };
2081    
2082  template<typename CT>  template < typename CT >
2083  class CStdStr : public std::basic_string<CT>  class CStdStr: public std::basic_string < CT >
2084  {  {
2085          // Typedefs for shorter names.  Using these names also appears to help          // Typedefs for shorter names.  Using these names also appears to help
2086          // us avoid some ambiguities that otherwise arise on some platforms          // us avoid some ambiguities that otherwise arise on some platforms
2087            
2088          typedef typename std::basic_string<CT>          MYBASE;  // my base class  #define MYBASE std::basic_string<CT>    // my base class
2089          typedef CStdStr<CT>                                                     MYTYPE;  // myself          //typedef typename std::basic_string<CT>                MYBASE;  // my base class
2090          typedef typename MYBASE::const_pointer          PCMYSTR; // PCSTR or PCWSTR          typedef CStdStr < CT > MYTYPE;      // myself
2091          typedef typename MYBASE::pointer                        PMYSTR;  // PSTR or PWSTR          typedef typename MYBASE::const_pointer PCMYSTR;     // PCSTR or PCWSTR
2092          typedef typename MYBASE::iterator                       MYITER;  // my iterator type          typedef typename MYBASE::pointer PMYSTR;    // PSTR or PWSTR
2093          typedef typename MYBASE::const_iterator         MYCITER; // you get the idea...          typedef typename MYBASE::iterator MYITER;   // my iterator type
2094          typedef typename MYBASE::reverse_iterator       MYRITER;          typedef typename MYBASE::const_iterator MYCITER;    // you get the idea...
2095          typedef typename MYBASE::size_type                      MYSIZE;            typedef typename MYBASE::reverse_iterator MYRITER;
2096          typedef typename MYBASE::value_type                     MYVAL;          typedef typename MYBASE::size_type MYSIZE;
2097          typedef typename MYBASE::allocator_type         MYALLOC;          typedef typename MYBASE::value_type MYVAL;
2098                    typedef typename MYBASE::allocator_type MYALLOC;
2099  public:          
2100        public:
2101          // shorthand conversion from PCTSTR to string resource ID          // shorthand conversion from PCTSTR to string resource ID
2102          #define _TRES(pctstr) (LOWORD((DWORD)(pctstr)))  #define SSRES(pctstr)  LOWORD(reinterpret_cast<unsigned long>(pctstr))
2103            
2104          // CStdStr inline constructors          bool TryLoad( const void *pT )
2105          CStdStr()          {
2106          {              bool bLoaded = false;
2107          }              
2108    #if defined(SS_WIN32) && !defined(SS_ANSI)
2109          CStdStr(const MYTYPE& str) : MYBASE(SSREF(str))              
2110          {              if ( ( pT != NULL ) && SS_IS_INTRESOURCE( pT ) ) {
2111          }                  UINT nId = LOWORD( reinterpret_cast < unsigned long >( pT ) );
2112                    if ( !LoadString( nId ) ) {
2113          CStdStr(const std::string& str)                      TRACE( _T( "Can't load string %u\n" ), SSRES( pT ) );
2114          {                  }
2115                  ssasn(*this, SSREF(str));                  bLoaded = true;
2116          }              }
2117    #endif
2118          CStdStr(const std::wstring& str)              
2119          {              return bLoaded;
2120                  ssasn(*this, SSREF(str));          }
2121          }          
2122            
2123          CStdStr(PCMYSTR pT, MYSIZE n) : MYBASE(pT, n)          // CStdStr inline constructors
2124          {          CStdStr()
2125          }          {}
2126            
2127          CStdStr(PCSTR pA)          CStdStr( const MYTYPE & str ) : MYBASE( SSREF( str ) )
2128          {          {}
2129          #ifdef SS_ANSI          
2130                  *this = pA;          CStdStr( const std::string & str )
2131          #else          {
2132                  if ( 0 != HIWORD(pA) )              ssasn( *this, SSREF( str ) );
2133                          *this = pA;          }
2134                  else if ( 0 != pA && !Load(_TRES(pA)) )          
2135                          TRACE(_T("Can't load string %u\n"), _TRES(pA));          CStdStr( const std::wstring & str )
2136          #endif          {
2137          }              ssasn( *this, SSREF( str ) );
2138            }
2139          CStdStr(PCWSTR pW)          
2140          {          CStdStr( PCMYSTR pT, MYSIZE n ) : MYBASE( pT, n )
2141          #ifdef SS_ANSI          {}
2142                  *this = pW;          
2143          #else  #ifdef SS_UNSIGNED
2144                  if ( 0 != HIWORD(pW) )          
2145                          *this = pW;          CStdStr( PCUSTR pU )
2146                  else if ( 0 != pW && !Load(_TRES(pW)) )          {
2147                          TRACE(_T("Can't load string %u\n"), _TRES(pW));              *this = reinterpret_cast < PCSTR > ( pU );
2148          #endif          }
2149          }  #endif
2150            
2151          CStdStr(MYCITER first, MYCITER last)          CStdStr( PCSTR pA )
2152                  : MYBASE(first, last)          {
2153          {  #ifdef SS_ANSI
2154          }              * this = pA;
2155    #else
2156          CStdStr(MYSIZE nSize, MYVAL ch, const MYALLOC& al=MYALLOC())              
2157                  : MYBASE(nSize, ch, al)  if ( !TryLoad( pA ) )
2158          {                  * this = pA;
2159          }  #endif
2160                
2161          #ifdef SS_INC_COMDEF          }
2162                  CStdStr(const _bstr_t& bstr)          
2163                  {          CStdStr( PCWSTR pW )
2164                          if ( bstr.length() > 0 )          {
2165                                  append(static_cast<PCMYSTR>(bstr), bstr.length());  #ifdef SS_ANSI
2166                  }              * this = pW;
2167          #endif  #else
2168                
2169          // CStdStr inline assignment operators -- the ssasn function now takes care              if ( !TryLoad( pW ) )
2170          // of fixing  the MSVC assignment bug (see knowledge base article Q172398).                  * this = pW;
2171          MYTYPE& operator=(const MYTYPE& str)  #endif
2172          {              
2173                  ssasn(*this, str);          }
2174                  return *this;          
2175          }          CStdStr( MYCITER first, MYCITER last )
2176                    : MYBASE( first, last )
2177          MYTYPE& operator=(const std::string& str)          {}
2178          {          
2179                  ssasn(*this, str);          CStdStr( MYSIZE nSize, MYVAL ch, const MYALLOC & al = MYALLOC() )
2180                  return *this;                  : MYBASE( nSize, ch, al )
2181          }          {}
2182            
2183          MYTYPE& operator=(const std::wstring& str)  #ifdef SS_INC_COMDEF
2184          {          
2185                  ssasn(*this, str);          CStdStr( const _bstr_t & bstr )
2186                  return *this;          {
2187          }              if ( bstr.length() > 0 )
2188                    this->append( static_cast < PCMYSTR > ( bstr ), bstr.length() );
2189          MYTYPE& operator=(PCSTR pA)          }
2190          {  #endif
2191                  ssasn(*this, pA);          
2192                  return *this;          // CStdStr inline assignment operators -- the ssasn function now takes care
2193          }          // of fixing  the MSVC assignment bug (see knowledge base article Q172398).
2194            MYTYPE & operator=( const MYTYPE & str )
2195          MYTYPE& operator=(PCWSTR pW)          {
2196          {              ssasn( *this, str );
2197                  ssasn(*this, pW);              return *this;
2198                  return *this;          }
2199          }          
2200            MYTYPE & operator=( const std::string & str )
2201          MYTYPE& operator=(CT t)          {
2202          {              ssasn( *this, str );
2203                  Q172398(*this);              return *this;
2204                  MYBASE::assign(1, t);          }
2205                  return *this;          
2206          }          MYTYPE & operator=( const std::wstring & str )
2207            {
2208          #ifdef SS_INC_COMDEF              ssasn( *this, str );
2209                  MYTYPE& operator=(const _bstr_t& bstr)              return *this;
2210                  {          }
2211                          if ( bstr.length() > 0 )          
2212                                  return assign(static_cast<PCMYSTR>(bstr), bstr.length());          MYTYPE & operator=( PCSTR pA )
2213                          else          {
2214                          {              ssasn( *this, pA );
2215                                  erase();              return *this;
2216                                  return *this;          }
2217                          }          
2218                  }          MYTYPE & operator=( PCWSTR pW )
2219          #endif          {
2220                ssasn( *this, pW );
2221                return *this;
2222          // Overloads  also needed to fix the MSVC assignment bug (KB: Q172398)          }
2223          //  *** Thanks to Pete The Plumber for catching this one ***          
2224          // They also are compiled if you have explicitly turned off refcounting  #ifdef SS_UNSIGNED
2225          #if ( defined(_MSC_VER) && ( _MSC_VER < 1200 ) ) || defined(SS_NO_REFCOUNT)          MYTYPE & operator=( PCUSTR pU )
2226            {
2227                  MYTYPE& assign(const MYTYPE& str)              ssasn( *this, reinterpret_cast < PCSTR > ( pU ) );
2228                  {              return *this;
2229                          ssasn(*this, str);          }
2230                          return *this;  #endif
2231                  }          
2232            MYTYPE & operator=( CT t )
2233                  MYTYPE& assign(const MYTYPE& str, MYSIZE nStart, MYSIZE nChars)          {
2234                  {              Q172398( *this );
2235                          // This overload of basic_string::assign is supposed to assign up to              this->assign( 1, t );
2236                          // <nChars> or the NULL terminator, whichever comes first.  Since we              return *this;
2237                          // are about to call a less forgiving overload (in which <nChars>          }
2238                          // must be a valid length), we must adjust the length here to a safe          
                         // value.  Thanks to Ullrich Pollähne for catching this bug  
   
                         nChars          = SSMIN(nChars, str.length() - nStart);  
   
                         // Watch out for assignment to self  
   
                         if ( this == &str )  
                         {  
                                 MYTYPE strTemp(str.c_str()+nStart, nChars);  
                                 assign(strTemp);  
                         }  
                         else  
                         {  
                                 Q172398(*this);  
                                 MYBASE::assign(str.c_str()+nStart, nChars);  
                         }  
                         return *this;  
                 }  
   
                 MYTYPE& assign(const MYBASE& str)  
                 {  
                         ssasn(*this, str);  
                         return *this;  
                 }  
   
                 MYTYPE& assign(const MYBASE& str, MYSIZE nStart, MYSIZE nChars)  
                 {  
                         // This overload of basic_string::assign is supposed to assign up to  
                         // <nChars> or the NULL terminator, whichever comes first.  Since we  
                         // are about to call a less forgiving overload (in which <nChars>  
                         // must be a valid length), we must adjust the length here to a safe  
                         // value. Thanks to Ullrich Pollähne for catching this bug  
   
                         nChars          = SSMIN(nChars, str.length() - nStart);  
   
                         // Watch out for assignment to self  
   
                         if ( this == &str )     // watch out for assignment to self  
                         {  
                                 MYTYPE strTemp(str.c_str() + nStart, nChars);  
                                 assign(strTemp);  
                         }  
                         else  
                         {  
                                 Q172398(*this);  
                                 MYBASE::assign(str.c_str()+nStart, nChars);  
                         }  
                         return *this;  
                 }  
   
                 MYTYPE& assign(const CT* pC, MYSIZE nChars)  
                 {  
                         // Q172398 only fix -- erase before assigning, but not if we're  
                         // assigning from our own buffer  
   
         #if defined ( _MSC_VER ) && ( _MSC_VER < 1200 )  
                         if ( !empty() && ( pC < data() || pC > data() + capacity() ) )  
                                 erase();  
         #endif  
                         Q172398(*this);  
                         MYBASE::assign(pC, nChars);  
                         return *this;  
                 }  
   
                 MYTYPE& assign(MYSIZE nChars, MYVAL val)  
                 {  
                         Q172398(*this);  
                         MYBASE::assign(nChars, val);  
                         return *this;  
                 }  
   
                 MYTYPE& assign(const CT* pT)  
                 {  
                         return assign(pT, CStdStr::traits_type::length(pT));  
                 }  
   
                 MYTYPE& assign(MYCITER iterFirst, MYCITER iterLast)  
                 {  
         #if defined ( _MSC_VER ) && ( _MSC_VER < 1200 )  
                         // Q172398 fix.  don't call erase() if we're assigning from ourself  
                         if ( iterFirst < begin() || iterFirst > begin() + size() )  
                                 erase()  
         #endif  
                         replace(begin(), end(), iterFirst, iterLast);  
                         return *this;  
                 }  
         #endif  
   
   
         // -------------------------------------------------------------------------  
         // CStdStr inline concatenation.  
         // -------------------------------------------------------------------------  
         MYTYPE& operator+=(const MYTYPE& str)  
         {  
                 ssadd(*this, str);  
                 return *this;  
         }  
   
         MYTYPE& operator+=(const std::string& str)  
         {  
                 ssadd(*this, str);  
                 return *this;  
         }  
   
         MYTYPE& operator+=(const std::wstring& str)  
         {  
                 ssadd(*this, str);  
                 return *this;  
         }  
   
         MYTYPE& operator+=(PCSTR pA)  
         {  
                 ssadd(*this, pA);  
                 return *this;  
         }  
   
         MYTYPE& operator+=(PCWSTR pW)  
         {  
                 ssadd(*this, pW);  
                 return *this;  
         }  
   
         MYTYPE& operator+=(CT t)  
         {  
                 append(1, t);  
                 return *this;  
         }  
         #ifdef SS_INC_COMDEF    // if we have _bstr_t, define a += for it too.  
                 MYTYPE& operator+=(const _bstr_t& bstr)  
                 {  
                         return operator+=(static_cast<PCMYSTR>(bstr));  
                 }  
         #endif  
   
   
         // addition operators -- global friend functions.  
   
         friend  MYTYPE  operator+(const MYTYPE& str1,   const MYTYPE& str2);  
         friend  MYTYPE  operator+(const MYTYPE& str,    CT t);  
         friend  MYTYPE  operator+(const MYTYPE& str,    PCSTR sz);  
         friend  MYTYPE  operator+(const MYTYPE& str,    PCWSTR sz);  
         friend  MYTYPE  operator+(PCSTR pA,                             const MYTYPE& str);  
         friend  MYTYPE  operator+(PCWSTR pW,                    const MYTYPE& str);  
2239  #ifdef SS_INC_COMDEF  #ifdef SS_INC_COMDEF
2240          friend  MYTYPE  operator+(const _bstr_t& bstr,  const MYTYPE& str);          MYTYPE & operator=( const _bstr_t & bstr )
2241          friend  MYTYPE  operator+(const MYTYPE& str,    const _bstr_t& bstr);          {
2242                if ( bstr.length() > 0 ) {
2243                    this->assign( static_cast < PCMYSTR > ( bstr ), bstr.length() );
2244                    return *this;
2245                } else {
2246                    this->erase();
2247                    return *this;
2248                }
2249            }
2250    #endif
2251            
2252            
2253            // Overloads  also needed to fix the MSVC assignment bug (KB: Q172398)
2254            //  *** Thanks to Pete The Plumber for catching this one ***
2255            // They also are compiled if you have explicitly turned off refcounting
2256    #if ( defined(_MSC_VER) && ( _MSC_VER < 1200 ) ) || defined(SS_NO_REFCOUNT)
2257            
2258            MYTYPE & assign( const MYTYPE & str )
2259            {
2260                Q172398( *this );
2261                sscpy( GetBuffer( str.size() + 1 ), SSREF( str ) );
2262                this->ReleaseBuffer( str.size() );
2263                return *this;
2264            }
2265            
2266            MYTYPE & assign( const MYTYPE & str, MYSIZE nStart, MYSIZE nChars )
2267            {
2268                // This overload of basic_string::assign is supposed to assign up to
2269                // <nChars> or the NULL terminator, whichever comes first.  Since we
2270                // are about to call a less forgiving overload (in which <nChars>
2271                // must be a valid length), we must adjust the length here to a safe
2272                // value.  Thanks to Ullrich Pollähne for catching this bug
2273                
2274                nChars = SSMIN( nChars, str.length() - nStart );
2275                MYTYPE strTemp( str.c_str() + nStart, nChars );
2276                Q172398( *this );
2277                this->assign( strTemp );
2278                return *this;
2279            }
2280            
2281            MYTYPE & assign( const MYBASE & str )
2282            {
2283                ssasn( *this, str );
2284                return *this;
2285            }
2286            
2287            MYTYPE & assign( const MYBASE & str, MYSIZE nStart, MYSIZE nChars )
2288            {
2289                // This overload of basic_string::assign is supposed to assign up to
2290                // <nChars> or the NULL terminator, whichever comes first.  Since we
2291                // are about to call a less forgiving overload (in which <nChars>
2292                // must be a valid length), we must adjust the length here to a safe
2293                // value. Thanks to Ullrich Pollähne for catching this bug
2294                
2295                nChars = SSMIN( nChars, str.length() - nStart );
2296                
2297                // Watch out for assignment to self
2298                
2299                if ( this == &str ) {
2300                    MYTYPE strTemp( str.c_str() + nStart, nChars );
2301                    static_cast < MYBASE * >( this ) ->assign( strTemp );
2302                } else {
2303                    Q172398( *this );
2304                    static_cast < MYBASE * >( this ) ->assign( str.c_str() + nStart,
2305                            nChars );
2306                }
2307                return *this;
2308            }
2309            
2310            MYTYPE & assign( const CT * pC, MYSIZE nChars )
2311            {
2312                // Q172398 only fix -- erase before assigning, but not if we're
2313                // assigning from our own buffer
2314                
2315    #if defined ( _MSC_VER ) && ( _MSC_VER < 1200 )
2316                if ( !this->empty() &&
2317                        ( pC < this->data() || pC > this->data() + this->capacity() ) ) {
2318                    this->erase();
2319                }
2320    #endif
2321                Q172398( *this );
2322                static_cast < MYBASE * >( this ) ->assign( pC, nChars );
2323                return *this;
2324            }
2325            
2326            MYTYPE & assign( MYSIZE nChars, MYVAL val )
2327            {
2328                Q172398( *this );
2329                static_cast < MYBASE * >( this ) ->assign( nChars, val );
2330                return *this;
2331            }
2332            
2333            MYTYPE & assign( const CT * pT )
2334            {
2335                return this->assign( pT, MYBASE::traits_type::length( pT ) );
2336            }
2337            
2338            MYTYPE & assign( MYCITER iterFirst, MYCITER iterLast )
2339            {
2340    #if defined ( _MSC_VER ) && ( _MSC_VER < 1200 )
2341                // Q172398 fix.  don't call erase() if we're assigning from ourself
2342                if ( iterFirst < this->begin() ||
2343                        iterFirst > this->begin() + this->size() ) {
2344                    this->erase()
2345                }
2346    #endif
2347                this->replace( this->begin(), this->end(), iterFirst, iterLast );
2348                return *this;
2349            }
2350    #endif
2351            
2352            
2353            // -------------------------------------------------------------------------
2354            // CStdStr inline concatenation.
2355            // -------------------------------------------------------------------------
2356            MYTYPE & operator+=( const MYTYPE & str )
2357            {
2358                ssadd( *this, str );
2359                return *this;
2360            }
2361            
2362            MYTYPE & operator+=( const std::string & str )
2363            {
2364                ssadd( *this, str );
2365                return *this;
2366            }
2367            
2368            MYTYPE & operator+=( const std::wstring & str )
2369            {
2370                ssadd( *this, str );
2371                return *this;
2372            }
2373            
2374            MYTYPE & operator+=( PCSTR pA )
2375            {
2376                ssadd( *this, pA );
2377                return *this;
2378            }
2379            
2380            MYTYPE & operator+=( PCWSTR pW )
2381            {
2382                ssadd( *this, pW );
2383                return *this;
2384            }
2385            
2386            MYTYPE & operator+=( CT t )
2387            {
2388                this->append( 1, t );
2389                return *this;
2390            }
2391    #ifdef SS_INC_COMDEF            // if we have _bstr_t, define a += for it too.
2392            MYTYPE & operator+=( const _bstr_t & bstr )
2393            {
2394                return this->operator+=( static_cast < PCMYSTR > ( bstr ) );
2395            }
2396    #endif
2397            
2398            
2399            // -------------------------------------------------------------------------
2400            // Case changing functions
2401            // -------------------------------------------------------------------------
2402            
2403            MYTYPE & ToUpper( const std::locale & loc = std::locale() )
2404            {
2405                // Note -- if there are any MBCS character sets in which the lowercase
2406                // form a character takes up a different number of bytes than the
2407                // uppercase form, this would probably not work...
2408                
2409                std::transform( this->begin(),
2410                                this->end(),
2411                                this->begin(), std::bind2nd( SSToUpper < CT > (), loc ) );
2412                                
2413                // ...but if it were, this would probably work better.  Also, this way
2414                // seems to be a bit faster when anything other then the "C" locale is
2415                // used...
2416                
2417                //              if ( !empty() )
2418                //              {
2419                //                      ssupr(this->GetBuf(), this->size(), loc);
2420                //                      this->RelBuf();
2421                //              }
2422                
2423                return *this;
2424            }
2425            
2426            MYTYPE & ToLower( const std::locale & loc = std::locale() )
2427            {
2428                // Note -- if there are any MBCS character sets in which the lowercase
2429                // form a character takes up a different number of bytes than the
2430                // uppercase form, this would probably not work...
2431                
2432                std::transform( this->begin(),
2433                                this->end(),
2434                                this->begin(), std::bind2nd( SSToLower < CT > (), loc ) );
2435                                
2436                // ...but if it were, this would probably work better.  Also, this way
2437                // seems to be a bit faster when anything other then the "C" locale is
2438                // used...
2439                
2440                //              if ( !empty() )
2441                //              {
2442                //                      sslwr(this->GetBuf(), this->size(), loc);
2443                //                      this->RelBuf();
2444                //              }
2445                return *this;
2446            }
2447            
2448            
2449            MYTYPE & Normalize()
2450            {
2451                return Trim().ToLower();
2452            }
2453            
2454            
2455            // -------------------------------------------------------------------------
2456            // CStdStr -- Direct access to character buffer.  In the MS' implementation,
2457            // the at() function that we use here also calls _Freeze() providing us some
2458            // protection from multithreading problems associated with ref-counting.
2459            // In VC 7 and later, of course, the ref-counting stuff is gone.
2460            // -------------------------------------------------------------------------
2461            
2462            CT *GetBuf( int nMinLen = -1 )
2463            {
2464                if ( static_cast < int >( this->size() )
2465                        < nMinLen )
2466                    this->resize( static_cast < MYSIZE > ( nMinLen ) );
2467                    
2468                return this->empty() ? const_cast <
2469                       CT * >( this->data() ) : &( this->at( 0 ) );
2470            }
2471            
2472            CT *SetBuf( int nLen )
2473            {
2474                nLen = ( nLen > 0 ? nLen : 0 );
2475                if ( this->capacity() < 1 && nLen == 0 )
2476                    this->resize( 1 );
2477                    
2478                this->resize( static_cast < MYSIZE > ( nLen ) );
2479                return const_cast < CT * >( this->data() );
2480            }
2481            void RelBuf( int nNewLen = -1 )
2482            {
2483                this->resize( static_cast < MYSIZE > ( nNewLen > -1 ? nNewLen :
2484                                                       sslen( this->c_str() ) ) );
2485            }
2486            
2487            void BufferRel()
2488            {
2489                RelBuf();
2490            }                           // backwards compatability
2491            CT *Buffer()
2492            {
2493                return GetBuf();
2494            }                           // backwards compatability
2495            CT *BufferSet( int nLen )
2496            {
2497                return SetBuf( nLen );
2498            }                           // backwards compatability
2499            
2500            bool Equals( const CT * pT, bool bUseCase = false ) const
2501            {
2502                return 0 ==
2503                       ( bUseCase ? this->compare( pT ) : ssicmp( this->c_str(), pT ) );
2504            }
2505            
2506            // -------------------------------------------------------------------------
2507            // FUNCTION:  CStdStr::Load
2508            // REMARKS:
2509            //              Loads string from resource specified by nID
2510            //
2511            // PARAMETERS:
2512            //              nID - resource Identifier.  Purely a Win32 thing in this case
2513            //
2514            // RETURN VALUE:
2515            //              true if successful, false otherwise
2516            // -------------------------------------------------------------------------
2517            
2518    #ifndef SS_ANSI
2519            
2520            bool Load( UINT nId, HMODULE hModule = NULL )
2521            {
2522                bool bLoaded = false;   // set to true of we succeed.
2523                
2524    #ifdef _MFC_VER                 // When in Rome (or MFC land)...
2525                
2526                // If they gave a resource handle, use it.  Note - this is archaic
2527                // and not really what I would recommend.  But then again, in MFC
2528                // land, you ought to be using CString for resources anyway since
2529                // it walks the resource chain for you.
2530                
2531                HMODULE hModuleOld = NULL;
2532                
2533                if ( NULL != hModule ) {
2534                    hModuleOld = AfxGetResourceHandle();
2535                    AfxSetResourceHandle( hModule );
2536                }
2537                
2538                // ...load the string
2539                
2540                CString strRes;
2541                bLoaded = FALSE != strRes.LoadString( nId );
2542                
2543                // ...and if we set the resource handle, restore it.
2544                
2545                if ( NULL != hModuleOld )
2546                    AfxSetResourceHandle( hModule );
2547                    
2548                if ( bLoaded )
2549                    * this = strRes;
2550                    
2551    #else // otherwise make our own hackneyed version of CString's Load
2552                    
2553    // Get the resource name and module handle
2554                    
2555                if ( NULL == hModule )
2556                    hModule = GetResourceHandle();
2557                    
2558                PCTSTR szName = MAKEINTRESOURCE( ( nId >> 4 ) + 1 );        // lifted
2559                DWORD dwSize = 0;
2560                    
2561                // No sense continuing if we can't find the resource
2562                    
2563                HRSRC hrsrc = ::FindResource( hModule, szName, RT_STRING );
2564                    
2565                if ( NULL == hrsrc ) {
2566                    TRACE( _T( "Cannot find resource %d: 0x%X" ), nId, ::GetLastError() );
2567                } else if ( 0 == ( dwSize = ::SizeofResource( hModule, hrsrc ) / sizeof( CT ) ) ) {
2568                    TRACE( _T( "Cant get size of resource %d 0x%X\n" ), nId,
2569                           GetLastError() );
2570                } else {
2571                    bLoaded = 0 != ssload( hModule, nId, GetBuf( dwSize ), dwSize );
2572                    ReleaseBuffer();
2573                }
2574                    
2575    #endif // #ifdef _MFC_VER
2576                    
2577                if ( !bLoaded )
2578                    TRACE( _T( "String not loaded 0x%X\n" ), ::GetLastError() );
2579                    
2580                return bLoaded;
2581            }
2582            
2583    #endif // #ifdef SS_ANSI
2584            
2585            // -------------------------------------------------------------------------
2586            // FUNCTION:  CStdStr::Format
2587            //              void _cdecl Formst(CStdStringA& PCSTR szFormat, ...)
2588            //              void _cdecl Format(PCSTR szFormat);
2589            //
2590            // DESCRIPTION:
2591            //              This function does sprintf/wsprintf style formatting on CStdStringA
2592            //              objects.  It looks a lot like MFC's CString::Format.  Some people
2593            //              might even call this identical.  Fortunately, these people are now
2594            //              dead... heh heh.
2595            //
2596            // PARAMETERS:
2597            //              nId - ID of string resource holding the format string
2598            //              szFormat - a PCSTR holding the format specifiers
2599            //              argList - a va_list holding the arguments for the format specifiers.
2600            //
2601            // RETURN VALUE:  None.
2602            // -------------------------------------------------------------------------
2603            // formatting (using wsprintf style formatting)
2604            
2605            // If they want a Format() function that safely handles string objects
2606            // without casting
2607            
2608    #ifdef SS_SAFE_FORMAT
2609            
2610            // Question:  Joe, you wacky coder you, why do you have so many overloads
2611            //      of the Format() function
2612            // Answer:  One reason only - CString compatability.  In short, by making
2613            //      the Format() function a template this way, I can do strong typing
2614            //      and allow people to pass CStdString arguments as fillers for
2615            //      "%s" format specifiers without crashing their program!  The downside
2616            //      is that I need to overload on the number of arguments.   If you are
2617            //      passing more arguments than I have listed below in any of my
2618            //      overloads, just add another one.
2619            //
2620            //      Yes, yes, this is really ugly.  In essence what I am doing here is
2621            //      protecting people from a bad (and incorrect) programming practice
2622            //      that they should not be doing anyway.  I am protecting them from
2623            //      themselves.  Why am I doing this?  Well, if you had any idea the
2624            //      number of times I've been emailed by people about this
2625            //      "incompatability" in my code, you wouldn't ask.
2626            
2627            void Fmt( const CT * szFmt, ... )
2628            {
2629                va_list argList;
2630                va_start( argList, szFmt );
2631                FormatV( szFmt, argList );
2632                va_end( argList );
2633            }
2634            
2635    #ifndef SS_ANSI
2636            
2637            void Format( UINT nId )
2638            {
2639                MYTYPE strFmt;
2640                if ( strFmt.Load( nId ) )
2641                    this->swap( strFmt );
2642            }
2643            template < class A1 >
2644            void Format( UINT nId, const A1 & v )
2645            {
2646                MYTYPE strFmt;
2647                if ( strFmt.Load( nId ) )
2648                    Fmt( strFmt, FmtArg < A1 > ( v ) () );
2649            }
2650            template < class A1, class A2 >
2651            void Format( UINT nId, const A1 & v1, const A2 & v2 )
2652            {
2653                MYTYPE strFmt;
2654                if ( strFmt.Load( nId ) )
2655                    Fmt( strFmt, FmtArg < A1 > ( v1 ) (), FmtArg < A2 > ( v2 ) () );
2656            }
2657            template < class A1, class A2, class A3 >
2658            void Format( UINT nId, const A1 & v1, const A2 & v2, const A3 & v3 )
2659            {
2660                MYTYPE strFmt;
2661                if ( strFmt.Load( nId ) ) {
2662                    Fmt( strFmt, FmtArg < A1 > ( v1 ) (), FmtArg < A2 > ( v2 ) (),
2663                         FmtArg < A3 > ( v3 ) () );
2664                }
2665            }
2666            template < class A1, class A2, class A3, class A4 >
2667            void Format( UINT nId, const A1 & v1, const A2 & v2, const A3 & v3,
2668                         const A4 & v4 )
2669            {
2670                MYTYPE strFmt;
2671                if ( strFmt.Load( nId ) ) {
2672                    Fmt( strFmt, FmtArg < A1 > ( v1 ) (), FmtArg < A2 > ( v2 ) (),
2673                         FmtArg < A3 > ( v3 ) (), FmtArg < A4 > ( v4 ) () );
2674                }
2675            }
2676            template < class A1, class A2, class A3, class A4, class A5 >
2677            void Format( UINT nId, const A1 & v1, const A2 & v2, const A3 & v3,
2678                         const A4 & v4, const A5 & v5 )
2679            {
2680                MYTYPE strFmt;
2681                if ( strFmt.Load( nId ) ) {
2682                    Fmt( strFmt, FmtArg < A1 > ( v1 ) (), FmtArg < A2 > ( v2 ) (),
2683                         FmtArg < A3 > ( v3 ) (), FmtArg < A4 > ( v4 ) (),
2684                         FmtArg < A5 > ( v5 ) () );
2685                }
2686            }
2687            template < class A1, class A2, class A3, class A4, class A5, class A6 >
2688            void Format( UINT nId, const A1 & v1, const A2 & v2, const A3 & v3,
2689                         const A4 & v4, const A5 & v5, const A6 & v6 )
2690            {
2691                MYTYPE strFmt;
2692                if ( strFmt.Load( nId ) ) {
2693                    Fmt( strFmt, FmtArg < A1 > ( v1 ) (), FmtArg < A2 > ( v2 ) (),
2694                         FmtArg < A3 > ( v3 ) (), FmtArg < A4 > ( v4 ) (),
2695                         FmtArg < A5 > ( v5 ) (), FmtArg < A6 > ( v6 ) () );
2696                }
2697            }
2698            template < class A1, class A2, class A3, class A4, class A5, class A6,
2699            class A7 >
2700            void Format( UINT nId, const A1 & v1, const A2 & v2, const A3 & v3,
2701                         const A4 & v4, const A5 & v5, const A6 & v6,
2702                         const A7 & v7 )
2703            {
2704                MYTYPE strFmt;
2705                if ( strFmt.Load( nId ) ) {
2706                    Fmt( strFmt, FmtArg < A1 > ( v1 ) (), FmtArg < A2 > ( v2 ) (),
2707                         FmtArg < A3 > ( v3 ) (), FmtArg < A4 > ( v4 ) (),
2708                         FmtArg < A5 > ( v5 ) (), FmtArg < A6 > ( v6 ) (),
2709                         FmtArg < A7 > ( v7 ) () );
2710                }
2711            }
2712            template < class A1, class A2, class A3, class A4, class A5, class A6,
2713            class A7, class A8 >
2714            void Format( UINT nId, const A1 & v1, const A2 & v2, const A3 & v3,
2715                         const A4 & v4, const A5 & v5, const A6 & v6,
2716                         const A7 & v7, const A8 & v8 )
2717            {
2718                MYTYPE strFmt;
2719                if ( strFmt.Load( nId ) ) {
2720                    Fmt( strFmt, FmtArg < A1 > ( v1 ) (), FmtArg < A2 > ( v2 ) (),
2721                         FmtArg < A3 > ( v3 ) (), FmtArg < A4 > ( v4 ) (),
2722                         FmtArg < A5 > ( v5 ) (), FmtArg < A6 > ( v6 ) (),
2723                         FmtArg < A7 > ( v7 ) (), FmtArg < A8 > ( v8 ) () );
2724                }
2725            }
2726            template < class A1, class A2, class A3, class A4, class A5, class A6,
2727            class A7, class A8, class A9 >
2728            void Format( UINT nId, const A1 & v1, const A2 & v2, const A3 & v3,
2729                         const A4 & v4, const A5 & v5, const A6 & v6,
2730                         const A7 & v7, const A8 & v8, const A9 & v9 )
2731            {
2732                MYTYPE strFmt;
2733                if ( strFmt.Load( nId ) ) {
2734                    Fmt( strFmt, FmtArg < A1 > ( v1 ) (), FmtArg < A2 > ( v2 ) (),
2735                         FmtArg < A3 > ( v3 ) (), FmtArg < A4 > ( v4 ) (),
2736                         FmtArg < A5 > ( v5 ) (), FmtArg < A6 > ( v6 ) (),
2737                         FmtArg < A7 > ( v7 ) (), FmtArg < A8 > ( v8 ) (),
2738                         FmtArg < A9 > ( v9 ) () );
2739                }
2740            }
2741            template < class A1, class A2, class A3, class A4, class A5, class A6,
2742            class A7, class A8, class A9, class A10 >
2743            void Format( UINT nId, const A1 & v1, const A2 & v2, const A3 & v3,
2744                         const A4 & v4, const A5 & v5, const A6 & v6,
2745                         const A7 & v7, const A8 & v8, const A9 & v9,
2746                         const A10 & v10 )
2747            {
2748                MYTYPE strFmt;
2749                if ( strFmt.Load( nId ) ) {
2750                    Fmt( strFmt, FmtArg < A1 > ( v1 ) (), FmtArg < A2 > ( v2 ) (),
2751                         FmtArg < A3 > ( v3 ) (), FmtArg < A4 > ( v4 ) (),
2752                         FmtArg < A5 > ( v5 ) (), FmtArg < A6 > ( v6 ) (),
2753                         FmtArg < A7 > ( v7 ) (), FmtArg < A8 > ( v8 ) (),
2754                         FmtArg < A9 > ( v9 ) (), FmtArg < A10 > ( v10 ) () );
2755                }
2756            }
2757            template < class A1, class A2, class A3, class A4, class A5, class A6,
2758            class A7, class A8, class A9, class A10, class A11 >
2759            void Format( UINT nId, const A1 & v1, const A2 & v2, const A3 & v3,
2760                         const A4 & v4, const A5 & v5, const A6 & v6,
2761                         const A7 & v7, const A8 & v8, const A9 & v9,
2762                         const A10 & v10, const A11 & v11 )
2763            {
2764                MYTYPE strFmt;
2765                if ( strFmt.Load( nId ) ) {
2766                    Fmt( strFmt, FmtArg < A1 > ( v1 ) (), FmtArg < A2 > ( v2 ) (),
2767                         FmtArg < A3 > ( v3 ) (), FmtArg < A4 > ( v4 ) (),
2768                         FmtArg < A5 > ( v5 ) (), FmtArg < A6 > ( v6 ) (),
2769                         FmtArg < A7 > ( v7 ) (), FmtArg < A8 > ( v8 ) (),
2770                         FmtArg < A9 > ( v9 ) (), FmtArg < A10 > ( v10 ) (),
2771                         FmtArg < A11 > ( v11 ) () );
2772                }
2773            }
2774            template < class A1, class A2, class A3, class A4, class A5, class A6,
2775            class A7, class A8, class A9, class A10, class A11, class A12 >
2776            void Format( UINT nId, const A1 & v1, const A2 & v2, const A3 & v3,
2777                         const A4 & v4, const A5 & v5, const A6 & v6,
2778                         const A7 & v7, const A8 & v8, const A9 & v9,
2779                         const A10 & v10, const A11 & v11, const A12 & v12 )
2780            {
2781                MYTYPE strFmt;
2782                if ( strFmt.Load( nId ) ) {
2783                    Fmt( strFmt, FmtArg < A1 > ( v1 ) (), FmtArg < A2 > ( v2 ) (),
2784                         FmtArg < A3 > ( v3 ) (), FmtArg < A4 > ( v4 ) (),
2785                         FmtArg < A5 > ( v5 ) (), FmtArg < A6 > ( v6 ) (),
2786                         FmtArg < A7 > ( v7 ) (), FmtArg < A8 > ( v8 ) (),
2787                         FmtArg < A9 > ( v9 ) (), FmtArg < A10 > ( v10 ) (),
2788                         FmtArg < A11 > ( v11 ) (), FmtArg < A12 > ( v12 ) () );
2789                }
2790            }
2791            template < class A1, class A2, class A3, class A4, class A5, class A6,
2792            class A7, class A8, class A9, class A10, class A11, class A12,
2793            class A13 >
2794            void Format( UINT nId, const A1 & v1, const A2 & v2, const A3 & v3,
2795                         const A4 & v4, const A5 & v5, const A6 & v6,
2796                         const A7 & v7, const A8 & v8, const A9 & v9,
2797                         const A10 & v10, const A11 & v11, const A12 & v12,
2798                         const A13 & v13 )
2799            {
2800                MYTYPE strFmt;
2801                if ( strFmt.Load( nId ) ) {
2802                    Fmt( strFmt, FmtArg < A1 > ( v1 ) (), FmtArg < A2 > ( v2 ) (),
2803                         FmtArg < A3 > ( v3 ) (), FmtArg < A4 > ( v4 ) (),
2804                         FmtArg < A5 > ( v5 ) (), FmtArg < A6 > ( v6 ) (),
2805                         FmtArg < A7 > ( v7 ) (), FmtArg < A8 > ( v8 ) (),
2806                         FmtArg < A9 > ( v9 ) (), FmtArg < A10 > ( v10 ) (),
2807                         FmtArg < A11 > ( v11 ) (), FmtArg < A12 > ( v12 ) (),
2808                         FmtArg < A13 > ( v13 ) () );
2809                }
2810            }
2811            template < class A1, class A2, class A3, class A4, class A5, class A6,
2812            class A7, class A8, class A9, class A10, class A11, class A12,
2813            class A13, class A14 >
2814            void Format( UINT nId, const A1 & v1, const A2 & v2, const A3 & v3,
2815                         const A4 & v4, const A5 & v5, const A6 & v6,
2816                         const A7 & v7, const A8 & v8, const A9 & v9,
2817                         const A10 & v10, const A11 & v11, const A12 & v12,
2818                         const A13 & v13, const A14 & v14 )
2819            {
2820                MYTYPE strFmt;
2821                if ( strFmt.Load( nId ) ) {
2822                    Fmt( strFmt, FmtArg < A1 > ( v1 ) (), FmtArg < A2 > ( v2 ) (),
2823                         FmtArg < A3 > ( v3 ) (), FmtArg < A4 > ( v4 ) (),
2824                         FmtArg < A5 > ( v5 ) (), FmtArg < A6 > ( v6 ) (),
2825                         FmtArg < A7 > ( v7 ) (), FmtArg < A8 > ( v8 ) (),
2826                         FmtArg < A9 > ( v9 ) (), FmtArg < A10 > ( v10 ) (),
2827                         FmtArg < A11 > ( v11 ) (), FmtArg < A12 > ( v12 ) (),
2828                         FmtArg < A13 > ( v13 ) (), FmtArg < A14 > ( v14 ) () );
2829                }
2830            }
2831            template < class A1, class A2, class A3, class A4, class A5, class A6,
2832            class A7, class A8, class A9, class A10, class A11, class A12,
2833            class A13, class A14, class A15 >
2834            void Format( UINT nId, const A1 & v1, const A2 & v2, const A3 & v3,
2835                         const A4 & v4, const A5 & v5, const A6 & v6,
2836                         const A7 & v7, const A8 & v8, const A9 & v9,
2837                         const A10 & v10, const A11 & v11, const A12 & v12,
2838                         const A13 & v13, const A14 & v14, const A15 & v15 )
2839            {
2840                MYTYPE strFmt;
2841                if ( strFmt.Load( nId ) ) {
2842                    Fmt( strFmt, FmtArg < A1 > ( v1 ) (), FmtArg < A2 > ( v2 ) (),
2843                         FmtArg < A3 > ( v3 ) (), FmtArg < A4 > ( v4 ) (),
2844                         FmtArg < A5 > ( v5 ) (), FmtArg < A6 > ( v6 ) (),
2845                         FmtArg < A7 > ( v7 ) (), FmtArg < A8 > ( v8 ) (),
2846                         FmtArg < A9 > ( v9 ) (), FmtArg < A10 > ( v10 ) (),
2847                         FmtArg < A11 > ( v11 ) (), FmtArg < A12 > ( v12 ) (),
2848                         FmtArg < A13 > ( v13 ) (), FmtArg < A14 > ( v14 ) (),
2849                         FmtArg < A15 > ( v15 ) () );
2850                }
2851            }
2852            template < class A1, class A2, class A3, class A4, class A5, class A6,
2853            class A7, class A8, class A9, class A10, class A11, class A12,
2854            class A13, class A14, class A15, class A16 >
2855            void Format( UINT nId, const A1 & v1, const A2 & v2, const A3 & v3,
2856                         const A4 & v4, const A5 & v5, const A6 & v6,
2857                         const A7 & v7, const A8 & v8, const A9 & v9,
2858                         const A10 & v10, const A11 & v11, const A12 & v12,
2859                         const A13 & v13, const A14 & v14, const A15 & v15,
2860                         const A16 & v16 )
2861            {
2862                MYTYPE strFmt;
2863                if ( strFmt.Load( nId ) ) {
2864                    Fmt( strFmt, FmtArg < A1 > ( v1 ) (), FmtArg < A2 > ( v2 ) (),
2865                         FmtArg < A3 > ( v3 ) (), FmtArg < A4 > ( v4 ) (),
2866                         FmtArg < A5 > ( v5 ) (), FmtArg < A6 > ( v6 ) (),
2867                         FmtArg < A7 > ( v7 ) (), FmtArg < A8 > ( v8 ) (),
2868                         FmtArg < A9 > ( v9 ) (), FmtArg < A10 > ( v10 ) (),
2869                         FmtArg < A11 > ( v11 ) (), FmtArg < A12 > ( v12 ) (),
2870                         FmtArg < A13 > ( v13 ) (), FmtArg < A14 > ( v14 ) (),
2871                         FmtArg < A15 > ( v15 ) (), FmtArg < A16 > ( v16 ) () );
2872                }
2873            }
2874            template < class A1, class A2, class A3, class A4, class A5, class A6,
2875            class A7, class A8, class A9, class A10, class A11, class A12,
2876            class A13, class A14, class A15, class A16, class A17 >
2877            void Format( UINT nId, const A1 & v1, const A2 & v2, const A3 & v3,
2878                         const A4 & v4, const A5 & v5, const A6 & v6,
2879                         const A7 & v7, const A8 & v8, const A9 & v9,
2880                         const A10 & v10, const A11 & v11, const A12 & v12,
2881                         const A13 & v13, const A14 & v14, const A15 & v15,
2882                         const A16 & v16, const A17 & v17 )
2883            {
2884                MYTYPE strFmt;
2885                if ( strFmt.Load( nId ) ) {
2886                    Fmt( strFmt, FmtArg < A1 > ( v1 ) (), FmtArg < A2 > ( v2 ) (),
2887                         FmtArg < A3 > ( v3 ) (), FmtArg < A4 > ( v4 ) (),
2888                         FmtArg < A5 > ( v5 ) (), FmtArg < A6 > ( v6 ) (),
2889                         FmtArg < A7 > ( v7 ) (), FmtArg < A8 > ( v8 ) (),
2890                         FmtArg < A9 > ( v9 ) (), FmtArg < A10 > ( v10 ) (),
2891                         FmtArg < A11 > ( v11 ) (), FmtArg < A12 > ( v12 ) (),
2892                         FmtArg < A13 > ( v13 ) (), FmtArg < A14 > ( v14 ) (),
2893                         FmtArg < A15 > ( v15 ) (), FmtArg < A16 > ( v16 ) (),
2894                         FmtArg < A17 > ( v17 ) () );
2895                }
2896            }
2897            
2898    #endif // #ifndef SS_ANSI
2899            
2900            // ...now the other overload of Format: the one that takes a string literal
2901            
2902            void Format( const CT * szFmt )
2903            {
2904                *this = szFmt;
2905            }
2906            template < class A1 >
2907            void Format( const CT * szFmt, const A1 & v )
2908            {
2909                Fmt( szFmt, FmtArg < A1 > ( v ) () );
2910            }
2911            template < class A1, class A2 >
2912            void Format( const CT * szFmt, const A1 & v1, const A2 & v2 )
2913            {
2914                Fmt( szFmt, FmtArg < A1 > ( v1 ) (), FmtArg < A2 > ( v2 ) () );
2915            }
2916            template < class A1, class A2, class A3 >
2917            void Format( const CT * szFmt, const A1 & v1, const A2 & v2,
2918                         const A3 & v3 )
2919            {
2920                Fmt( szFmt, FmtArg < A1 > ( v1 ) (), FmtArg < A2 > ( v2 ) (),
2921                     FmtArg < A3 > ( v3 ) () );
2922            }
2923            template < class A1, class A2, class A3, class A4 >
2924            void Format( const CT * szFmt, const A1 & v1, const A2 & v2,
2925                         const A3 & v3, const A4 & v4 )
2926            {
2927                Fmt( szFmt, FmtArg < A1 > ( v1 ) (), FmtArg < A2 > ( v2 ) (),
2928                     FmtArg < A3 > ( v3 ) (), FmtArg < A4 > ( v4 ) () );
2929            }
2930            template < class A1, class A2, class A3, class A4, class A5 >
2931            void Format( const CT * szFmt, const A1 & v1, const A2 & v2,
2932                         const A3 & v3, const A4 & v4, const A5 & v5 )
2933            {
2934                Fmt( szFmt, FmtArg < A1 > ( v1 ) (), FmtArg < A2 > ( v2 ) (),
2935                     FmtArg < A3 > ( v3 ) (), FmtArg < A4 > ( v4 ) (),
2936                     FmtArg < A5 > ( v5 ) () );
2937            }
2938            template < class A1, class A2, class A3, class A4, class A5, class A6 >
2939            void Format( const CT * szFmt, const A1 & v1, const A2 & v2,
2940                         const A3 & v3, const A4 & v4, const A5 & v5,
2941                         const A6 & v6 )
2942            {
2943                Fmt( szFmt, FmtArg < A1 > ( v1 ) (), FmtArg < A2 > ( v2 ) (),
2944                     FmtArg < A3 > ( v3 ) (), FmtArg < A4 > ( v4 ) (),
2945                     FmtArg < A5 > ( v5 ) (), FmtArg < A6 > ( v6 ) () );
2946            }
2947            template < class A1, class A2, class A3, class A4, class A5, class A6,
2948            class A7 >
2949            void Format( const CT * szFmt, const A1 & v1, const A2 & v2,
2950                         const A3 & v3, const A4 & v4, const A5 & v5,
2951                         const A6 & v6, const A7 & v7 )
2952            {
2953                Fmt( szFmt, FmtArg < A1 > ( v1 ) (), FmtArg < A2 > ( v2 ) (),
2954                     FmtArg < A3 > ( v3 ) (), FmtArg < A4 > ( v4 ) (),
2955                     FmtArg < A5 > ( v5 ) (), FmtArg < A6 > ( v6 ) (),
2956                     FmtArg < A7 > ( v7 ) () );
2957            }
2958            template < class A1, class A2, class A3, class A4, class A5, class A6,
2959            class A7, class A8 >
2960            void Format( const CT * szFmt, const A1 & v1, const A2 & v2,
2961                         const A3 & v3, const A4 & v4, const A5 & v5,
2962                         const A6 & v6, const A7 & v7, const A8 & v8 )
2963            {
2964                Fmt( szFmt, FmtArg < A1 > ( v1 ) (), FmtArg < A2 > ( v2 ) (),
2965                     FmtArg < A3 > ( v3 ) (), FmtArg < A4 > ( v4 ) (),
2966                     FmtArg < A5 > ( v5 ) (), FmtArg < A6 > ( v6 ) (),
2967                     FmtArg < A7 > ( v7 ) (), FmtArg < A8 > ( v8 ) () );
2968            }
2969            template < class A1, class A2, class A3, class A4, class A5, class A6,
2970            class A7, class A8, class A9 >
2971            void Format( const CT * szFmt, const A1 & v1, const A2 & v2,
2972                         const A3 & v3, const A4 & v4, const A5 & v5,
2973                         const A6 & v6, const A7 & v7, const A8 & v8,
2974                         const A9 & v9 )
2975            {
2976                Fmt( szFmt, FmtArg < A1 > ( v1 ) (), FmtArg < A2 > ( v2 ) (),
2977                     FmtArg < A3 > ( v3 ) (), FmtArg < A4 > ( v4 ) (),
2978                     FmtArg < A5 > ( v5 ) (), FmtArg < A6 > ( v6 ) (),
2979                     FmtArg < A7 > ( v7 ) (), FmtArg < A8 > ( v8 ) (),
2980                     FmtArg < A9 > ( v9 ) () );
2981            }
2982            template < class A1, class A2, class A3, class A4, class A5, class A6,
2983            class A7, class A8, class A9, class A10 >
2984            void Format( const CT * szFmt, const A1 & v1, const A2 & v2,
2985                         const A3 & v3, const A4 & v4, const A5 & v5,
2986                         const A6 & v6, const A7 & v7, const A8 & v8,
2987                         const A9 & v9, const A10 & v10 )
2988            {
2989                Fmt( szFmt, FmtArg < A1 > ( v1 ) (), FmtArg < A2 > ( v2 ) (),
2990                     FmtArg < A3 > ( v3 ) (), FmtArg < A4 > ( v4 ) (),
2991                     FmtArg < A5 > ( v5 ) (), FmtArg < A6 > ( v6 ) (),
2992                     FmtArg < A7 > ( v7 ) (), FmtArg < A8 > ( v8 ) (),
2993                     FmtArg < A9 > ( v9 ) (), FmtArg < A10 > ( v10 ) () );
2994            }
2995            template < class A1, class A2, class A3, class A4, class A5, class A6,
2996            class A7, class A8, class A9, class A10, class A11 >
2997            void Format( const CT * szFmt, const A1 & v1, const A2 & v2,
2998                         const A3 & v3, const A4 & v4, const A5 & v5,
2999                         const A6 & v6, const A7 & v7, const A8 & v8,
3000                         const A9 & v9, const A10 & v10, const A11 & v11 )
3001            {
3002                Fmt( szFmt, FmtArg < A1 > ( v1 ) (), FmtArg < A2 > ( v2 ) (),
3003                     FmtArg < A3 > ( v3 ) (), FmtArg < A4 > ( v4 ) (),
3004                     FmtArg < A5 > ( v5 ) (), FmtArg < A6 > ( v6 ) (),
3005                     FmtArg < A7 > ( v7 ) (), FmtArg < A8 > ( v8 ) (),
3006                     FmtArg < A9 > ( v9 ) (), FmtArg < A10 > ( v10 ) (),
3007                     FmtArg < A11 > ( v11 ) () );
3008            }
3009            template < class A1, class A2, class A3, class A4, class A5, class A6,
3010            class A7, class A8, class A9, class A10, class A11, class A12 >
3011            void Format( const CT * szFmt, const A1 & v1, const A2 & v2,
3012                         const A3 & v3, const A4 & v4, const A5 & v5,
3013                         const A6 & v6, const A7 & v7, const A8 & v8,
3014                         const A9 & v9, const A10 & v10, const A11 & v11,
3015                         const A12 & v12 )
3016            {
3017                Fmt( szFmt, FmtArg < A1 > ( v1 ) (), FmtArg < A2 > ( v2 ) (),
3018                     FmtArg < A3 > ( v3 ) (), FmtArg < A4 > ( v4 ) (),
3019                     FmtArg < A5 > ( v5 ) (), FmtArg < A6 > ( v6 ) (),
3020                     FmtArg < A7 > ( v7 ) (), FmtArg < A8 > ( v8 ) (),
3021                     FmtArg < A9 > ( v9 ) (), FmtArg < A10 > ( v10 ) (),
3022                     FmtArg < A11 > ( v11 ) (), FmtArg < A12 > ( v12 ) () );
3023            }
3024            template < class A1, class A2, class A3, class A4, class A5, class A6,
3025            class A7, class A8, class A9, class A10, class A11, class A12,
3026            class A13 >
3027            void Format( const CT * szFmt, const A1 & v1, const A2 & v2,
3028                         const A3 & v3, const A4 & v4, const A5 & v5,
3029                         const A6 & v6, const A7 & v7, const A8 & v8,
3030                         const A9 & v9, const A10 & v10, const A11 & v11,
3031                         const A12 & v12, const A13 & v13 )
3032            {
3033                Fmt( szFmt, FmtArg < A1 > ( v1 ) (), FmtArg < A2 > ( v2 ) (),
3034                     FmtArg < A3 > ( v3 ) (), FmtArg < A4 > ( v4 ) (),
3035                     FmtArg < A5 > ( v5 ) (), FmtArg < A6 > ( v6 ) (),
3036                     FmtArg < A7 > ( v7 ) (), FmtArg < A8 > ( v8 ) (),
3037                     FmtArg < A9 > ( v9 ) (), FmtArg < A10 > ( v10 ) (),
3038                     FmtArg < A11 > ( v11 ) (), FmtArg < A12 > ( v12 ) (),
3039                     FmtArg < A13 > ( v13 ) () );
3040            }
3041            template < class A1, class A2, class A3, class A4, class A5, class A6,
3042            class A7, class A8, class A9, class A10, class A11, class A12,
3043            class A13, class A14 >
3044            void Format( const CT * szFmt, const A1 & v1, const A2 & v2,
3045                         const A3 & v3, const A4 & v4, const A5 & v5,
3046                         const A6 & v6, const A7 & v7, const A8 & v8,
3047                         const A9 & v9, const A10 & v10, const A11 & v11,
3048                         const A12 & v12, const A13 & v13, const A14 & v14 )
3049            {
3050                Fmt( szFmt, FmtArg < A1 > ( v1 ) (), FmtArg < A2 > ( v2 ) (),
3051                     FmtArg < A3 > ( v3 ) (), FmtArg < A4 > ( v4 ) (),
3052                     FmtArg < A5 > ( v5 ) (), FmtArg < A6 > ( v6 ) (),
3053                     FmtArg < A7 > ( v7 ) (), FmtArg < A8 > ( v8 ) (),
3054                     FmtArg < A9 > ( v9 ) (), FmtArg < A10 > ( v10 ) (),
3055                     FmtArg < A11 > ( v11 ) (), FmtArg < A12 > ( v12 ) (),
3056                     FmtArg < A13 > ( v13 ) (), FmtArg < A14 > ( v14 ) () );
3057            }
3058            template < class A1, class A2, class A3, class A4, class A5, class A6,
3059            class A7, class A8, class A9, class A10, class A11, class A12,
3060            class A13, class A14, class A15 >
3061            void Format( const CT * szFmt, const A1 & v1, const A2 & v2,
3062                         const A3 & v3, const A4 & v4, const A5 & v5,
3063                         const A6 & v6, const A7 & v7, const A8 & v8,
3064                         const A9 & v9, const A10 & v10, const A11 & v11,
3065                         const A12 & v12, const A13 & v13, const A14 & v14,
3066                         const A15 & v15 )
3067            {
3068                Fmt( szFmt, FmtArg < A1 > ( v1 ) (), FmtArg < A2 > ( v2 ) (),
3069                     FmtArg < A3 > ( v3 ) (), FmtArg < A4 > ( v4 ) (),
3070                     FmtArg < A5 > ( v5 ) (), FmtArg < A6 > ( v6 ) (),
3071                     FmtArg < A7 > ( v7 ) (), FmtArg < A8 > ( v8 ) (),
3072                     FmtArg < A9 > ( v9 ) (), FmtArg < A10 > ( v10 ) (),
3073                     FmtArg < A11 > ( v11 ) (), FmtArg < A12 > ( v12 ) (),
3074                     FmtArg < A13 > ( v13 ) (), FmtArg < A14 > ( v14 ) (),
3075                     FmtArg < A15 > ( v15 ) () );
3076            }
3077            template < class A1, class A2, class A3, class A4, class A5, class A6,
3078            class A7, class A8, class A9, class A10, class A11, class A12,
3079            class A13, class A14, class A15, class A16 >
3080            void Format( const CT * szFmt, const A1 & v1, const A2 & v2,
3081                         const A3 & v3, const A4 & v4, const A5 & v5,
3082                         const A6 & v6, const A7 & v7, const A8 & v8,
3083                         const A9 & v9, const A10 & v10, const A11 & v11,
3084                         const A12 & v12, const A13 & v13, const A14 & v14,
3085                         const A15 & v15, const A16 & v16 )
3086            {
3087                Fmt( szFmt, FmtArg < A1 > ( v1 ) (), FmtArg < A2 > ( v2 ) (),
3088                     FmtArg < A3 > ( v3 ) (), FmtArg < A4 > ( v4 ) (),
3089                     FmtArg < A5 > ( v5 ) (), FmtArg < A6 > ( v6 ) (),
3090                     FmtArg < A7 > ( v7 ) (), FmtArg < A8 > ( v8 ) (),
3091                     FmtArg < A9 > ( v9 ) (), FmtArg < A10 > ( v10 ) (),
3092                     FmtArg < A11 > ( v11 ) (), FmtArg < A12 > ( v12 ) (),
3093                     FmtArg < A13 > ( v13 ) (), FmtArg < A14 > ( v14 ) (),
3094                     FmtArg < A15 > ( v15 ) (), FmtArg < A16 > ( v16 ) () );
3095            }
3096            template < class A1, class A2, class A3, class A4, class A5, class A6,
3097            class A7, class A8, class A9, class A10, class A11, class A12,
3098            class A13, class A14, class A15, class A16, class A17 >
3099            void Format( const CT * szFmt, const A1 & v1, const A2 & v2,
3100                         const A3 & v3, const A4 & v4, const A5 & v5,
3101                         const A6 & v6, const A7 & v7, const A8 & v8,
3102                         const A9 & v9, const A10 & v10, const A11 & v11,
3103                         const A12 & v12, const A13 & v13, const A14 & v14,
3104                         const A15 & v15, const A16 & v16, const A17 & v17 )
3105            {
3106                Fmt( szFmt, FmtArg < A1 > ( v1 ) (), FmtArg < A2 > ( v2 ) (),
3107                     FmtArg < A3 > ( v3 ) (), FmtArg < A4 > ( v4 ) (),
3108                     FmtArg < A5 > ( v5 ) (), FmtArg < A6 > ( v6 ) (),
3109                     FmtArg < A7 > ( v7 ) (), FmtArg < A8 > ( v8 ) (),
3110                     FmtArg < A9 > ( v9 ) (), FmtArg < A10 > ( v10 ) (),
3111                     FmtArg < A11 > ( v11 ) (), FmtArg < A12 > ( v12 ) (),
3112                     FmtArg < A13 > ( v13 ) (), FmtArg < A14 > ( v14 ) (),
3113                     FmtArg < A15 > ( v15 ) (), FmtArg < A16 > ( v16 ) (),
3114                     FmtArg < A17 > ( v17 ) () );
3115            }
3116            
3117    #else // #ifdef SS_SAFE_FORMAT
3118            
3119            
3120    #ifndef SS_ANSI
3121            
3122    void Format( UINT nId, ... )
3123            {
3124                va_list argList;
3125                va_start( argList, nId );
3126            
3127                MYTYPE strFmt;
3128                if ( strFmt.Load( nId ) )
3129                    FormatV( strFmt, argList );
3130            
3131                va_end( argList );
3132            }
3133            
3134    #endif // #ifdef SS_ANSI
3135            
3136            void Format( const CT * szFmt, ... )
3137            {
3138                va_list argList;
3139                va_start( argList, szFmt );
3140                FormatV( szFmt, argList );
3141                va_end( argList );
3142            }
3143            
3144    #endif // #ifdef SS_SAFE_FORMAT
3145            
3146            void AppendFormat( const CT * szFmt, ... )
3147            {
3148                va_list argList;
3149                va_start( argList, szFmt );
3150                AppendFormatV( szFmt, argList );
3151                va_end( argList );
3152            }
3153            
3154    #define MAX_FMT_TRIES  5       // #of times we try
3155    #define FMT_BLOCK_SIZE  2048    // # of bytes to increment per try
3156    #define BUFSIZE_1ST 256
3157    #define BUFSIZE_2ND 512
3158    #define STD_BUF_SIZE  1024
3159            
3160            // an efficient way to add formatted characters to the string.  You may only
3161            // add up to STD_BUF_SIZE characters at a time, though
3162            void AppendFormatV( const CT * szFmt, va_list argList )
3163            {
3164                CT szBuf[ STD_BUF_SIZE ];
3165    #ifdef SS_ANSI
3166                
3167                int nLen = ssvsprintf( szBuf, STD_BUF_SIZE - 1, szFmt, argList );
3168    #else
3169                
3170                int nLen = ssnprintf( szBuf, STD_BUF_SIZE - 1, szFmt, argList );
3171  #endif  #endif
3172                
3173          // -------------------------------------------------------------------------              if ( 0 < nLen )
3174          // Case changing functions                  this->append( szBuf, nLen );
3175          // -------------------------------------------------------------------------          }
3176          // -------------------------------------------------------------------------          
3177          MYTYPE& ToUpper()          // -------------------------------------------------------------------------
3178          {          // FUNCTION:  FormatV
3179                  //  Strictly speaking, this would be about the most portable way          //              void FormatV(PCSTR szFormat, va_list, argList);
3180            //
3181                  //      std::transform(begin(),          // DESCRIPTION:
3182                  //                                 end(),          //              This function formats the string with sprintf style format-specs.
3183                  //                                 begin(),          //              It makes a general guess at required buffer size and then tries
3184                  //                                 std::bind2nd(SSToUpper<CT>(), std::locale()));          //              successively larger buffers until it finds one big enough or a
3185            //              threshold (MAX_FMT_TRIES) is exceeded.
3186                  // But practically speaking, this works faster          //
3187            // PARAMETERS:
3188                  if ( !empty() )          //              szFormat - a PCSTR holding the format of the output
3189                          ssupr(GetBuf(), size());          //              argList - a Microsoft specific va_list for variable argument lists
3190            //
3191                  return *this;          // RETURN VALUE:
3192          }          // -------------------------------------------------------------------------
3193            
3194            void FormatV( const CT * szFormat, va_list argList )
3195            {
3196          MYTYPE& ToLower()  #ifdef SS_ANSI
3197          {          
3198                  //  Strictly speaking, this would be about the most portable way              int nLen = sslen( szFormat ) + STD_BUF_SIZE;
3199                ssvsprintf( GetBuffer( nLen ), nLen - 1, szFormat, argList );
3200                  //      std::transform(begin(),              ReleaseBuffer();
3201                  //                                 end(),              
3202                  //                                 begin(),  #else
3203                  //                                 std::bind2nd(SSToLower<CT>(), std::locale()));              
3204    CT *pBuf = NULL;
3205                  // But practically speaking, this works faster              int nChars = 1;
3206                int nUsed = 0;
3207                  if ( !empty() )              size_type nActual = 0;
3208                          sslwr(GetBuf(), size());              int nTry = 0;
3209                
3210                  return *this;              do {
3211          }                  // Grow more than linearly (e.g. 512, 1536, 3072, etc)
3212                
3213                    nChars += ( ( nTry + 1 ) * FMT_BLOCK_SIZE );
3214                    pBuf = reinterpret_cast < CT * >( _alloca( sizeof( CT ) * nChars ) );
3215          MYTYPE& Normalize()                  nUsed = ssnprintf( pBuf, nChars - 1, szFormat, argList );
3216          {              
3217                  return Trim().ToLower();                  // Ensure proper NULL termination.
3218          }              
3219                    nActual = nUsed == -1 ? nChars - 1 : SSMIN( nUsed, nChars - 1 );
3220                    pBuf[ nActual ] = '\0';
3221          // -------------------------------------------------------------------------              
3222          // CStdStr -- Direct access to character buffer.  In the MS' implementation,              
3223          // the at() function that we use here also calls _Freeze() providing us some              } while ( nUsed < 0 && nTry++ < MAX_FMT_TRIES );
3224          // protection from multithreading problems associated with ref-counting.              
3225          // -------------------------------------------------------------------------              // assign whatever we managed to format
3226          CT* GetBuf(int nMinLen=-1)              
3227          {              this->assign( pBuf, nActual );
3228                  if ( static_cast<int>(size()) < nMinLen )              
3229                          resize(static_cast<MYSIZE>(nMinLen));  #endif
3230                
3231                  return empty() ? const_cast<CT*>(data()) : &(at(0));          }
3232          }          
3233            // -------------------------------------------------------------------------
3234          CT* SetBuf(int nLen)          // CString Facade Functions:
3235          {          //
3236                  nLen = ( nLen > 0 ? nLen : 0 );          // The following methods are intended to allow you to use this class as a
3237                  if ( capacity() < 1 && nLen == 0 )          // near drop-in replacement for CString.
3238                          resize(1);          // -------------------------------------------------------------------------
3239    #ifdef SS_WIN32
3240                  resize(static_cast<MYSIZE>(nLen));          BSTR AllocSysString() const
3241                  return const_cast<CT*>(data());          {
3242          }              ostring os;
3243          void RelBuf(int nNewLen=-1)              ssasn( os, *this );
3244          {              return ::SysAllocString( os.c_str() );
3245                  resize(static_cast<MYSIZE>(nNewLen > -1 ? nNewLen : sslen(c_str())));          }
3246          }  #endif
3247            
3248          void BufferRel()                 { RelBuf(); }                  // backwards compatability          int Collate( PCMYSTR szThat ) const
3249          CT*  Buffer()                    { return GetBuf(); }   // backwards compatability          {
3250          CT*  BufferSet(int nLen) { return SetBuf(nLen);}// backwards compatability              return sscoll( this->c_str(), this->length(), szThat, sslen( szThat ) );
3251            }
3252          bool Equals(const CT* pT, bool bUseCase=false) const          
3253          {       // get copy, THEN compare (thread safe)          int CollateNoCase( PCMYSTR szThat ) const
3254                  return  bUseCase ? compare(pT) == 0 : ssicmp(MYTYPE(*this), pT) == 0;          {
3255          }              return ssicoll( this->c_str(), this->length(), szThat, sslen( szThat ) );
3256            }
3257          // -------------------------------------------------------------------------          
3258          // FUNCTION:  CStdStr::Load          int Compare( PCMYSTR szThat ) const
3259          // REMARKS:          {
3260          //              Loads string from resource specified by nID              return this->compare( szThat );
3261          //          }
3262          // PARAMETERS:          
3263          //              nID - resource Identifier.  Purely a Win32 thing in this case          int CompareNoCase( PCMYSTR szThat ) const
3264          //          {
3265          // RETURN VALUE:              return ssicmp( this->c_str(), szThat );
3266          //              true if successful, false otherwise          }
3267          // -------------------------------------------------------------------------          
3268            int Delete( int nIdx, int nCount = 1 )
3269            {
3270                if ( nIdx < 0 )
3271                    nIdx = 0;
3272                    
3273                if ( nIdx < this->GetLength() )
3274                    this->erase( static_cast < MYSIZE > ( nIdx ),
3275                                 static_cast < MYSIZE > ( nCount ) );
3276                                
3277                return GetLength();
3278            }
3279            
3280            void Empty()
3281            {
3282                this->erase();
3283            }
3284            
3285            int Find( CT ch ) const
3286            {
3287                MYSIZE nIdx = this->find_first_of( ch );
3288                return static_cast < int >( MYBASE::npos == nIdx ? -1 : nIdx );
3289            }
3290            
3291            int Find( PCMYSTR szSub ) const
3292            {
3293                MYSIZE nIdx = this->find( szSub );
3294                return static_cast < int >( MYBASE::npos == nIdx ? -1 : nIdx );
3295            }
3296            
3297            int Find( CT ch, int nStart ) const
3298            {
3299                // CString::Find docs say add 1 to nStart when it's not zero
3300                // CString::Find code doesn't do that however.  We'll stick
3301                // with what the code does
3302                
3303                MYSIZE nIdx =
3304                    this->find_first_of( ch, static_cast < MYSIZE > ( nStart ) );
3305                return static_cast < int >( MYBASE::npos == nIdx ? -1 : nIdx );
3306            }
3307            
3308            int Find( PCMYSTR szSub, int nStart ) const
3309            {
3310                // CString::Find docs say add 1 to nStart when it's not zero
3311                // CString::Find code doesn't do that however.  We'll stick
3312                // with what the code does
3313                
3314                MYSIZE nIdx = this->find( szSub, static_cast < MYSIZE > ( nStart ) );
3315                return static_cast < int >( MYBASE::npos == nIdx ? -1 : nIdx );
3316            }
3317            
3318            int FindOneOf( PCMYSTR szCharSet ) const
3319            {
3320                MYSIZE nIdx = this->find_first_of( szCharSet );
3321                return static_cast < int >( MYBASE::npos == nIdx ? -1 : nIdx );
3322            }
3323            
3324  #ifndef SS_ANSI  #ifndef SS_ANSI
3325          bool Load(UINT nId, HMODULE hModule=NULL)          void FormatMessage( PCMYSTR szFormat, ... ) throw( std::exception )
3326          {          {
3327                  bool bLoaded            = false;        // set to true of we succeed.              va_list argList;
3328                va_start( argList, szFormat );
3329          #ifdef _MFC_VER         // When in Rome...              PMYSTR szTemp;
3330                if ( ssfmtmsg
3331                  CString strRes;                      ( FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER,
3332                  bLoaded                         = FALSE != strRes.LoadString(nId);                        szFormat, 0, 0, reinterpret_cast < PMYSTR > ( &szTemp ), 0,
3333                  if ( bLoaded )                        &argList ) == 0 || szTemp == 0 ) {
3334                          *this                   = strRes;                  throw std::runtime_error( "out of memory" );
3335                }
3336          #else              *this = szTemp;
3337                                LocalFree( szTemp );
3338                  // Get the resource name and module handle              va_end( argList );
3339            }
3340                  if ( NULL == hModule )          
3341                          hModule                 = GetResourceHandle();          void FormatMessage( UINT nFormatId, ... ) throw( std::exception )
3342            {
3343                  PCTSTR szName           = MAKEINTRESOURCE((nId>>4)+1); // lifted              MYTYPE sFormat;
3344                  DWORD dwSize            = 0;              VERIFY( sFormat.LoadString( nFormatId ) );
3345                va_list argList;
3346                  // No sense continuing if we can't find the resource              va_start( argList, nFormatId );
3347                PMYSTR szTemp;
3348                  HRSRC hrsrc                     = ::FindResource(hModule, szName, RT_STRING);              if ( ssfmtmsg
3349                        ( FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER,
3350                  if ( NULL == hrsrc )                        sFormat, 0, 0, reinterpret_cast < PMYSTR > ( &szTemp ), 0,
3351                          TRACE(_T("Cannot find resource %d: 0x%X"), nId, ::GetLastError());                        &argList ) == 0 || szTemp == 0 ) {
3352                  else if ( 0 == (dwSize = ::SizeofResource(hModule, hrsrc) / sizeof(CT)))                  throw std::runtime_error( "out of memory" );
3353                          TRACE(_T("Cant get size of resource %d 0x%X\n"),nId,GetLastError());              }
3354                  else              *this = szTemp;
3355                  {              LocalFree( szTemp );
3356                          bLoaded                 = 0 != ssload(hModule, nId, GetBuf(dwSize), dwSize);              va_end( argList );
3357                          ReleaseBuffer();          }
3358                  }  #endif
3359            
3360          #endif          // GetAllocLength -- an MSVC7 function but it costs us nothing to add it.
3361            
3362                  if ( !bLoaded )          int GetAllocLength()
3363                          TRACE(_T("String not loaded 0x%X\n"), ::GetLastError());          {
3364                return static_cast < int >( this->capacity() );
3365                  return bLoaded;          }
3366          }          
3367  #endif          // -------------------------------------------------------------------------
3368                    // GetXXXX -- Direct access to character buffer
3369          // -------------------------------------------------------------------------          // -------------------------------------------------------------------------
3370          // FUNCTION:  CStdStr::Format          CT GetAt( int nIdx ) const
3371          //              void _cdecl Formst(CStdStringA& PCSTR szFormat, ...)          {
3372          //              void _cdecl Format(PCSTR szFormat);              return this->at( static_cast < MYSIZE > ( nIdx ) );
3373          //                    }
3374          // DESCRIPTION:          
3375          //              This function does sprintf/wsprintf style formatting on CStdStringA          CT *GetBuffer( int nMinLen = -1 )
3376          //              objects.  It looks a lot like MFC's CString::Format.  Some people          {
3377          //              might even call this identical.  Fortunately, these people are now              return GetBuf( nMinLen );
3378          //              dead.          }
3379          //          
3380          // PARAMETERS:          CT *GetBufferSetLength( int nLen )
3381          //              nId - ID of string resource holding the format string          {
3382          //              szFormat - a PCSTR holding the format specifiers              return BufferSet( nLen );
3383          //              argList - a va_list holding the arguments for the format specifiers.          }
3384          //          
3385          // RETURN VALUE:  None.          // GetLength() -- MFC docs say this is the # of BYTES but
3386          // -------------------------------------------------------------------------          // in truth it is the number of CHARACTERs (chars or wchar_ts)
3387          // formatting (using wsprintf style formatting)          int GetLength() const
3388          #ifndef SS_ANSI          {
3389          void Format(UINT nId, ...)              return static_cast < int >( this->length() );
3390          {          }
3391                  va_list argList;          
3392                  va_start(argList, nId);          int Insert( int nIdx, CT ch )
3393                  va_start(argList, nId);          {
3394                if ( static_cast < MYSIZE > ( nIdx ) >
3395                  MYTYPE strFmt;                      this->size() - 1 )
3396                  if ( strFmt.Load(nId) )                  this->append( 1, ch );
3397                          FormatV(strFmt, argList);              else
3398                    this->insert( static_cast < MYSIZE > ( nIdx ), 1, ch );
3399                  va_end(argList);                  
3400          }              return GetLength();
3401          #endif          }
3402          void Format(const CT* szFmt, ...)          int Insert( int nIdx, PCMYSTR sz )
3403          {          {
3404                  va_list argList;              if ( static_cast < MYSIZE > ( nIdx ) >
3405                  va_start(argList, szFmt);                      = this->size() )
3406                  FormatV(szFmt, argList);                  this->append( sz, static_cast < MYSIZE > ( sslen( sz ) ) );
3407                  va_end(argList);              else
3408          }                  this->insert( static_cast < MYSIZE > ( nIdx ), sz );
3409          void AppendFormat(const CT* szFmt, ...)                  
3410          {              return GetLength();
3411                  va_list argList;          }
3412                  va_start(argList, szFmt);          
3413                  AppendFormatV(szFmt, argList);          bool IsEmpty() const
3414                  va_end(argList);          {
3415          }              return this->empty();
3416            }
3417          #define MAX_FMT_TRIES           5        // #of times we try          
3418          #define FMT_BLOCK_SIZE          2048 // # of bytes to increment per try          MYTYPE Left( int nCount ) const
3419          #define BUFSIZE_1ST     256          {
3420          #define BUFSIZE_2ND 512              // Range check the count.
3421          #define STD_BUF_SIZE            1024              
3422                nCount = SSMAX( 0, SSMIN( nCount, static_cast < int >( this->size() ) ) );
3423          // an efficient way to add formatted characters to the string.  You may only              return this->substr( 0, static_cast < MYSIZE > ( nCount ) );
3424          // add up to STD_BUF_SIZE characters at a time, though          }
3425          void AppendFormatV(const CT* szFmt, va_list argList)          
         {  
                 CT szBuf[STD_BUF_SIZE];  
         #ifdef SS_ANSI  
                 int nLen = ssvsprintf(szBuf, STD_BUF_SIZE-1, szFmt, argList);  
         #else  
                 int nLen = ssnprintf(szBuf, STD_BUF_SIZE-1, szFmt, argList);  
         #endif  
                 if ( 0 < nLen )  
                         append(szBuf, nLen);  
         }  
   
         // -------------------------------------------------------------------------  
         // FUNCTION:  FormatV  
         //              void FormatV(PCSTR szFormat, va_list, argList);  
         //            
         // DESCRIPTION:  
         //              This function formats the string with sprintf style format-specs.  
         //              It makes a general guess at required buffer size and then tries  
         //              successively larger buffers until it finds one big enough or a  
         //              threshold (MAX_FMT_TRIES) is exceeded.  
         //  
         // PARAMETERS:  
         //              szFormat - a PCSTR holding the format of the output  
         //              argList - a Microsoft specific va_list for variable argument lists  
         //  
         // RETURN VALUE:  
         // -------------------------------------------------------------------------  
   
         void FormatV(const CT* szFormat, va_list argList)  
         {  
         #ifdef SS_ANSI  
   
                 int nLen        = sslen(szFormat) + STD_BUF_SIZE;  
                 ssvsprintf(GetBuffer(nLen), nLen-1, szFormat, argList);  
                 ReleaseBuffer();  
   
         #else  
   
                 CT* pBuf                        = NULL;  
                 int nChars                      = 1;  
                 int nUsed                       = 0;  
                 size_type nActual       = 0;  
                 int nTry                        = 0;  
   
                 do        
                 {  
                         // Grow more than linearly (e.g. 512, 1536, 3072, etc)  
   
                         nChars                  += ((nTry+1) * FMT_BLOCK_SIZE);  
                         pBuf                    = reinterpret_cast<CT*>(_alloca(sizeof(CT)*nChars));  
                         nUsed                   = ssnprintf(pBuf, nChars-1, szFormat, argList);  
   
                         // Ensure proper NULL termination.  
   
                         nActual                 = nUsed == -1 ? nChars-1 : SSMIN(nUsed, nChars-1);  
                         pBuf[nActual+1]= '\0';  
   
   
                 } while ( nUsed < 0 && nTry++ < MAX_FMT_TRIES );  
   
                 // assign whatever we managed to format  
   
                 assign(pBuf, nActual);  
   
         #endif  
         }  
           
   
         // -------------------------------------------------------------------------  
         // CString Facade Functions:  
         //  
         // The following methods are intended to allow you to use this class as a  
         // drop-in replacement for CString.  
         // -------------------------------------------------------------------------  
         #ifndef SS_ANSI  
                 BSTR AllocSysString() const  
                 {  
                         ostring os;  
                         ssasn(os, *this);  
                         return ::SysAllocString(os.c_str());  
                 }  
         #endif  
   
         int Collate(PCMYSTR szThat) const  
         {  
                 return sscoll(c_str(), length(), szThat, sslen(szThat));  
         }  
   
         int CollateNoCase(PCMYSTR szThat) const  
         {  
                 return ssicoll(c_str(), length(), szThat, sslen(szThat));  
         }  
   
         int Compare(PCMYSTR szThat) const  
         {  
                 return MYBASE::compare(szThat);  
         }  
   
         int CompareNoCase(PCMYSTR szThat)       const  
         {  
                 return ssicmp(c_str(), szThat);  
         }  
   
         int Delete(int nIdx, int nCount=1)  
         {  
                 if ( nIdx < GetLength() )  
                         erase(static_cast<MYSIZE>(nIdx), static_cast<MYSIZE>(nCount));  
   
                 return GetLength();  
         }  
   
         void Empty()  
         {  
                 erase();  
         }  
   
         int Find(CT ch) const  
         {  
                 MYSIZE nIdx     = find_first_of(ch);  
                 return static_cast<int>(MYBASE::npos == nIdx  ? -1 : nIdx);  
         }  
   
         int Find(PCMYSTR szSub) const  
         {  
                 MYSIZE nIdx     = find(szSub);  
                 return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);  
         }  
   
         int Find(CT ch, int nStart) const  
         {  
                 // CString::Find docs say add 1 to nStart when it's not zero  
                 // CString::Find code doesn't do that however.  We'll stick  
                 // with what the code does  
   
                 MYSIZE nIdx     = find_first_of(ch, static_cast<MYSIZE>(nStart));  
                 return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);  
         }  
   
         int Find(PCMYSTR szSub, int nStart) const  
         {  
                 // CString::Find docs say add 1 to nStart when it's not zero  
                 // CString::Find code doesn't do that however.  We'll stick  
                 // with what the code does  
   
                 MYSIZE nIdx     = find(szSub, static_cast<MYSIZE>(nStart));  
                 return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);  
         }  
   
         int FindOneOf(PCMYSTR szCharSet) const  
         {  
                 MYSIZE nIdx = find_first_of(szCharSet);  
                 return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);  
         }  
   
3426  #ifndef SS_ANSI  #ifndef SS_ANSI
3427          void FormatMessage(PCMYSTR szFormat, ...) throw(std::exception)          bool LoadString( UINT nId )
3428          {          {
3429                  va_list argList;              return this->Load( nId );
3430                  va_start(argList, szFormat);          }
3431                  PMYSTR szTemp;  #endif
3432                  if ( ssfmtmsg(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ALLOCATE_BUFFER,          
3433                                             szFormat, 0, 0,          void MakeLower()
3434                                             reinterpret_cast<PMYSTR>(&szTemp), 0, &argList) == 0 ||          {
3435                           szTemp == 0 )              ToLower();
3436                  {          }
3437                          throw std::runtime_error("out of memory");          
3438                  }          void MakeReverse()
3439                  *this = szTemp;          {
3440                  LocalFree(szTemp);              std::reverse( this->begin(), this->end() );
3441                  va_end(argList);          }
3442          }          
3443            void MakeUpper()
3444          void FormatMessage(UINT nFormatId, ...) throw(std::exception)          {
3445          {              ToUpper();
3446                  MYTYPE sFormat;          }
3447                  VERIFY(sFormat.LoadString(nFormatId) != 0);          
3448                  va_list argList;          MYTYPE Mid( int nFirst ) const
3449                  va_start(argList, nFormatId);          {
3450                  PMYSTR szTemp;              return Mid( nFirst, this->GetLength() - nFirst );
3451                  if ( ssfmtmsg(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ALLOCATE_BUFFER,          }
3452                                             sFormat, 0, 0,          
3453                                             reinterpret_cast<PMYSTR>(&szTemp), 0, &argList) == 0 ||          MYTYPE Mid( int nFirst, int nCount ) const
3454                          szTemp == 0)          {
3455                  {              // CString does range checking here.  Since we're trying to emulate it,
3456                          throw std::runtime_error("out of memory");              // we must check too.
3457                  }              
3458                  *this = szTemp;              if ( nFirst < 0 )
3459                  LocalFree(szTemp);                  nFirst = 0;
3460                  va_end(argList);              if ( nCount < 0 )
3461          }                  nCount = 0;
3462  #endif                  
3463                int nSize = static_cast < int >( this->size() );
3464                
3465          // -------------------------------------------------------------------------              if ( nFirst + nCount > nSize )
3466          // GetXXXX -- Direct access to character buffer                  nCount = nSize - nFirst;
3467          // -------------------------------------------------------------------------                  
3468          CT GetAt(int nIdx) const              if ( nFirst > nSize )
3469          {                  return MYTYPE();
3470                  return at(static_cast<MYSIZE>(nIdx));                  
3471          }              ASSERT( nFirst >= 0 );
3472                ASSERT( nFirst + nCount <= nSize );
3473          CT* GetBuffer(int nMinLen=-1)              
3474          {              return this->substr( static_cast < MYSIZE > ( nFirst ),
3475                  return GetBuf(nMinLen);                                   static_cast < MYSIZE > ( nCount ) );
3476          }          }
3477            
3478          CT* GetBufferSetLength(int nLen)          void ReleaseBuffer( int nNewLen = -1 )
3479          {          {
3480                  return BufferSet(nLen);              RelBuf( nNewLen );
3481          }          }
3482            
3483          // GetLength() -- MFC docs say this is the # of BYTES but          int Remove( CT ch )
3484          // in truth it is the number of CHARACTERs (chars or wchar_ts)          {
3485          int GetLength() const              MYSIZE nIdx = 0;
3486          {              int nRemoved = 0;
3487                  return static_cast<int>(length());              while ( ( nIdx = this->find_first_of( ch ) ) != MYBASE::npos ) {
3488          }                  this->erase( nIdx, 1 );
3489                    nRemoved++;
3490                        }
3491          int Insert(int nIdx, CT ch)              return nRemoved;
3492          {          }
3493                  if ( static_cast<MYSIZE>(nIdx) > size() -1 )          
3494                          append(1, ch);          int Replace( CT chOld, CT chNew )
3495                  else          {
3496                          insert(static_cast<MYSIZE>(nIdx), 1, ch);              int nReplaced = 0;
3497                
3498                  return GetLength();              for ( MYITER iter = this->begin(); iter != this->end(); iter++ ) {
3499          }                  if ( *iter == chOld ) {
3500          int Insert(int nIdx, PCMYSTR sz)                      *iter = chNew;
3501          {                      nReplaced++;
3502                  if ( nIdx >= size() )                  }
3503                          append(sz, sslen(sz));              }
3504                  else              
3505                          insert(static_cast<MYSIZE>(nIdx), sz);              return nReplaced;
3506            }
3507                  return GetLength();          
3508          }          int Replace( PCMYSTR szOld, PCMYSTR szNew )
3509            {
3510          bool IsEmpty() const              int nReplaced = 0;
3511          {              MYSIZE nIdx = 0;
3512                  return empty();              MYSIZE nOldLen = sslen( szOld );
3513          }              
3514                if ( 0 != nOldLen ) {
3515          MYTYPE Left(int nCount) const                  // If the replacement string is longer than the one it replaces, this
3516          {                  // string is going to have to grow in size,  Figure out how much
3517                  return substr(0, static_cast<MYSIZE>(nCount));                  // and grow it all the way now, rather than incrementally
3518          }                  
3519                    MYSIZE nNewLen = sslen( szNew );
3520          #ifndef SS_ANSI                  if ( nNewLen > nOldLen ) {
3521          bool LoadString(UINT nId)                      int nFound = 0;
3522          {                      while ( nIdx < this->length() &&
3523                  return this->Load(nId);                              ( nIdx = this->find( szOld, nIdx ) ) != MYBASE::npos ) {
3524          }                          nFound++;
3525          #endif                          nIdx += nOldLen;
3526                        }
3527          void MakeLower()                      this->reserve( this->size() + nFound * ( nNewLen - nOldLen ) );
3528          {                  }
3529                  ToLower();                  
3530          }                  
3531                    static const CT ch = CT( 0 );
3532          void MakeReverse()                  PCMYSTR szRealNew = szNew == 0 ? &ch : szNew;
3533          {                  nIdx = 0;
3534                  std::reverse(begin(), end());                  
3535          }                  while ( nIdx < this->length() &&
3536                            ( nIdx = this->find( szOld, nIdx ) ) != MYBASE::npos ) {
3537          void MakeUpper()                      this->replace( this->begin() + nIdx,
3538          {                                     this->begin() + nIdx + nOldLen, szRealNew );
3539                  ToUpper();                                    
3540          }                      nReplaced++;
3541                        nIdx += nNewLen;
3542          MYTYPE Mid(int nFirst ) const                  }
3543          {              }
3544                  return substr(static_cast<MYSIZE>(nFirst));              
3545          }              return nReplaced;
3546            }
3547          MYTYPE Mid(int nFirst, int nCount) const          
3548          {          int ReverseFind( CT ch ) const
3549                  return substr(static_cast<MYSIZE>(nFirst), static_cast<MYSIZE>(nCount));          {
3550          }              MYSIZE nIdx = this->find_last_of( ch );
3551                return static_cast < int >( MYBASE::npos == nIdx ? -1 : nIdx );
3552          void ReleaseBuffer(int nNewLen=-1)          }
3553          {          
3554                  RelBuf(nNewLen);          // ReverseFind overload that's not in CString but might be useful
3555          }          int ReverseFind( PCMYSTR szFind, MYSIZE pos = MYBASE::npos ) const
3556            {
3557          int Remove(CT ch)              MYSIZE nIdx = this->rfind( 0 == szFind ? MYTYPE() : szFind, pos );
3558          {              return static_cast < int >( MYBASE::npos == nIdx ? -1 : nIdx );
3559                  MYSIZE nIdx             = 0;          }
3560                  int nRemoved    = 0;          
3561                  while ( (nIdx=find_first_of(ch)) != MYBASE::npos )          MYTYPE Right( int nCount ) const
3562                  {          {
3563                          erase(nIdx, 1);              // Range check the count.
3564                          nRemoved++;              
3565                  }              nCount = SSMAX( 0, SSMIN( nCount, static_cast < int >( this->size() ) ) );
3566                  return nRemoved;              return this->substr( this->size() - static_cast < MYSIZE > ( nCount ) );
3567          }          }
3568            
3569          int Replace(CT chOld, CT chNew)          void SetAt( int nIndex, CT ch )
3570          {          {
3571                  int nReplaced   = 0;              ASSERT( this->size() > static_cast < MYSIZE > ( nIndex ) );
3572                  for ( MYITER iter=begin(); iter != end(); iter++ )              this->at( static_cast < MYSIZE > ( nIndex ) ) = ch;
3573                  {          }
3574                          if ( *iter == chOld )          
3575                          {  #ifndef SS_ANSI
3576                                  *iter = chNew;          BSTR SetSysString( BSTR * pbstr ) const
3577                                  nReplaced++;          {
3578                          }              ostring os;
3579                  }              ssasn( os, *this );
3580                  return nReplaced;              if ( !::SysReAllocStringLen( pbstr, os.c_str(), os.length() ) )
3581          }                  throw std::runtime_error( "out of memory" );
3582                    
3583          int Replace(PCMYSTR szOld, PCMYSTR szNew)              ASSERT( *pbstr != 0 );
3584          {              return *pbstr;
3585                  int nReplaced           = 0;          }
3586                  MYSIZE nIdx                     = 0;  #endif
3587                  MYSIZE nOldLen          = sslen(szOld);          
3588                  if ( 0 == nOldLen )          MYTYPE SpanExcluding( PCMYSTR szCharSet ) const
3589                          return 0;          {
3590                MYSIZE pos = this->find_first_of( szCharSet );
3591                  static const CT ch      = CT(0);              return pos == MYBASE::npos ? *this : Left( pos );
3592                  MYSIZE nNewLen          = sslen(szNew);          }
3593                  PCMYSTR szRealNew       = szNew == 0 ? &ch : szNew;          
3594            MYTYPE SpanIncluding( PCMYSTR szCharSet ) const
3595                  while ( (nIdx=find(szOld, nIdx)) != MYBASE::npos )          {
3596                  {              MYSIZE pos = this->find_first_not_of( szCharSet );
3597                          replace(begin()+nIdx, begin()+nIdx+nOldLen, szRealNew);              return pos == MYBASE::npos ? *this : Left( pos );
3598                          nReplaced++;          }
3599                          nIdx += nNewLen;          
3600                  }  #if defined SS_WIN32 && !defined(UNICODE) && !defined(SS_ANSI)
3601                  return nReplaced;          
3602          }          // CString's OemToAnsi and AnsiToOem functions are available only in
3603            // Unicode builds.  However since we're a template we also need a
3604          int ReverseFind(CT ch) const          // runtime check of CT and a reinterpret_cast to account for the fact
3605          {          // that CStdStringW gets instantiated even in non-Unicode builds.
3606                  MYSIZE nIdx     = find_last_of(ch);          
3607                  return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);          void AnsiToOem()
3608          }          {
3609                if ( sizeof( CT ) == sizeof( char ) && !empty() ) {
3610          // ReverseFind overload that's not in CString but might be useful                  ::CharToOem( reinterpret_cast < PCSTR > ( this->c_str() ),
3611          int ReverseFind(PCMYSTR szFind, MYSIZE pos=MYBASE::npos) const                               reinterpret_cast < PSTR > ( GetBuf() ) );
3612          {              } else {
3613                  MYSIZE nIdx     = rfind(0 == szFind ? MYTYPE() : szFind, pos);                  ASSERT( false );
3614                  return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);              }
3615          }          }
3616            
3617          MYTYPE Right(int nCount) const          void OemToAnsi()
3618          {          {
3619                  nCount = SSMIN(nCount, static_cast<int>(size()));              if ( sizeof( CT ) == sizeof( char ) && !empty() ) {
3620                  return substr(size()-static_cast<MYSIZE>(nCount));                  ::OemToChar( reinterpret_cast < PCSTR > ( this->c_str() ),
3621          }                               reinterpret_cast < PSTR > ( GetBuf() ) );
3622                } else {
3623          void SetAt(int nIndex, CT ch)                  ASSERT( false );
3624          {              }
3625                  ASSERT(size() > static_cast<MYSIZE>(nIndex));          }
3626                  at(static_cast<MYSIZE>(nIndex))         = ch;          
3627          }  #endif
3628            
3629          #ifndef SS_ANSI          
3630                  BSTR SetSysString(BSTR* pbstr) const          // -------------------------------------------------------------------------
3631                  {          // Trim and its variants
3632                          ostring os;          // -------------------------------------------------------------------------
3633                          ssasn(os, *this);          MYTYPE & Trim()
3634                          if ( !::SysReAllocStringLen(pbstr, os.c_str(), os.length()) )          {
3635                                  throw std::runtime_error("out of memory");              return TrimLeft().TrimRight();
3636            }
3637                          ASSERT(*pbstr != 0);          
3638                          return *pbstr;          MYTYPE & TrimLeft()
3639                  }          {
3640          #endif              this->erase( this->begin(),
3641                             std::find_if( this->begin(), this->end(),
3642          MYTYPE SpanExcluding(PCMYSTR szCharSet) const                                         NotSpace < CT > () ) );
3643          {                                        
3644                  return Left(find_first_of(szCharSet));              return *this;
3645          }          }
3646            
3647          MYTYPE SpanIncluding(PCMYSTR szCharSet) const          MYTYPE & TrimLeft( CT tTrim )
3648          {          {
3649                  return Left(find_first_not_of(szCharSet));              this->erase( 0, this->find_first_not_of( tTrim ) );
3650          }              return *this;
3651            }
3652          #if !defined(UNICODE) && !defined(SS_ANSI)          
3653            MYTYPE & TrimLeft( PCMYSTR szTrimChars )
3654                  // CString's OemToAnsi and AnsiToOem functions are available only in          {
3655                  // Unicode builds.  However since we're a template we also need a              this->erase( 0, this->find_first_not_of( szTrimChars ) );
3656                  // runtime check of CT and a reinterpret_cast to account for the fact              return *this;
3657                  // that CStdStringW gets instantiated even in non-Unicode builds.          }
3658            
3659                  void AnsiToOem()          MYTYPE & TrimRight()
3660                  {          {
3661                          if ( sizeof(CT) == sizeof(char) && !empty() )              // NOTE:  When comparing reverse_iterators here (MYRITER), I avoid using
3662                          {              // operator!=.  This is because namespace rel_ops also has a template
3663                                  ::CharToOem(reinterpret_cast<PCSTR>(c_str()),              // operator!= which conflicts with the global operator!= already defined
3664                                                          reinterpret_cast<PSTR>(GetBuf()));              // for reverse_iterator in the header <utility>.
3665                          }              // Thanks to John James for alerting me to this.
3666                          else              
3667                          {              MYRITER it =
3668                                  ASSERT(false);                  std::find_if( this->rbegin(), this->rend(), NotSpace < CT > () );
3669                          }              if ( !( this->rend() == it ) )
3670                  }                  this->erase( this->rend() - it );
3671                    
3672                  void OemToAnsi()              this->erase( !( it == this->rend() ) ? this->find_last_of( *it ) + 1 : 0 );
3673                  {              return *this;
3674                          if ( sizeof(CT) == sizeof(char) && !empty() )          }
3675                          {          
3676                                  ::OemToChar(reinterpret_cast<PCSTR>(c_str()),          MYTYPE & TrimRight( CT tTrim )
3677                                                          reinterpret_cast<PSTR>(GetBuf()));          {
3678                          }              MYSIZE nIdx = this->find_last_not_of( tTrim );
3679                          else              this->erase( MYBASE::npos == nIdx ? 0 : ++nIdx );
3680                          {              return *this;
3681                                  ASSERT(false);          }
3682                          }          
3683                  }          MYTYPE & TrimRight( PCMYSTR szTrimChars )
3684            {
3685          #endif              MYSIZE nIdx = this->find_last_not_of( szTrimChars );
3686                        this->erase( MYBASE::npos == nIdx ? 0 : ++nIdx );
3687                return *this;
3688          // -------------------------------------------------------------------------          }
3689          // Trim and its variants          
3690          // -------------------------------------------------------------------------          void FreeExtra()
3691          MYTYPE& Trim()          {
3692          {              MYTYPE mt;
3693                  return TrimLeft().TrimRight();              this->swap( mt );
3694          }              if ( !mt.empty() )
3695                    this->assign( mt.c_str(), mt.size() );
3696          MYTYPE& TrimLeft()          }
3697          {          
3698                  erase(begin(), std::find_if(begin(),end(),NotSpace<CT>(std::locale())));          // I have intentionally not implemented the following CString
3699                  return *this;          // functions.   You cannot make them work without taking advantage
3700          }          // of implementation specific behavior.  However if you absolutely
3701            // MUST have them, uncomment out these lines for "sort-of-like"
3702          MYTYPE&  TrimLeft(CT tTrim)          // their behavior.  You're on your own.
3703          {          
3704                  erase(0, find_first_not_of(tTrim));          //      CT*                             LockBuffer()    { return GetBuf(); }// won't really lock
3705                  return *this;          //      void                    UnlockBuffer(); { }     // why have UnlockBuffer w/o LockBuffer?
3706          }          
3707            // Array-indexing operators.  Required because we defined an implicit cast
3708          MYTYPE&  TrimLeft(PCMYSTR szTrimChars)          // to operator const CT* (Thanks to Julian Selman for pointing this out)
3709          {          
3710                  erase(0, find_first_not_of(szTrimChars));          CT & operator[] ( int nIdx )
3711                  return *this;          {
3712          }              return static_cast < MYBASE * >( this ) ->operator[] ( static_cast <
3713                        MYSIZE > ( nIdx ) );
3714          MYTYPE& TrimRight()          }
3715          {          
3716                  std::locale loc;          const CT & operator[] ( int nIdx ) const
3717                  MYRITER it = std::find_if(rbegin(), rend(), NotSpace<CT>(loc));          {
3718                  if ( rend() != it )              return static_cast < const MYBASE *>( this ) ->operator[] ( static_cast <
3719                          erase(rend() - it);                      MYSIZE >
3720                        ( nIdx ) );
3721                  erase(it != rend() ? find_last_of(*it) + 1 : 0);          }
3722                  return *this;          
3723          }          CT & operator[] ( unsigned int nIdx )
3724            {
3725          MYTYPE&  TrimRight(CT tTrim)              return static_cast < MYBASE * >( this ) ->operator[] ( static_cast <
3726          {                      MYSIZE > ( nIdx ) );
3727                  MYSIZE nIdx     = find_last_not_of(tTrim);          }
3728                  erase(MYBASE::npos == nIdx ? 0 : ++nIdx);          
3729                  return *this;          const CT & operator[] ( unsigned int nIdx ) const
3730          }          {
3731                return static_cast < const MYBASE *>( this ) ->operator[] ( static_cast <
3732          MYTYPE&  TrimRight(PCMYSTR szTrimChars)                      MYSIZE >
3733          {                      ( nIdx ) );
3734                  MYSIZE nIdx     = find_last_not_of(szTrimChars);          }
3735                  erase(MYBASE::npos == nIdx ? 0 : ++nIdx);          
3736                  return *this;  #ifndef SS_NO_IMPLICIT_CAST
3737          }          operator const CT *() const
3738            {
3739          void                    FreeExtra()              return this->c_str();
3740          {          }
3741                  MYTYPE mt;  #endif
3742                  swap(mt);          
3743                  if ( !mt.empty() )          // IStream related functions.  Useful in IPersistStream implementations
3744                          assign(mt.c_str(), mt.size());          
         }  
   
         // I have intentionally not implemented the following CString  
         // functions.   You cannot make them work without taking advantage  
         // of implementation specific behavior.  However if you absolutely  
         // MUST have them, uncomment out these lines for "sort-of-like"  
         // their behavior.  You're on your own.  
   
 //      CT*                             LockBuffer()    { return GetBuf(); }// won't really lock  
 //      void                    UnlockBuffer(); { }     // why have UnlockBuffer w/o LockBuffer?  
   
         // Array-indexing operators.  Required because we defined an implicit cast  
         // to operator const CT* (Thanks to Julian Selman for pointing this out)  
         CT& operator[](int nIdx)  
         {  
                 return MYBASE::operator[](static_cast<MYSIZE>(nIdx));  
         }  
   
         const CT& operator[](int nIdx) const  
         {  
                 return MYBASE::operator[](static_cast<MYSIZE>(nIdx));  
         }  
   
         CT& operator[](unsigned int nIdx)  
         {  
                 return MYBASE::operator[](static_cast<MYSIZE>(nIdx));  
         }  
   
         const CT& operator[](unsigned int nIdx) const  
         {  
                 return MYBASE::operator[](static_cast<MYSIZE>(nIdx));  
         }  
   
         operator const CT*() const  
         {  
                 return c_str();  
         }  
   
         // IStream related functions.  Useful in IPersistStream implementations  
   
3745  #ifdef SS_INC_COMDEF  #ifdef SS_INC_COMDEF
3746            
3747          // struct SSSHDR - useful for non Std C++ persistence schemes.          // struct SSSHDR - useful for non Std C++ persistence schemes.
3748          typedef struct SSSHDR          typedef struct SSSHDR
3749          {          {
3750                  BYTE    byCtrl;              BYTE byCtrl;
3751                  ULONG   nChars;              ULONG nChars;
3752          } SSSHDR;       // as in "Standard String Stream Header"          }
3753            SSSHDR;                   // as in "Standard String Stream Header"
3754          #define SSSO_UNICODE    0x01    // the string is a wide string          
3755          #define SSSO_COMPRESS   0x02    // the string is compressed  #define SSSO_UNICODE 0x01    // the string is a wide string
3756    #define SSSO_COMPRESS 0x02    // the string is compressed
3757          // -------------------------------------------------------------------------          
3758          // FUNCTION: StreamSize          // -------------------------------------------------------------------------
3759          // REMARKS:          // FUNCTION: StreamSize
3760          //              Returns how many bytes it will take to StreamSave() this CStdString          // REMARKS:
3761          //              object to an IStream.          //              Returns how many bytes it will take to StreamSave() this CStdString
3762          // -------------------------------------------------------------------------          //              object to an IStream.
3763          ULONG StreamSize() const          // -------------------------------------------------------------------------
3764          {          ULONG StreamSize() const
3765                  // Control header plus string          {
3766                  ASSERT(size()*sizeof(CT) < 0xffffffffUL - sizeof(SSSHDR));              // Control header plus string
3767                  return (size() * sizeof(CT)) + sizeof(SSSHDR);              ASSERT( this->size() * sizeof( CT ) < 0xffffffffUL - sizeof( SSSHDR ) );
3768          }              return ( this->size() * sizeof( CT ) ) + sizeof( SSSHDR );
3769            }
3770          // -------------------------------------------------------------------------          
3771          // FUNCTION: StreamSave          // -------------------------------------------------------------------------
3772          // REMARKS:          // FUNCTION: StreamSave
3773          //              Saves this CStdString object to a COM IStream.          // REMARKS:
3774          // -------------------------------------------------------------------------          //              Saves this CStdString object to a COM IStream.
3775          HRESULT StreamSave(IStream* pStream) const          // -------------------------------------------------------------------------
3776          {          HRESULT StreamSave( IStream * pStream ) const
3777                  ASSERT(size()*sizeof(CT) < 0xffffffffUL - sizeof(SSSHDR));          {
3778                  HRESULT hr              = E_FAIL;              ASSERT( this->size() * sizeof( CT ) < 0xffffffffUL - sizeof( SSSHDR ) );
3779                  ASSERT(pStream != 0);              HRESULT hr = E_FAIL;
3780                  SSSHDR hdr;              ASSERT( pStream != 0 );
3781                  hdr.byCtrl              = sizeof(CT) == 2 ? SSSO_UNICODE : 0;              SSSHDR hdr;
3782                  hdr.nChars              = size();              hdr.byCtrl = sizeof( CT ) == 2 ? SSSO_UNICODE : 0;
3783                hdr.nChars = this->size();
3784                
3785                  if ( FAILED(hr=pStream->Write(&hdr, sizeof(SSSHDR), 0)) )              
3786                          TRACE(_T("StreamSave: Cannot write control header, ERR=0x%X\n"),hr);              if ( FAILED( hr = pStream->Write( &hdr, sizeof( SSSHDR ), 0 ) ) ) {
3787                  else if ( empty() )                  TRACE( _T( "StreamSave: Cannot write control header, ERR=0x%X\n" ),
3788                          ;               // nothing to write                         hr );
3789                  else if ( FAILED(hr=pStream->Write(c_str(), size()*sizeof(CT), 0)) )              } else if ( empty() ) {
3790                          TRACE(_T("StreamSave: Cannot write string to stream 0x%X\n"), hr);                  ;                   // nothing to write
3791                } else if ( FAILED( hr = pStream->Write( this->c_str(),
3792                  return hr;                                       this->size() * sizeof( CT ), 0 ) ) ) {
3793          }                  TRACE( _T( "StreamSave: Cannot write string to stream 0x%X\n" ), hr );
3794                }
3795                
3796          // -------------------------------------------------------------------------              return hr;
3797          // FUNCTION: StreamLoad          }
3798          // REMARKS:          
3799          //              This method loads the object from an IStream.          
3800          // -------------------------------------------------------------------------          // -------------------------------------------------------------------------
3801          HRESULT StreamLoad(IStream* pStream)          // FUNCTION: StreamLoad
3802          {          // REMARKS:
3803                  ASSERT(pStream != 0);          //              This method loads the object from an IStream.
3804                  SSSHDR hdr;          // -------------------------------------------------------------------------
3805                  HRESULT hr                      = E_FAIL;          HRESULT StreamLoad( IStream * pStream )
3806            {
3807                  if ( FAILED(hr=pStream->Read(&hdr, sizeof(SSSHDR), 0)) )              ASSERT( pStream != 0 );
3808                  {              SSSHDR hdr;
3809                          TRACE(_T("StreamLoad: Cant read control header, ERR=0x%X\n"), hr);              HRESULT hr = E_FAIL;
3810                  }              
3811                  else if ( hdr.nChars > 0 )              if ( FAILED( hr = pStream->Read( &hdr, sizeof( SSSHDR ), 0 ) ) ) {
3812                  {                  TRACE( _T( "StreamLoad: Cant read control header, ERR=0x%X\n" ), hr );
3813                          ULONG nRead             = 0;              } else if ( hdr.nChars > 0 ) {
3814                          PMYSTR pMyBuf   = BufferSet(hdr.nChars);                  ULONG nRead = 0;
3815                    PMYSTR pMyBuf = BufferSet( hdr.nChars );
3816                          // If our character size matches the character size of the string                  
3817                          // we're trying to read, then we can read it directly into our                  // If our character size matches the character size of the string
3818                          // buffer. Otherwise, we have to read into an intermediate buffer                  // we're trying to read, then we can read it directly into our
3819                          // and convert.                  // buffer. Otherwise, we have to read into an intermediate buffer
3820                                            // and convert.
3821                          if ( (hdr.byCtrl & SSSO_UNICODE) != 0 )                  
3822                          {                  if ( ( hdr.byCtrl & SSSO_UNICODE ) != 0 ) {
3823                                  ULONG nBytes    = hdr.nChars * sizeof(wchar_t);                      ULONG nBytes = hdr.nChars * sizeof( wchar_t );
3824                                  if ( sizeof(CT) == sizeof(wchar_t) )                      if ( sizeof( CT ) == sizeof( wchar_t ) ) {
3825                                  {                          if ( FAILED( hr = pStream->Read( pMyBuf, nBytes, &nRead ) ) )
3826                                          if ( FAILED(hr=pStream->Read(pMyBuf, nBytes, &nRead)) )                              TRACE( _T( "StreamLoad: Cannot read string: 0x%X\n" ),
3827                                                  TRACE(_T("StreamLoad: Cannot read string: 0x%X\n"), hr);                                     hr );
3828                                  }                      } else {
3829                                  else                          PWSTR pBufW =
3830                                  {                                    reinterpret_cast < PWSTR > ( _alloca( ( nBytes ) + 1 ) );
3831                                          PWSTR pBufW = reinterpret_cast<PWSTR>(_alloca((nBytes)+1));                          if ( FAILED( hr = pStream->Read( pBufW, nBytes, &nRead ) ) )
3832                                          if ( FAILED(hr=pStream->Read(pBufW, nBytes, &nRead)) )                              TRACE( _T( "StreamLoad: Cannot read string: 0x%X\n" ),
3833                                                  TRACE(_T("StreamLoad: Cannot read string: 0x%X\n"), hr);                                     hr );
3834                                          else                          else
3835                                                  sscpy(pMyBuf, pBufW, hdr.nChars);                              sscpy( pMyBuf, pBufW, hdr.nChars );
3836                                  }                      }
3837                          }                  } else {
3838                          else                      ULONG nBytes = hdr.nChars * sizeof( char );
3839                          {                      if ( sizeof( CT ) == sizeof( char ) ) {
3840                                  ULONG nBytes    = hdr.nChars * sizeof(char);                          if ( FAILED( hr = pStream->Read( pMyBuf, nBytes, &nRead ) ) )
3841                                  if ( sizeof(CT) == sizeof(char) )                              TRACE( _T( "StreamLoad: Cannot read string: 0x%X\n" ),
3842                                  {                                     hr );
3843                                          if ( FAILED(hr=pStream->Read(pMyBuf, nBytes, &nRead)) )                      } else {
3844                                                  TRACE(_T("StreamLoad: Cannot read string: 0x%X\n"), hr);                          PSTR pBufA = reinterpret_cast < PSTR > ( _alloca( nBytes ) );
3845                                  }                          if ( FAILED( hr = pStream->Read( pBufA, hdr.nChars, &nRead ) ) )
3846                                  else                              TRACE( _T( "StreamLoad: Cannot read string: 0x%X\n" ),
3847                                  {                                     hr );
3848                                          PSTR pBufA = reinterpret_cast<PSTR>(_alloca(nBytes));                          else
3849                                          if ( FAILED(hr=pStream->Read(pBufA, hdr.nChars, &nRead)) )                              sscpy( pMyBuf, pBufA, hdr.nChars );
3850                                                  TRACE(_T("StreamLoad: Cannot read string: 0x%X\n"), hr);                      }
3851                                          else                  }
3852                                                  sscpy(pMyBuf, pBufA, hdr.nChars);              } else {
3853                                  }                  this->erase();
3854                          }              }
3855                  }              return hr;
3856                  else          }
                 {  
                         this->erase();  
                 }  
                 return hr;  
         }  
3857  #endif // #ifdef SS_INC_COMDEF  #endif // #ifdef SS_INC_COMDEF
3858            
3859  #ifndef SS_ANSI  #ifndef SS_ANSI
3860            
3861          // SetResourceHandle/GetResourceHandle.  In MFC builds, these map directly          // SetResourceHandle/GetResourceHandle.  In MFC builds, these map directly
3862          // to AfxSetResourceHandle and AfxGetResourceHandle.  In non-MFC builds they          // to AfxSetResourceHandle and AfxGetResourceHandle.  In non-MFC builds they
3863          // 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
3864          // 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
3865          // 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
3866          // but it's better than nothing.          // but it's better than nothing.
3867            
3868          #ifdef _MFC_VER  #ifdef _MFC_VER
3869                  static void SetResourceHandle(HMODULE hNew)          static void SetResourceHandle( HMODULE hNew )
3870                  {          {
3871                          AfxSetResourceHandle(hNew);              AfxSetResourceHandle( hNew );
3872                  }          }
3873                  static HMODULE GetResourceHandle()          static HMODULE GetResourceHandle()
3874                  {          {
3875                          return AfxGetResourceHandle();              return AfxGetResourceHandle();
3876                  }          }
3877          #else  #else
3878                  static void SetResourceHandle(HMODULE hNew)  static void SetResourceHandle( HMODULE hNew )
3879                  {          {
3880                          SSResourceHandle() = hNew;              SSResourceHandle() = hNew;
3881                  }          }
3882                  static HMODULE GetResourceHandle()          static HMODULE GetResourceHandle()
3883                  {          {
3884                          return SSResourceHandle();              return SSResourceHandle();
3885                  }          }
3886          #endif  #endif
3887            
3888  #endif  #endif
3889  };  };
3890    
3891    // -----------------------------------------------------------------------------
3892    // MSVC USERS: HOW TO EXPORT CSTDSTRING FROM A DLL
3893    //
3894    // If you are using MS Visual C++ and you want to export CStdStringA and
3895    // CStdStringW from a DLL, then all you need to
3896    //
3897    //              1.      make sure that all components link to the same DLL version
3898    //                      of the CRT (not the static one).
3899    //              2.      Uncomment the 3 lines of code below
3900    //              3.      #define 2 macros per the instructions in MS KnowledgeBase
3901    //                      article Q168958.  The macros are:
3902    //
3903    //              MACRO           DEFINTION WHEN EXPORTING                DEFINITION WHEN IMPORTING
3904    //              -----           ------------------------                -------------------------
3905    //              SSDLLEXP        (nothing, just #define it)              extern
3906    //              SSDLLSPEC       __declspec(dllexport)                   __declspec(dllimport)
3907    //
3908    //              Note that these macros must be available to ALL clients who want to
3909    //              link to the DLL and use the class.  If they
3910    //
3911    // A word of advice: Don't bother.
3912    //
3913    // Really, it is not necessary to export CStdString functions from a DLL.  I
3914    // never do.  In my projects, I do generally link to the DLL version of the
3915    // Standard C++ Library, but I do NOT attempt to export CStdString functions.
3916    // I simply include the header where it is needed and allow for the code
3917    // redundancy.
3918    //
3919    // That redundancy is a lot less than you think.  This class does most of its
3920    // work via the Standard C++ Library, particularly the base_class basic_string<>
3921    // member functions.  Most of the functions here are small enough to be inlined
3922    // anyway.  Besides, you'll find that in actual practice you use less than 1/2
3923    // of the code here, even in big projects and different modules will use as
3924    // little as 10% of it.  That means a lot less functions actually get linked
3925    // your binaries.  If you export this code from a DLL, it ALL gets linked in.
3926    //
3927    // I've compared the size of the binaries from exporting vs NOT exporting.  Take
3928    // my word for it -- exporting this code is not worth the hassle.
3929    //
3930    // -----------------------------------------------------------------------------
3931    //#pragma warning(disable:4231) // non-standard extension ("extern template")
3932    //      SSDLLEXP template class SSDLLSPEC CStdStr<char>;
3933    //      SSDLLEXP template class SSDLLSPEC CStdStr<wchar_t>;
3934    
3935    
3936    // =============================================================================
3937    //                                              END OF CStdStr INLINE FUNCTION DEFINITIONS
3938    // =============================================================================
3939    
3940    //      Now typedef our class names based upon this humongous template
3941    
3942    typedef CStdStr < char >CStdStringA;    // a better std::string
3943    typedef CStdStr < wchar_t > CStdStringW;        // a better std::wstring
3944    typedef CStdStr < OLECHAR > CStdStringO;        // almost always CStdStringW
3945    
3946  // -----------------------------------------------------------------------------  // -----------------------------------------------------------------------------
3947  // CStdStr friend addition functions defined as inline  // CStdStr addition functions defined as inline
3948  // -----------------------------------------------------------------------------  // -----------------------------------------------------------------------------
 template<typename CT>  
 inline  
 CStdStr<CT> operator+(const  CStdStr<CT>& str1, const  CStdStr<CT>& str2)  
 {  
         CStdStr<CT> strRet(SSREF(str1));  
         strRet.append(str2);  
         return strRet;  
 }  
3949    
 template<typename CT>    
 inline  
 CStdStr<CT> operator+(const  CStdStr<CT>& str, CT t)  
 {  
         // this particular overload is needed for disabling reference counting  
         // though it's only an issue from line 1 to line 2  
3950    
3951          CStdStr<CT> strRet(SSREF(str)); // 1  inline CStdStringA operator+( const CStdStringA & s1, const CStdStringA & s2 )
         strRet.append(1, t);                            // 2  
         return strRet;  
 }  
   
 template<typename CT>  
 inline  
 CStdStr<CT> operator+(const  CStdStr<CT>& str, PCSTR pA)  
3952  {  {
3953          return CStdStr<CT>(str) + CStdStr<CT>(pA);      CStdStringA sRet( SSREF( s1 ) );
3954        sRet.append( s2 );
3955        return sRet;
3956  }  }
3957    inline CStdStringA operator+( const CStdStringA & s1,
3958  template<typename CT>                                CStdStringA::value_type t )
 inline  
 CStdStr<CT> operator+(PCSTR pA, const  CStdStr<CT>& str)  
3959  {  {
3960          CStdStr<CT> strRet(pA);      CStdStringA sRet( SSREF( s1 ) );
3961          strRet.append(str);      sRet.append( 1, t );
3962          return strRet;      return sRet;
3963  }  }
3964    inline CStdStringA operator+( const CStdStringA & s1, PCSTR pA )
3965  template<typename CT>  {
3966  inline      CStdStringA sRet( SSREF( s1 ) );
3967  CStdStr<CT> operator+(const CStdStr<CT>& str, PCWSTR pW)      sRet.append( pA );
3968  {      return sRet;
         return CStdStr<CT>(SSREF(str)) + CStdStr<CT>(pW);  
3969  }  }
3970    inline CStdStringA operator+( PCSTR pA, const CStdStringA & sA )
 template<typename CT>  
 inline  
 CStdStr<CT> operator+(PCWSTR pW, const CStdStr<CT>& str)  
3971  {  {
3972          CStdStr<CT> strRet(pW);      CStdStringA sRet;
3973          strRet.append(str);      CStdStringA::size_type nObjSize = sA.size();
3974          return strRet;      CStdStringA::size_type nLitSize =
3975            static_cast < CStdStringA::size_type > ( sslen( pA ) );
3976            
3977        sRet.reserve( nLitSize + nObjSize );
3978        sRet.assign( pA );
3979        sRet.append( sA );
3980        return sRet;
3981  }  }
3982    
 #ifdef SS_INC_COMDEF  
         template<typename CT>  
         inline  
         CStdStr<CT> operator+(const _bstr_t& bstr, const CStdStr<CT>& str)  
         {  
                 return static_cast<const CT*>(bstr) + str;  
         }  
   
         template<typename CT>  
         inline  
         CStdStr<CT> operator+(const CStdStr<CT>& str, const _bstr_t& bstr)  
         {  
                 return str + static_cast<const CT*>(bstr);  
         }  
 #endif  
   
   
   
   
 // -----------------------------------------------------------------------------  
 // These versions of operator+ provided by Scott Hathaway in order to allow  
 // CStdString to build on Sun Unix systems.  
 // -----------------------------------------------------------------------------  
   
 #if defined(__SUNPRO_CC_COMPAT) || defined(__SUNPRO_CC)  
3983    
3984  // Made non-template versions due to "undefined" errors on Sun Forte compiler  inline CStdStringA operator+( const CStdStringA & s1, const CStdStringW & s2 )
 // when linking with friend template functions  
 inline  
 CStdStr<wchar_t> operator+(const CStdStr<wchar_t>& str1,  
                                                    const CStdStr<wchar_t>& str2)  
3985  {  {
3986          CStdStr<wchar_t> strRet(SSREF(str1));      return s1 + CStdStringA( s2 );
         strRet.append(str2);  
         return strRet;  
3987  }  }
3988    inline CStdStringW operator+( const CStdStringW & s1, const CStdStringW & s2 )
 inline  
 CStdStr<wchar_t> operator+(const CStdStr<wchar_t>& str, wchar_t t)  
3989  {  {
3990          // this particular overload is needed for disabling reference counting      CStdStringW sRet( SSREF( s1 ) );
3991          // though it's only an issue from line 1 to line 2      sRet.append( s2 );
3992        return sRet;
         CStdStr<wchar_t> strRet(SSREF(str));    // 1  
         strRet.append(1, t);                                    // 2  
         return strRet;  
3993  }  }
3994    inline CStdStringA operator+( const CStdStringA & s1, PCWSTR pW )
 inline  
 CStdStr<wchar_t> operator+(const CStdStr<wchar_t>& str, PCWSTR pW)  
3995  {  {
3996          return CStdStr<wchar_t>(str) + CStdStr<wchar_t>(pW);      return s1 + CStdStringA( pW );
3997  }  }
3998    
3999  inline  #ifdef UNICODE
4000  CStdStr<wchar_t> operator+(PCWSTR pA, const  CStdStr<wchar_t>& str)  inline CStdStringW operator+( PCWSTR pW, const CStdStringA & sA )
4001  {  {
4002          CStdStr<wchar_t> strRet(pA);      return CStdStringW( pW ) + CStdStringW( SSREF( sA ) );
         strRet.append(str);  
         return strRet;  
4003  }  }
4004    inline CStdStringW operator+( PCSTR pA, const CStdStringW & sW )
4005  inline  {
4006  CStdStr<wchar_t> operator+(const CStdStr<wchar_t>& str, PCSTR pW)      return CStdStringW( pA ) + sW;
 {  
         return CStdStr<wchar_t>(SSREF(str)) + CStdStr<wchar_t>(pW);  
4007  }  }
4008    #else
4009  inline  inline CStdStringA operator+( PCWSTR pW, const CStdStringA & sA )
 CStdStr<wchar_t> operator+(PCSTR pW, const CStdStr<wchar_t>& str)  
4010  {  {
4011          CStdStr<wchar_t> strRet(pW);      return CStdStringA( pW ) + sA;
         strRet.append(str);  
         return strRet;  
4012  }  }
4013    inline CStdStringA operator+( PCSTR pA, const CStdStringW & sW )
 inline  
 CStdStr<char> operator+(const  CStdStr<char>& str1, const  CStdStr<char>& str2)  
4014  {  {
4015          CStdStr<char> strRet(SSREF(str1));      return pA + CStdStringA( sW );
         strRet.append(str2);  
         return strRet;  
4016  }  }
4017    #endif
4018    
4019  inline  // ...Now the wide string versions.
4020  CStdStr<char> operator+(const  CStdStr<char>& str, char t)  inline CStdStringW operator+( const CStdStringW & s1,
4021                                  CStdStringW::value_type t )
4022  {  {
4023          // this particular overload is needed for disabling reference counting      CStdStringW sRet( SSREF( s1 ) );
4024          // though it's only an issue from line 1 to line 2      sRet.append( 1, t );
4025        return sRet;
         CStdStr<char> strRet(SSREF(str));       // 1  
         strRet.append(1, t);                            // 2  
         return strRet;  
4026  }  }
4027    inline CStdStringW operator+( const CStdStringW & s1, PCWSTR pW )
 inline  
 CStdStr<char> operator+(const  CStdStr<char>& str, PCSTR pA)  
4028  {  {
4029          return CStdStr<char>(str) + CStdStr<char>(pA);      CStdStringW sRet( SSREF( s1 ) );
4030        sRet.append( pW );
4031        return sRet;
4032  }  }
4033    inline CStdStringW operator+( PCWSTR pW, const CStdStringW & sW )
 inline  
 CStdStr<char> operator+(PCSTR pA, const  CStdStr<char>& str)  
4034  {  {
4035          CStdStr<char> strRet(pA);      CStdStringW sRet;
4036          strRet.append(str);      CStdStringW::size_type nObjSize = sW.size();
4037          return strRet;      CStdStringA::size_type nLitSize =
4038            static_cast < CStdStringW::size_type > ( sslen( pW ) );
4039            
4040        sRet.reserve( nLitSize + nObjSize );
4041        sRet.assign( pW );
4042        sRet.append( sW );
4043        return sRet;
4044  }  }
4045    
4046  inline  inline CStdStringW operator+( const CStdStringW & s1, const CStdStringA & s2 )
4047  CStdStr<char> operator+(const CStdStr<char>& str, PCWSTR pW)  {
4048  {      return s1 + CStdStringW( s2 );
         return CStdStr<char>(SSREF(str)) + CStdStr<char>(pW);  
4049  }  }
4050    inline CStdStringW operator+( const CStdStringW & s1, PCSTR pA )
 inline  
 CStdStr<char> operator+(PCWSTR pW, const CStdStr<char>& str)  
4051  {  {
4052          CStdStr<char> strRet(pW);      return s1 + CStdStringW( pA );
         strRet.append(str);  
         return strRet;  
4053  }  }
4054    
4055    
4056  #endif // defined(__SUNPRO_CC_COMPAT) || defined(__SUNPRO_CC)  // New-style format function is a template
4057    
4058    #ifdef SS_SAFE_FORMAT
4059    
4060  // =============================================================================  template <>
4061  //                                              END OF CStdStr INLINE FUNCTION DEFINITIONS  struct FmtArg <CStdStringA >
4062  // =============================================================================  {
4063        explicit FmtArg( const CStdStringA & arg ) : a_( arg )
4064  //      Now typedef our class names based upon this humongous template      {}
4065        PCSTR operator() () const
4066        {
4067            return a_.c_str();
4068        }
4069        const CStdStringA & a_;
4070    private:
4071        FmtArg < CStdStringA > &operator=( const FmtArg < CStdStringA > & )
4072        {
4073            return * this;
4074        }
4075    };
4076    template <>
4077    struct FmtArg <CStdStringW >
4078    {
4079        explicit FmtArg( const CStdStringW & arg ) : a_( arg )
4080        {}
4081        PCWSTR operator() () const
4082        {
4083            return a_.c_str();
4084        }
4085        const CStdStringW & a_;
4086    private:
4087        FmtArg < CStdStringW > &operator=( const FmtArg < CStdStringW > & )
4088        {
4089            return * this;
4090        }
4091    };
4092    
4093  typedef CStdStr<char>           CStdStringA;    // a better std::string  template <>
4094  typedef CStdStr<wchar_t>        CStdStringW;    // a better std::wstring  struct FmtArg <std::string >
4095  typedef CStdStr<OLECHAR>        CStdStringO;    // almost always CStdStringW  {
4096        explicit FmtArg( const std::string & arg ) : a_( arg )
4097        {}
4098        PCSTR operator() () const
4099        {
4100            return a_.c_str();
4101        }
4102        const std::string & a_;
4103    private:
4104        FmtArg < std::string > &operator=( const FmtArg < std::string > & )
4105        {
4106            return * this;
4107        }
4108    };
4109    template <>
4110    struct FmtArg <std::wstring >
4111    {
4112        explicit FmtArg( const std::wstring & arg ) : a_( arg )
4113        {}
4114        PCWSTR operator() () const
4115        {
4116            return a_.c_str();
4117        }
4118        const std::wstring & a_;
4119    private:
4120        FmtArg < std::wstring > &operator=( const FmtArg < std::wstring > & )
4121        {
4122            return * this;
4123        }
4124    };
4125    #endif // #ifdef SS_SAFEFORMAT
4126    
4127  #ifndef SS_ANSI  #ifndef SS_ANSI
4128          // SSResourceHandle: our MFC-like resource handle  // SSResourceHandle: our MFC-like resource handle
4129          inline HMODULE& SSResourceHandle()  inline HMODULE & SSResourceHandle()
4130          {  {
4131                  static HMODULE hModuleSS        = GetModuleHandle(0);      static HMODULE hModuleSS = GetModuleHandle( 0 );
4132                  return hModuleSS;      return hModuleSS;
4133          }  }
4134  #endif  #endif
4135    
4136    
# Line 2773  typedef CStdStr<OLECHAR>       CStdStringO;    // Line 4140  typedef CStdStr<OLECHAR>       CStdStringO;    //
4140  // we use the exact same format.  // we use the exact same format.
4141    
4142  #ifdef _MFC_VER  #ifdef _MFC_VER
4143          inline CArchive& AFXAPI operator<<(CArchive& ar, const CStdStringA& strA)  inline CArchive & AFXAPI operator<<( CArchive & ar, const CStdStringA & strA )
4144          {  {
4145                  CString strTemp = strA;      CString strTemp = strA;
4146                  return ar << strTemp;      return ar << strTemp;
4147          }  }
         inline CArchive& AFXAPI operator<<(CArchive& ar, const CStdStringW& strW)  
         {  
                 CString strTemp = strW;  
                 return ar << strTemp;  
         }  
   
         inline CArchive& AFXAPI operator>>(CArchive& ar, CStdStringA& strA)  
         {  
                 CString strTemp;  
                 ar >> strTemp;  
                 strA = strTemp;  
                 return ar;  
         }  
         inline CArchive& AFXAPI operator>>(CArchive& ar, CStdStringW& strW)  
         {  
                 CString strTemp;  
                 ar >> strTemp;  
                 strW = strTemp;  
                 return ar;  
         }  
 #endif  // #ifdef _MFC_VER -- (i.e. is this MFC?)  
4148    
4149    inline CArchive & AFXAPI operator<<( CArchive & ar, const CStdStringW & strW )
4150    {
4151        CString strTemp = strW;
4152        return ar << strTemp;
4153    }
4154    
4155    inline CArchive & AFXAPI operator>>( CArchive & ar, CStdStringA & strA )
4156    {
4157        CString strTemp;
4158        ar >> strTemp;
4159        strA = strTemp;
4160        return ar;
4161    }
4162    
4163    inline CArchive & AFXAPI operator>>( CArchive & ar, CStdStringW & strW )
4164    {
4165        CString strTemp;
4166        ar >> strTemp;
4167        strW = strTemp;
4168        return ar;
4169    }
4170    #endif // #ifdef _MFC_VER -- (i.e. is this MFC?)
4171    
 // -----------------------------------------------------------------------------  
 // HOW TO EXPORT CSTDSTRING FROM A DLL  
 //  
 // If you want to export CStdStringA and CStdStringW from a DLL, then all you  
 // need to  
 //              1.      make sure that all components link to the same DLL version  
 //                      of the CRT (not the static one).  
 //              2.      Uncomment the 3 lines of code below  
 //              3.      #define 2 macros per the instructions in MS KnowledgeBase  
 //                      article Q168958.  The macros are:  
 //  
 //              MACRO           DEFINTION WHEN EXPORTING                DEFINITION WHEN IMPORTING  
 //              -----           ------------------------                -------------------------  
 //              SSDLLEXP        (nothing, just #define it)              extern  
 //              SSDLLSPEC       __declspec(dllexport)                   __declspec(dllimport)  
 //  
 //              Note that these macros must be available to ALL clients who want to  
 //              link to the DLL and use the class.  If they  
 // -----------------------------------------------------------------------------  
 //#pragma warning(disable:4231) // non-standard extension ("extern template")  
 //      SSDLLEXP template class SSDLLSPEC CStdStr<char>;  
 //      SSDLLEXP template class SSDLLSPEC CStdStr<wchar_t>;  
4172    
4173    
4174  // -----------------------------------------------------------------------------  // -----------------------------------------------------------------------------
4175  // GLOBAL FUNCTION:  WUFormat  // GLOBAL FUNCTION:  WUFormat
4176  //              CStdStringA WUFormat(UINT nId, ...);  //              CStdStringA WUFormat(UINT nId, ...);
4177  //              CStdStringA WUFormat(PCSTR szFormat, ...);  //              CStdStringA WUFormat(PCSTR szFormat, ...);
4178  //  //
4179  // REMARKS:  // REMARKS:
4180  //              This function allows the caller for format and return a CStdStringA  //              This function allows the caller for format and return a CStdStringA
4181  //              object with a single line of code.  //              object with a single line of code.
4182  // -----------------------------------------------------------------------------  // -----------------------------------------------------------------------------
4183    
4184    inline CStdStringA WUFormatA( PCSTR szFormat, ... )
4185    {
4186        va_list argList;
4187        va_start( argList, szFormat );
4188        CStdStringA strOut;
4189        strOut.FormatV( szFormat, argList );
4190        va_end( argList );
4191        return strOut;
4192    }
4193    inline CStdStringW WUFormatW( PCWSTR szwFormat, ... )
4194    {
4195        va_list argList;
4196        va_start( argList, szwFormat );
4197        CStdStringW strOut;
4198        strOut.FormatV( szwFormat, argList );
4199        va_end( argList );
4200        return strOut;
4201    }
4202    
4203  #ifdef SS_ANSI  #ifdef SS_ANSI
4204  #else  #else
4205          inline CStdStringA WUFormatA(UINT nId, ...)  inline CStdStringA WUFormatA( UINT nId, ... )
4206          {  {
4207                  va_list argList;      va_list argList;
4208                  va_start(argList, nId);      va_start( argList, nId );
4209    
4210                  CStdStringA strFmt;      CStdStringA strFmt;
4211                  CStdStringA strOut;      CStdStringA strOut;
4212                  if ( strFmt.Load(nId) )      if ( strFmt.Load( nId ) )
4213                          strOut.FormatV(strFmt, argList);          strOut.FormatV( strFmt, argList );
4214    
4215                  va_end(argList);      va_end( argList );
4216                  return strOut;      return strOut;
4217          }  }
4218          inline CStdStringA WUFormatA(PCSTR szFormat, ...)  
4219          {  inline CStdStringW WUFormatW( UINT nId, ... )
4220                  va_list argList;  {
4221                  va_start(argList, szFormat);      va_list argList;
4222                  CStdStringA strOut;      va_start( argList, nId );
4223                  strOut.FormatV(szFormat, argList);  
4224                  va_end(argList);      CStdStringW strFmt;
4225                  return strOut;      CStdStringW strOut;
4226          }      if ( strFmt.Load( nId ) )
4227            strOut.FormatV( strFmt, argList );
4228          inline CStdStringW WUFormatW(UINT nId, ...)  
4229          {      va_end( argList );
4230                  va_list argList;      return strOut;
4231                  va_start(argList, nId);  }
   
                 CStdStringW strFmt;  
                 CStdStringW strOut;  
                 if ( strFmt.Load(nId) )  
                         strOut.FormatV(strFmt, argList);  
   
                 va_end(argList);  
                 return strOut;  
         }  
         inline CStdStringW WUFormatW(PCWSTR szwFormat, ...)  
         {  
                 va_list argList;  
                 va_start(argList, szwFormat);  
                 CStdStringW strOut;  
                 strOut.FormatV(szwFormat, argList);  
                 va_end(argList);  
                 return strOut;  
         }  
4232  #endif // #ifdef SS_ANSI  #endif // #ifdef SS_ANSI
4233    
4234  #ifdef SS_ANSI  
4235  #else  
4236          // -------------------------------------------------------------------------  #if defined(SS_WIN32) && !defined (SS_ANSI)
4237          // FUNCTION: WUSysMessage  // -------------------------------------------------------------------------
4238          //       CStdStringA WUSysMessageA(DWORD dwError, DWORD dwLangId=SS_DEFLANGID);  // FUNCTION: WUSysMessage
4239          //       CStdStringW WUSysMessageW(DWORD dwError, DWORD dwLangId=SS_DEFLANGID);  //       CStdStringA WUSysMessageA(DWORD dwError, DWORD dwLangId=SS_DEFLANGID);
4240          //            //       CStdStringW WUSysMessageW(DWORD dwError, DWORD dwLangId=SS_DEFLANGID);
4241          // DESCRIPTION:  //
4242          //       This function simplifies the process of obtaining a string equivalent  // DESCRIPTION:
4243          //       of a system error code returned from GetLastError().  You simply  //       This function simplifies the process of obtaining a string equivalent
4244          //       supply the value returned by GetLastError() to this function and the  //       of a system error code returned from GetLastError().  You simply
4245          //       corresponding system string is returned in the form of a CStdStringA.  //       supply the value returned by GetLastError() to this function and the
4246          //  //       corresponding system string is returned in the form of a CStdStringA.
4247          // PARAMETERS:  //
4248          //       dwError - a DWORD value representing the error code to be translated  // PARAMETERS:
4249          //       dwLangId - the language id to use.  defaults to english.  //       dwError - a DWORD value representing the error code to be translated
4250          //  //       dwLangId - the language id to use.  defaults to english.
4251          // RETURN VALUE:  //
4252          //       a CStdStringA equivalent of the error code.  Currently, this function  // RETURN VALUE:
4253          //       only returns either English of the system default language strings.    //       a CStdStringA equivalent of the error code.  Currently, this function
4254          // -------------------------------------------------------------------------  //       only returns either English of the system default language strings.
4255          #define SS_DEFLANGID MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT)  // -------------------------------------------------------------------------
4256          inline CStdStringA WUSysMessageA(DWORD dwError, DWORD dwLangId=SS_DEFLANGID)  #define SS_DEFLANGID MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT)
4257          {  inline CStdStringA WUSysMessageA( DWORD dwError, DWORD dwLangId = SS_DEFLANGID )
4258                  CHAR szBuf[512];  {
4259        CHAR szBuf[ 512 ];
4260                  if ( 0 != ::FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError,      
4261                                                                     dwLangId, szBuf, 511, NULL) )      if ( 0 != ::FormatMessageA( FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError,
4262                          return WUFormatA("%s (0x%X)", szBuf, dwError);                                  dwLangId, szBuf, 511, NULL ) )
4263                  else          return WUFormatA( "%s (0x%X)", szBuf, dwError );
4264                          return WUFormatA("Unknown error (0x%X)", dwError);      else
4265          }          return WUFormatA( "Unknown error (0x%X)", dwError );
4266          inline CStdStringW WUSysMessageW(DWORD dwError, DWORD dwLangId=SS_DEFLANGID)  }
4267          {  inline CStdStringW WUSysMessageW( DWORD dwError, DWORD dwLangId = SS_DEFLANGID )
4268                  WCHAR szBuf[512];  {
4269        WCHAR szBuf[ 512 ];
4270                  if ( 0 != ::FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError,      
4271                                                                     dwLangId, szBuf, 511, NULL) )      if ( 0 != ::FormatMessageW( FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError,
4272                          return WUFormatW(L"%s (0x%X)", szBuf, dwError);                                  dwLangId, szBuf, 511, NULL ) )
4273                  else          return WUFormatW( L"%s (0x%X)", szBuf, dwError );
4274                          return WUFormatW(L"Unknown error (0x%X)", dwError);      else
4275          }          return WUFormatW( L"Unknown error (0x%X)", dwError );
4276    }
4277  #endif  #endif
4278    
4279  // Define TCHAR based friendly names for some of these functions  // Define TCHAR based friendly names for some of these functions
4280    
4281  #ifdef UNICODE  #ifdef UNICODE
4282          #define CStdString                              CStdStringW  //#define CStdString                            CStdStringW
4283          #define WUSysMessage                    WUSysMessageW  typedef CStdStringW CStdString;
4284          #define WUFormat                                WUFormatW  #define WUSysMessage   WUSysMessageW
4285  #else  #define WUFormat    WUFormatW
4286          #define CStdString                              CStdStringA  #else
4287          #define WUSysMessage                    WUSysMessageA  //#define CStdString                            CStdStringA
4288          #define WUFormat                                WUFormatA  typedef CStdStringA CStdString;
4289    #define WUSysMessage   WUSysMessageA
4290    #define WUFormat    WUFormatA
4291  #endif  #endif
4292    
4293  // ...and some shorter names for the space-efficient  // ...and some shorter names for the space-efficient
4294    
4295  #define WUSysMsg                                        WUSysMessage  #define WUSysMsg     WUSysMessage
4296  #define WUSysMsgA                                       WUSysMessageA  #define WUSysMsgA     WUSysMessageA
4297  #define WUSysMsgW                                       WUSysMessageW  #define WUSysMsgW     WUSysMessageW
4298  #define WUFmtA                                          WUFormatA  #define WUFmtA      WUFormatA
4299  #define WUFmtW                                          WUFormatW  #define WUFmtW      WUFormatW
4300  #define WUFmt                                           WUFormat  #define WUFmt      WUFormat
4301  #define WULastErrMsg()                          WUSysMessage(::GetLastError())  #define WULastErrMsg()    WUSysMessage(::GetLastError())
4302  #define WULastErrMsgA()                         WUSysMessageA(::GetLastError())  #define WULastErrMsgA()    WUSysMessageA(::GetLastError())
4303  #define WULastErrMsgW()                         WUSysMessageW(::GetLastError())  #define WULastErrMsgW()    WUSysMessageW(::GetLastError())
4304    
4305    
4306  // -----------------------------------------------------------------------------  // -----------------------------------------------------------------------------
4307  // FUNCTIONAL COMPARATORS:  // FUNCTIONAL COMPARATORS:
4308  // REMARKS:  // REMARKS:
4309  //              These structs are derived from the std::binary_function template.  They  //              These structs are derived from the std::binary_function template.  They
4310  //              give us functional classes (which may be used in Standard C++ Library  //              give us functional classes (which may be used in Standard C++ Library
4311  //              collections and algorithms) that perform case-insensitive comparisons of  //              collections and algorithms) that perform case-insensitive comparisons of
4312  //              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
4313  //               proper string but in the wrong case.  //               proper string but in the wrong case.
4314  // -----------------------------------------------------------------------------  // -----------------------------------------------------------------------------
4315  #define StdStringLessNoCaseW            SSLNCW  // avoid VC compiler warning 4786  #define StdStringLessNoCaseW  SSLNCW  // avoid VC compiler warning 4786
4316  #define StdStringEqualsNoCaseW          SSENCW            #define StdStringEqualsNoCaseW  SSENCW
4317  #define StdStringLessNoCaseA            SSLNCA            #define StdStringLessNoCaseA  SSLNCA
4318  #define StdStringEqualsNoCaseA          SSENCA            #define StdStringEqualsNoCaseA  SSENCA
4319    
4320  #ifdef UNICODE  #ifdef UNICODE
4321          #define StdStringLessNoCase             SSLNCW            #define StdStringLessNoCase  SSLNCW
4322          #define StdStringEqualsNoCase   SSENCW            #define StdStringEqualsNoCase SSENCW
4323  #else  #else
4324          #define StdStringLessNoCase             SSLNCA            #define StdStringLessNoCase  SSLNCA
4325          #define StdStringEqualsNoCase   SSENCA            #define StdStringEqualsNoCase SSENCA
4326  #endif  #endif
4327    
4328  struct StdStringLessNoCaseW  struct StdStringLessNoCaseW: std::binary_function < CStdStringW, CStdStringW,
4329          : std::binary_function<CStdStringW, CStdStringW, bool>              bool >
4330  {  {
4331          inline      inline
4332          bool operator()(const CStdStringW& sLeft, const CStdStringW& sRight) const      bool operator() ( const CStdStringW & sLeft,
4333          { return ssicmp(sLeft.c_str(), sRight.c_str()) < 0; }                        const CStdStringW & sRight ) const
4334        {
4335            return ssicmp( sLeft.c_str(), sRight.c_str() ) < 0;
4336        }
4337  };  };
4338  struct StdStringEqualsNoCaseW  struct StdStringEqualsNoCaseW: std::binary_function < CStdStringW, CStdStringW,
4339          : std::binary_function<CStdStringW, CStdStringW, bool>              bool >
4340  {  {
4341          inline      inline
4342          bool operator()(const CStdStringW& sLeft, const CStdStringW& sRight) const      bool operator() ( const CStdStringW & sLeft,
4343          { return ssicmp(sLeft.c_str(), sRight.c_str()) == 0; }                        const CStdStringW & sRight ) const
4344        {
4345            return ssicmp( sLeft.c_str(), sRight.c_str() ) == 0;
4346        }
4347  };  };
4348  struct StdStringLessNoCaseA  struct StdStringLessNoCaseA: std::binary_function < CStdStringA, CStdStringA,
4349          : std::binary_function<CStdStringA, CStdStringA, bool>              bool >
4350  {  {
4351          inline      inline
4352          bool operator()(const CStdStringA& sLeft, const CStdStringA& sRight) const      bool operator() ( const CStdStringA & sLeft,
4353          { return ssicmp(sLeft.c_str(), sRight.c_str()) < 0; }                        const CStdStringA & sRight ) const
4354        {
4355            return ssicmp( sLeft.c_str(), sRight.c_str() ) < 0;
4356        }
4357  };  };
4358  struct StdStringEqualsNoCaseA  struct StdStringEqualsNoCaseA: std::binary_function < CStdStringA, CStdStringA,
4359          : std::binary_function<CStdStringA, CStdStringA, bool>              bool >
4360  {  {
4361          inline      inline
4362          bool operator()(const CStdStringA& sLeft, const CStdStringA& sRight) const      bool operator() ( const CStdStringA & sLeft,
4363          { return ssicmp(sLeft.c_str(), sRight.c_str()) == 0; }                        const CStdStringA & sRight ) const
4364        {
4365            return ssicmp( sLeft.c_str(), sRight.c_str() ) == 0;
4366        }
4367  };  };
4368    
4369  // 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
4370    
4371  #ifdef TRACE_DEFINED_HERE  #ifdef TRACE_DEFINED_HERE
4372          #undef TRACE  #undef TRACE
4373          #undef TRACE_DEFINED_HERE  #undef TRACE_DEFINED_HERE
4374  #endif  #endif
4375    
4376    
 #endif  // #ifndef STDSTRING_H  
4377    // These std::swap specializations come courtesy of Mike Crusader.
4378    
4379    //namespace std
4380    //{
4381    //      inline void swap(CStdStringA& s1, CStdStringA& s2) throw()
4382    //      {
4383    //              s1.swap(s2);
4384    //      }
4385    //      template<>
4386    //      inline void swap(CStdStringW& s1, CStdStringW& s2) throw()
4387    //      {
4388    //              s1.swap(s2);
4389    //      }
4390    //}
4391    
4392    // Turn back on any Borland warnings we turned off.
4393    
4394    #ifdef __BORLANDC__
4395    #pragma option pop              // Turn back on inline function warnings
4396    //      #pragma warn +inl   // Turn back on inline function warnings
4397    #endif
4398    
4399    #endif // #ifndef STDSTRING_H

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

  ViewVC Help
Powered by ViewVC 1.1.26