zoukankan      html  css  js  c++  java
  • 跨平台的CStdString类,实现了CString的接口

    在实际工作中,std的string功能相对于MFC的CString来说,实在是相形见绌。

    CStdString类实现了CString的功能,支持跨平台。

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