跨平台的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
原文地址:https://www.cnblogs.com/jojodru/p/4002267.html