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