rtoss - Blame information for rev 182

Subversion Repositories:
Rev:
Rev Author Line No. Line
181 roytam 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ähne
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ähne 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  
182 roytam 325 // Avoid multiple inclusion
326  
327 #ifndef STDSTRING_H
328 #define STDSTRING_H
329  
330 // When using VC, turn off browser references
181 roytam 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 // Borland warnings to turn off
341  
342 #ifdef __BORLANDC__
343     #pragma option push -w-inl
344 //      #pragma warn -inl   // Turn off inline function warnings
345 #endif
346  
347 // SS_IS_INTRESOURCE
348 // -----------------
349 //              A copy of IS_INTRESOURCE from VC7.  Because old VC6 version of winuser.h
350 //              doesn't have this.
351  
352 #define SS_IS_INTRESOURCE(_r) (false)
353  
354 #if !defined (SS_ANSI) && defined(_MSC_VER)
355         #undef SS_IS_INTRESOURCE
356         #if defined(_WIN64)
357                 #define SS_IS_INTRESOURCE(_r) (((unsigned __int64)(_r) >> 16) == 0)
358         #else
359                 #define SS_IS_INTRESOURCE(_r) (((unsigned long)(_r) >> 16) == 0)
360         #endif
361 #endif
362  
363  
364 // MACRO: SS_UNSIGNED
365 // ------------------
366 //      This macro causes the addition of a constructor and assignment operator
367 //      which take unsigned characters.  CString has such functions and in order
368 //      to provide maximum CString-compatability, this code needs them as well.
369 //      In practice you will likely never need these functions...
370  
371 //#define SS_UNSIGNED
372  
373 #ifdef SS_ALLOW_UNSIGNED_CHARS
374         #define SS_UNSIGNED
375 #endif
376  
377 // MACRO: SS_SAFE_FORMAT
378 // ---------------------
379 //      This macro provides limited compatability with a questionable CString
380 //      "feature".  You can define it in order to avoid a common problem that
381 //      people encounter when switching from CString to CStdString.
382 //
383 //      To illustrate the problem -- With CString, you can do this:
384 //
385 //          CString sName("Joe");
386 //          CString sTmp;
387 //          sTmp.Format("My name is %s", sName);                    // WORKS!
388 //
389 //      However if you were to try this with CStdString, your program would
390 //      crash.
391 //
392 //          CStdString sName("Joe");
393 //          CStdString sTmp;
394 //          sTmp.Format("My name is %s", sName);                    // CRASHES!
395 //
396 //      You must explicitly call c_str() or cast the object to the proper type
397 //
398 //          sTmp.Format("My name is %s", sName.c_str());            // WORKS!
399 //          sTmp.Format("My name is %s", static_cast<PCSTR>(sName));// WORKS!
400 //          sTmp.Format("My name is %s", (PCSTR)sName);                         // WORKS!
401 //
402 //      This is because it is illegal to pass anything but a POD type as a
403 //      variadic argument to a variadic function (i.e. as one of the "..."
404 //      arguments).  The type const char* is a POD type.  The type CStdString
405 //      is not.  Of course, neither is the type CString, but CString lets you do
406 //      it anyway due to the way they laid out the class in binary.  I have no
407 //      control over this in CStdString since I derive from whatever
408 //      implementation of basic_string is available.
409 //
410 //      However if you have legacy code (which does this) that you want to take
411 //      out of the MFC world and you don't want to rewrite all your calls to
412 //      Format(), then you can define this flag and it will no longer crash.
413 //
414 //      Note however that this ONLY works for Format(), not sprintf, fprintf,
415 //      etc.  If you pass a CStdString object to one of those functions, your
416 //      program will crash.  Not much I can do to get around this, short of
417 //      writing substitutes for those functions as well.
418  
419 #define SS_SAFE_FORMAT  // use new template style Format() function
420  
421  
422 // MACRO: SS_NO_IMPLICIT_CAST
423 // --------------------------
424 //      Some people don't like the implicit cast to const char* (or rather to
425 //      const CT*) that CStdString (and MFC's CString) provide.  That was the
426 //      whole reason I created this class in the first place, but hey, whatever
427 //      bakes your cake.  Just #define this macro to get rid of the the implicit
428 //      cast.
429  
430 //#define SS_NO_IMPLICIT_CAST // gets rid of operator const CT*()
431  
432  
433 // MACRO: SS_NO_REFCOUNT
434 // ---------------------
435 //              turns off reference counting at the assignment level.  Only needed
436 //              for the version of basic_string<> that comes with Visual C++ versions
437 //              6.0 or earlier, and only then in some heavily multithreaded scenarios.
438 //              Uncomment it if you feel you need it.
439  
440 //#define SS_NO_REFCOUNT
441  
442 // MACRO: SS_WIN32
443 // ---------------
444 //      When this flag is set, we are building code for the Win32 platform and
445 //      may use Win32 specific functions (such as LoadString).  This gives us
446 //      a couple of nice extras for the code.
447 //
448 //      Obviously, Microsoft's is not the only compiler available for Win32 out
449 //      there.  So I can't just check to see if _MSC_VER is defined to detect
450 //      if I'm building on Win32.  So for now, if you use MS Visual C++ or
451 //      Borland's compiler, I turn this on.  Otherwise you may turn it on
452 //      yourself, if you prefer
453  
454 #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(_WIN32)
455     #define SS_WIN32
456 #endif
457  
458 // MACRO: SS_ANSI
459 // --------------
460 //      When this macro is defined, the code attempts only to use ANSI/ISO
461 //      standard library functions to do it's work.  It will NOT attempt to use
462 //      any Win32 of Visual C++ specific functions -- even if they are
463 //      available.  You may define this flag yourself to prevent any Win32
464 //      of VC++ specific functions from being called.
465  
466 // If we're not on Win32, we MUST use an ANSI build
467  
468 #ifndef SS_WIN32
469     #if !defined(SS_NO_ANSI)
470         #define SS_ANSI
471     #endif
472 #endif
473  
474 // MACRO: SS_ALLOCA
475 // ----------------
476 //      Some implementations of the Standard C Library have a non-standard
477 //      function known as alloca().  This functions allows one to allocate a
478 //      variable amount of memory on the stack.  It is needed to implement
479 //      the ASCII/MBCS conversion macros.
480 //
481 //      I wanted to find some way to determine automatically if alloca() is
482 //              available on this platform via compiler flags but that is asking for
483 //              trouble.  The crude test presented here will likely need fixing on
484 //              other platforms.  Therefore I'll leave it up to you to fiddle with
485 //              this test to determine if it exists.  Just make sure SS_ALLOCA is or
486 //              is not defined as appropriate and you control this feature.
487  
488 #if defined(_MSC_VER) && !defined(SS_ANSI)
489         #define SS_ALLOCA
490 #endif
491  
182 roytam 492  
181 roytam 493 // MACRO: SS_MBCS
494 // --------------
182 roytam 495 //              Setting this macro means you are using MBCS characters.  In MSVC builds,
496 //              this macro gets set automatically by detection of the preprocessor flag
497 //              _MBCS.  For other platforms you may set it manually if you wish.  The
498 //              only effect it currently has is to cause the allocation of more space
499 //              for wchar_t --> char conversions.
181 roytam 500 //              Note that MBCS does not mean UNICODE.
501 //
502 //      #define SS_MBCS
503 //
182 roytam 504  
181 roytam 505 #ifdef _MBCS
506         #define SS_MBCS
507 #endif
508  
509  
182 roytam 510 // MACRO SS_NO_LOCALE
511 // ------------------
512 // If your implementation of the Standard C++ Library lacks the <locale> header,
513 // you can #define this macro to make your code build properly.  Note that this
514 // is some of my newest code and frankly I'm not very sure of it, though it does
515 // pass my unit tests.
181 roytam 516  
182 roytam 517 // #define SS_NO_LOCALE
518  
519  
181 roytam 520 // Compiler Error regarding _UNICODE and UNICODE
521 // -----------------------------------------------
522 // Microsoft header files are screwy.  Sometimes they depend on a preprocessor
523 // flag named "_UNICODE".  Other times they check "UNICODE" (note the lack of
524 // leading underscore in the second version".  In several places, they silently
525 // "synchronize" these two flags this by defining one of the other was defined.
526 // In older version of this header, I used to try to do the same thing.
527 //
528 // However experience has taught me that this is a bad idea.  You get weird
529 // compiler errors that seem to indicate things like LPWSTR and LPTSTR not being
530 // equivalent in UNICODE builds, stuff like that (when they MUST be in a proper
531 // UNICODE  build).  You end up scratching your head and saying, "But that HAS
532 // to compile!".
533 //
534 // So what should you do if you get this error?
535 //
536 // Make sure that both macros (_UNICODE and UNICODE) are defined before this
537 // file is included.  You can do that by either
538 //
539 //              a) defining both yourself before any files get included
540 //              b) including the proper MS headers in the proper order
541 //              c) including this file before any other file, uncommenting
542 //                 the #defines below, and commenting out the #errors
543 //
544 //      Personally I recommend solution a) but it's your call.
545  
546 #ifdef _MSC_VER
547         #if defined (_UNICODE) && !defined (UNICODE)
548                 #error UNICODE defined  but not UNICODE
549         //      #define UNICODE  // no longer silently fix this
550         #endif
551         #if defined (UNICODE) && !defined (_UNICODE)
552                 #error Warning, UNICODE defined  but not _UNICODE
553         //      #define _UNICODE  // no longer silently fix this
554         #endif
555 #endif
556  
557  
558 // -----------------------------------------------------------------------------
559 // MIN and MAX.  The Standard C++ template versions go by so many names (at
560 // at least in the MS implementation) that you never know what's available
561 // -----------------------------------------------------------------------------
562 template<class Type>
563 inline const Type& SSMIN(const Type& arg1, const Type& arg2)
564 {
565         return arg2 < arg1 ? arg2 : arg1;
566 }
567 template<class Type>
568 inline const Type& SSMAX(const Type& arg1, const Type& arg2)
569 {
570         return arg2 > arg1 ? arg2 : arg1;
571 }
572  
573 // If they have not #included W32Base.h (part of my W32 utility library) then
574 // we need to define some stuff.  Otherwise, this is all defined there.
575  
576 #if !defined(W32BASE_H)
577  
578         // If they want us to use only standard C++ stuff (no Win32 stuff)
579  
580         #ifdef SS_ANSI
581  
582                 // On Win32 we have TCHAR.H so just include it.  This is NOT violating
583         // the spirit of SS_ANSI as we are not calling any Win32 functions here.
584  
585                 #ifdef SS_WIN32
586  
587                         #include <TCHAR.H>
588                         #include <WTYPES.H>
589                         #ifndef STRICT
590                                 #define STRICT
591                         #endif
592  
593         // ... but on non-Win32 platforms, we must #define the types we need.
594  
595                 #else
596  
597                         typedef const char*             PCSTR;
598                         typedef char*                   PSTR;
599                         typedef const wchar_t*  PCWSTR;
600                         typedef wchar_t*                PWSTR;
601                         #ifdef UNICODE
602                                 typedef wchar_t         TCHAR;
603                         #else
604                                 typedef char            TCHAR;
605                         #endif
606                         typedef wchar_t                 OLECHAR;
607  
608                 #endif  // #ifndef _WIN32
609  
610  
611                 // Make sure ASSERT and verify are defined using only ANSI stuff
612  
613                 #ifndef ASSERT
614                         #include <assert.h>
615                         #define ASSERT(f) assert((f))
616                 #endif
617                 #ifndef VERIFY
618                         #ifdef _DEBUG
619                                 #define VERIFY(x) ASSERT((x))
620                         #else
621                                 #define VERIFY(x) x
622                         #endif
623                 #endif
624  
625         #else // ...else SS_ANSI is NOT defined
626  
627                 #include <TCHAR.H>
628                 #include <WTYPES.H>
629                 #ifndef STRICT
630                         #define STRICT
631                 #endif
632  
633                 // Make sure ASSERT and verify are defined
634  
635                 #ifndef ASSERT
636                         #include <crtdbg.h>
637                         #define ASSERT(f) _ASSERTE((f))
638                 #endif
639                 #ifndef VERIFY
640                         #ifdef _DEBUG
641                                 #define VERIFY(x) ASSERT((x))
642                         #else
643                                 #define VERIFY(x) x
644                         #endif
645                 #endif
646  
647         #endif // #ifdef SS_ANSI
648  
649         #ifndef UNUSED
650                 #define UNUSED(x) x
651         #endif
652  
653 #endif // #ifndef W32BASE_H
654  
655 // Standard headers needed
656  
657 #include <string>                       // basic_string
658 #include <algorithm>            // for_each, etc.
659 #include <functional>           // for StdStringLessNoCase, et al
182 roytam 660 #ifndef SS_NO_LOCALE
661         #include <locale>                       // for various facets
662 #endif
181 roytam 663  
664 // If this is a recent enough version of VC include comdef.h, so we can write
665 // member functions to deal with COM types & compiler support classes e.g.
666 // _bstr_t
667  
668 #if defined (_MSC_VER) && (_MSC_VER >= 1100)
669         #include <comdef.h>
670         #define SS_INC_COMDEF           // signal that we #included MS comdef.h file
671         #define STDSTRING_INC_COMDEF
672         #define SS_NOTHROW __declspec(nothrow)
673 #else
674         #define SS_NOTHROW
675 #endif
676  
677 #ifndef TRACE
678         #define TRACE_DEFINED_HERE
679         #define TRACE
680 #endif
681  
682 // Microsoft defines PCSTR, PCWSTR, etc, but no PCTSTR.  I hate to use the
683 // versions with the "L" in front of them because that's a leftover from Win 16
684 // days, even though it evaluates to the same thing.  Therefore, Define a PCSTR
685 // as an LPCTSTR.
686  
687 #if !defined(PCTSTR) && !defined(PCTSTR_DEFINED)
688         typedef const TCHAR*                    PCTSTR;
689         #define PCTSTR_DEFINED
690 #endif
691  
692 #if !defined(PCOLESTR) && !defined(PCOLESTR_DEFINED)
693         typedef const OLECHAR*                  PCOLESTR;
694         #define PCOLESTR_DEFINED
695 #endif
696  
697 #if !defined(POLESTR) && !defined(POLESTR_DEFINED)
698         typedef OLECHAR*                                POLESTR;
699         #define POLESTR_DEFINED
700 #endif
701  
702 #if !defined(PCUSTR) && !defined(PCUSTR_DEFINED)
703         typedef const unsigned char*    PCUSTR;
704         typedef unsigned char*                  PUSTR;
705         #define PCUSTR_DEFINED
706 #endif
707  
708  
709 // SGI compiler 7.3 doesnt know these  types - oh and btw, remember to use
710 // -LANG:std in the CXX Flags
711 #if defined(__sgi)
712     typedef unsigned long           DWORD;
713     typedef void *                  LPCVOID;
714 #endif
715  
716  
717 // SS_USE_FACET macro and why we need it:
718 //
719 // Since I'm a good little Standard C++ programmer, I use locales.  Thus, I
720 // need to make use of the use_facet<> template function here.   Unfortunately,
721 // this need is complicated by the fact the MS' implementation of the Standard
722 // C++ Library has a non-standard version of use_facet that takes more
723 // arguments than the standard dictates.  Since I'm trying to write CStdString
724 // to work with any version of the Standard library, this presents a problem.
725 //
726 // The upshot of this is that I can't do 'use_facet' directly.  The MS' docs
727 // tell me that I have to use a macro, _USE() instead.  Since _USE obviously
728 // won't be available in other implementations, this means that I have to write
729 // my OWN macro -- SS_USE_FACET -- that evaluates either to _USE or to the
730 // standard, use_facet.
731 //
732 // If you are having trouble with the SS_USE_FACET macro, in your implementation
733 // of the Standard C++ Library, you can define your own version of SS_USE_FACET.
734  
735 #ifndef schMSG
736         #define schSTR(x)          #x
737         #define schSTR2(x)      schSTR(x)
738         #define schMSG(desc) message(__FILE__ "(" schSTR2(__LINE__) "):" #desc)
739 #endif
740  
741 #ifndef SS_USE_FACET
742  
743         // STLPort #defines a macro (__STL_NO_EXPLICIT_FUNCTION_TMPL_ARGS) for
744         // all MSVC builds, erroneously in my opinion.  It causes problems for
745         // my SS_ANSI builds.  In my code, I always comment out that line.  You'll
746         // find it in   \stlport\config\stl_msvc.h
747  
748         #if defined(__SGI_STL_PORT) && (__SGI_STL_PORT >= 0x400 )
749  
750                 #if defined(__STL_NO_EXPLICIT_FUNCTION_TMPL_ARGS) && defined(_MSC_VER)
751                         #ifdef SS_ANSI
752                                 #pragma schMSG(__STL_NO_EXPLICIT_FUNCTION_TMPL_ARGS defined!!)
753                         #endif
754                 #endif
755                 #define SS_USE_FACET(loc, fac) std::use_facet<fac >(loc)
756  
757         #elif defined(_MSC_VER )
758  
759                 #define SS_USE_FACET(loc, fac) std::_USE(loc, fac)
760  
761         // ...and
762         #elif defined(_RWSTD_NO_TEMPLATE_ON_RETURN_TYPE)
763  
764         #define SS_USE_FACET(loc, fac) std::use_facet(loc, (fac*)0)
765  
766         #else
767  
768                 #define SS_USE_FACET(loc, fac) std::use_facet<fac >(loc)
769  
770         #endif
771  
772 #endif
773  
774 // =============================================================================
775 // UNICODE/MBCS conversion macros.  Made to work just like the MFC/ATL ones.
776 // =============================================================================
777  
778 #include <wchar.h>      // Added to Std Library with Amendment #1.
779  
780 // First define the conversion helper functions.  We define these regardless of
781 // any preprocessor macro settings since their names won't collide.
782  
783 // Not sure if we need all these headers.   I believe ANSI says we do.
784  
785 #include <stdio.h>
786 #include <stdarg.h>
787 #include <wctype.h>
788 #include <ctype.h>
789 #include <stdlib.h>
790 #ifndef va_start
791         #include <varargs.h>
792 #endif
793  
794  
182 roytam 795 #ifdef SS_NO_LOCALE
181 roytam 796  
182 roytam 797         #if defined(_WIN32) || defined (_WIN32_WCE)
181 roytam 798  
182 roytam 799                 inline PWSTR StdCodeCvt(PWSTR pDstW, int nDst, PCSTR pSrcA, int nSrc,
800                         UINT acp=CP_ACP)
801                 {
802                         ASSERT(0 != pSrcA);
803                         ASSERT(0 != pDstW);
804                         pDstW[0] = '\0';
805                         MultiByteToWideChar(acp, 0, pSrcA, nSrc, pDstW, nDst);
806                         return pDstW;
807                 }
808                 inline PWSTR StdCodeCvt(PWSTR pDstW, int nDst, PCUSTR pSrcA, int nSrc,
809                         UINT acp=CP_ACP)
810                 {
811                         return StdCodeCvt(pDstW, nDst, (PCSTR)pSrcA, nSrc, acp);
812                 }
181 roytam 813  
182 roytam 814                 inline PSTR StdCodeCvt(PSTR pDstA, int nDst, PCWSTR pSrcW, int nSrc,
815                         UINT acp=CP_ACP)
816                 {
817                         ASSERT(0 != pDstA);
818                         ASSERT(0 != pSrcW);
819                         pDstA[0] = '\0';
820                         WideCharToMultiByte(acp, 0, pSrcW, nSrc, pDstA, nDst, 0, 0);
821                         return pDstA;
822                 }
823                 inline PUSTR StdCodeCvt(PUSTR pDstA, int nDst, PCWSTR pSrcW, int nSrc,
824                         UINT acp=CP_ACP)
825                 {
826                         return (PUSTR)StdCodeCvt((PSTR)pDstA, nDst, pSrcW, nSrc, acp);
827                 }
828         #else
829         #endif
181 roytam 830  
182 roytam 831 #else
181 roytam 832  
182 roytam 833         // StdCodeCvt - made to look like Win32 functions WideCharToMultiByte
834         //                              and MultiByteToWideChar but uses locales in SS_ANSI
835         //                              builds.  There are a number of overloads.
836         //              First argument is the destination buffer.
837         //              Second argument is the source buffer
838         //#if defined (SS_ANSI) || !defined (SS_WIN32)
181 roytam 839  
182 roytam 840         // 'SSCodeCvt' - shorthand name for the codecvt facet we use
181 roytam 841  
182 roytam 842         typedef std::codecvt<wchar_t, char, mbstate_t> SSCodeCvt;
181 roytam 843  
182 roytam 844         inline PWSTR StdCodeCvt(PWSTR pDstW, int nDst, PCSTR pSrcA, int nSrc,
845                 const std::locale& loc=std::locale())
846         {
847                 ASSERT(0 != pSrcA);
848                 ASSERT(0 != pDstW);
181 roytam 849  
182 roytam 850                 pDstW[0]                                        = '\0';
181 roytam 851  
182 roytam 852                 if ( nSrc > 0 )
853                 {
854                         PCSTR pNextSrcA                 = pSrcA;
855                         PWSTR pNextDstW                 = pDstW;
856                         SSCodeCvt::result res   = SSCodeCvt::ok;
857                         const SSCodeCvt& conv   = SS_USE_FACET(loc, SSCodeCvt);
858                         SSCodeCvt::state_type st= { 0 };
859                         res                                             = conv.in(st,
860                                                                                 pSrcA, pSrcA + nSrc, pNextSrcA,
861                                                                                 pDstW, pDstW + nDst, pNextDstW);
181 roytam 862  
182 roytam 863                         ASSERT(SSCodeCvt::ok == res);
864                         ASSERT(SSCodeCvt::error != res);
865                         ASSERT(pNextDstW >= pDstW);
866                         ASSERT(pNextSrcA >= pSrcA);
181 roytam 867  
182 roytam 868                         // Null terminate the converted string
181 roytam 869  
182 roytam 870                         if ( pNextDstW - pDstW > nDst )
871                                 *(pDstW + nDst) = '\0';
872                         else
873                                 *pNextDstW = '\0';
874                 }
875                 return pDstW;
181 roytam 876         }
182 roytam 877         inline PWSTR StdCodeCvt(PWSTR pDstW, int nDst, PCUSTR pSrcA, int nSrc,
878                 const std::locale& loc=std::locale())
181 roytam 879         {
182 roytam 880                 return StdCodeCvt(pDstW, nDst, (PCSTR)pSrcA, nSrc, loc);
181 roytam 881         }
882  
182 roytam 883         inline PSTR StdCodeCvt(PSTR pDstA, int nDst, PCWSTR pSrcW, int nSrc,
884                 const std::locale& loc=std::locale())
181 roytam 885         {
886                 ASSERT(0 != pDstA);
887                 ASSERT(0 != pSrcW);
182 roytam 888  
889                 pDstA[0]                                        = '\0';
890  
891                 if ( nSrc > 0 )
892                 {
893                         PSTR pNextDstA                  = pDstA;
894                         PCWSTR pNextSrcW                = pSrcW;
895                         SSCodeCvt::result res   = SSCodeCvt::ok;
896                         const SSCodeCvt& conv   = SS_USE_FACET(loc, SSCodeCvt);
897                         SSCodeCvt::state_type st= { 0 };
898                         res                                             = conv.out(st,
899                                                                                 pSrcW, pSrcW + nSrc, pNextSrcW,
900                                                                                 pDstA, pDstA + nDst, pNextDstA);
901  
902                         ASSERT(SSCodeCvt::error != res);
903                         ASSERT(SSCodeCvt::ok == res);   // strict, comment out for sanity
904                         ASSERT(pNextDstA >= pDstA);
905                         ASSERT(pNextSrcW >= pSrcW);
906  
907                         // Null terminate the converted string
908  
909                         if ( pNextDstA - pDstA > nDst )
910                                 *(pDstA + nDst) = '\0';
911                         else
912                                 *pNextDstA = '\0';
913                 }
914                 return pDstA;
181 roytam 915         }
182 roytam 916  
917         inline PUSTR StdCodeCvt(PUSTR pDstA, int nDst, PCWSTR pSrcW, int nSrc,
918                 const std::locale& loc=std::locale())
181 roytam 919         {
182 roytam 920                 return (PUSTR)StdCodeCvt((PSTR)pDstA, nDst, pSrcW, nSrc, loc);
181 roytam 921         }
922  
923 #endif
924  
182 roytam 925  
926  
181 roytam 927 // Unicode/MBCS conversion macros are only available on implementations of
928 // the "C" library that have the non-standard _alloca function.  As far as I
929 // know that's only Microsoft's though I've heard that the function exists
930 // elsewhere.  
931  
932 #if defined(SS_ALLOCA) && !defined SS_NO_CONVERSION
933  
934     #include <malloc.h> // needed for _alloca
935  
936     // Define our conversion macros to look exactly like Microsoft's to
937     // facilitate using this stuff both with and without MFC/ATL
938  
939     #ifdef _CONVERSION_USES_THREAD_LOCALE
940  
941             #ifndef _DEBUG
942                     #define SSCVT int _cvt; _cvt; UINT _acp=GetACP(); \
943                             _acp; PCWSTR _pw; _pw; PCSTR _pa; _pa
944             #else
945                     #define SSCVT int _cvt = 0; _cvt; UINT _acp=GetACP();\
946                              _acp; PCWSTR _pw=0; _pw; PCSTR _pa=0; _pa
947             #endif
948             #define SSA2W(pa) (\
949                     ((_pa = pa) == 0) ? 0 : (\
950                             _cvt = (sslen(_pa)),\
951                             StdCodeCvt((PWSTR) _alloca((_cvt+1)*2), (_cvt+1)*2, \
952                                                         _pa, _cvt, _acp)))
953             #define SSW2A(pw) (\
954                     ((_pw = pw) == 0) ? 0 : (\
955                             _cvt = sslen(_pw), \
956                             StdCodeCvt((LPSTR) _alloca((_cvt+1)*2), (_cvt+1)*2, \
957                                         _pw, _cvt, _acp)))
958         #else
959  
960             #ifndef _DEBUG
961                     #define SSCVT int _cvt; _cvt; UINT _acp=CP_ACP; _acp;\
962                              PCWSTR _pw; _pw; PCSTR _pa; _pa
963             #else
964                     #define SSCVT int _cvt = 0; _cvt; UINT _acp=CP_ACP; \
965                             _acp; PCWSTR _pw=0; _pw; PCSTR _pa=0; _pa
966             #endif
967             #define SSA2W(pa) (\
968                     ((_pa = pa) == 0) ? 0 : (\
969                             _cvt = (sslen(_pa)),\
970                             StdCodeCvt((PWSTR) _alloca((_cvt+1)*2), (_cvt+1)*2, \
971                                         _pa, _cvt)))
972             #define SSW2A(pw) (\
973                     ((_pw = pw) == 0) ? 0 : (\
974                             _cvt = (sslen(_pw)),\
975                             StdCodeCvt((LPSTR) _alloca((_cvt+1)*2), (_cvt+1)*2, \
976                                         _pw, _cvt)))
977     #endif
978  
979     #define SSA2CW(pa) ((PCWSTR)SSA2W((pa)))
980     #define SSW2CA(pw) ((PCSTR)SSW2A((pw)))
981  
982     #ifdef UNICODE
983             #define SST2A       SSW2A
984             #define SSA2T       SSA2W
985             #define SST2CA      SSW2CA
986             #define SSA2CT      SSA2CW
987                 // (Did you get a compiler error here about not being able to convert
988                 // PTSTR into PWSTR?  Then your _UNICODE and UNICODE flags are messed
989                 // up.  Best bet: #define BOTH macros before including any MS headers.)
990             inline PWSTR        SST2W(PTSTR p)                  { return p; }
991             inline PTSTR        SSW2T(PWSTR p)                  { return p; }
992             inline PCWSTR       SST2CW(PCTSTR p)                { return p; }
993             inline PCTSTR       SSW2CT(PCWSTR p)                { return p; }
994     #else
995             #define SST2W       SSA2W
996             #define SSW2T       SSW2A
997             #define SST2CW      SSA2CW
998             #define SSW2CT      SSW2CA
999             inline PSTR         SST2A(PTSTR p)                  { return p; }
1000             inline PTSTR        SSA2T(PSTR p)                   { return p; }
1001             inline PCSTR        SST2CA(PCTSTR p)                { return p; }
1002             inline PCTSTR       SSA2CT(PCSTR p)                 { return p; }
1003     #endif // #ifdef UNICODE
1004  
1005     #if defined(UNICODE)
1006     // in these cases the default (TCHAR) is the same as OLECHAR
1007             inline PCOLESTR     SST2COLE(PCTSTR p)              { return p; }
1008             inline PCTSTR       SSOLE2CT(PCOLESTR p)    { return p; }
1009             inline POLESTR      SST2OLE(PTSTR p)                { return p; }
1010             inline PTSTR        SSOLE2T(POLESTR p)              { return p; }
1011     #elif defined(OLE2ANSI)
1012     // in these cases the default (TCHAR) is the same as OLECHAR
1013             inline PCOLESTR     SST2COLE(PCTSTR p)              { return p; }
1014             inline PCTSTR       SSOLE2CT(PCOLESTR p)    { return p; }
1015             inline POLESTR      SST2OLE(PTSTR p)                { return p; }
1016             inline PTSTR        SSOLE2T(POLESTR p)              { return p; }
1017     #else
1018             //CharNextW doesn't work on Win95 so we use this
1019             #define SST2COLE(pa)        SSA2CW((pa))
1020             #define SST2OLE(pa)         SSA2W((pa))
1021             #define SSOLE2CT(po)        SSW2CA((po))
1022             #define SSOLE2T(po)         SSW2A((po))
1023     #endif
1024  
1025     #ifdef OLE2ANSI
1026             #define SSW2OLE             SSW2A
1027             #define SSOLE2W             SSA2W
1028             #define SSW2COLE    SSW2CA
1029             #define SSOLE2CW    SSA2CW
1030             inline POLESTR              SSA2OLE(PSTR p)         { return p; }
1031             inline PSTR                 SSOLE2A(POLESTR p)      { return p; }
1032             inline PCOLESTR             SSA2COLE(PCSTR p)       { return p; }
1033             inline PCSTR                SSOLE2CA(PCOLESTR p){ return p; }
1034     #else
1035             #define SSA2OLE             SSA2W
1036             #define SSOLE2A             SSW2A
1037             #define SSA2COLE    SSA2CW
1038             #define SSOLE2CA    SSW2CA
1039             inline POLESTR              SSW2OLE(PWSTR p)        { return p; }
1040             inline PWSTR                SSOLE2W(POLESTR p)      { return p; }
1041             inline PCOLESTR             SSW2COLE(PCWSTR p)      { return p; }
1042             inline PCWSTR               SSOLE2CW(PCOLESTR p){ return p; }
1043     #endif
1044  
1045     // Above we've defined macros that look like MS' but all have
1046     // an 'SS' prefix.  Now we need the real macros.  We'll either
1047     // get them from the macros above or from MFC/ATL.
1048  
1049         #if defined (USES_CONVERSION)
1050  
1051                 #define _NO_STDCONVERSION       // just to be consistent
1052  
1053         #else
1054  
1055                 #ifdef _MFC_VER
1056  
1057                         #include <afxconv.h>
1058                         #define _NO_STDCONVERSION // just to be consistent
1059  
1060                 #else
1061  
1062                         #define USES_CONVERSION SSCVT
1063                         #define A2CW                    SSA2CW
1064                         #define W2CA                    SSW2CA
1065                         #define T2A                             SST2A
1066                         #define A2T                             SSA2T
1067                         #define T2W                             SST2W
1068                         #define W2T                             SSW2T
1069                         #define T2CA                    SST2CA
1070                         #define A2CT                    SSA2CT
1071                         #define T2CW                    SST2CW
1072                         #define W2CT                    SSW2CT
1073                         #define ocslen                  sslen
1074                         #define ocscpy                  sscpy
1075                         #define T2COLE                  SST2COLE
1076                         #define OLE2CT                  SSOLE2CT
1077                         #define T2OLE                   SST2COLE
1078                         #define OLE2T                   SSOLE2CT
1079                         #define A2OLE                   SSA2OLE
1080                         #define OLE2A                   SSOLE2A
1081                         #define W2OLE                   SSW2OLE
1082                         #define OLE2W                   SSOLE2W
1083                         #define A2COLE                  SSA2COLE
1084                         #define OLE2CA                  SSOLE2CA
1085                         #define W2COLE                  SSW2COLE
1086                         #define OLE2CW                  SSOLE2CW
1087  
1088                 #endif // #ifdef _MFC_VER
1089         #endif // #ifndef USES_CONVERSION
1090 #endif // #ifndef SS_NO_CONVERSION
1091  
1092 // Define ostring - generic name for std::basic_string<OLECHAR>
1093  
1094 #if !defined(ostring) && !defined(OSTRING_DEFINED)
1095         typedef std::basic_string<OLECHAR> ostring;
1096         #define OSTRING_DEFINED
1097 #endif
1098  
1099 // StdCodeCvt when there's no conversion to be done
1100 inline PSTR StdCodeCvt(PSTR pDst, int nDst, PCSTR pSrc, int nSrc)
1101 {
1102         int nChars = SSMIN(nSrc, nDst);
1103  
1104         if ( nChars > 0 )
1105         {
1106                 pDst[0]                         = '\0';
1107                 std::basic_string<char>::traits_type::copy(pDst, pSrc, nChars);
1108 //              std::char_traits<char>::copy(pDst, pSrc, nChars);
1109                 pDst[nChars]    = '\0';
1110         }
1111  
1112         return pDst;
1113 }
1114 inline PSTR StdCodeCvt(PSTR pDst, int nDst, PCUSTR pSrc, int nSrc)
1115 {
1116         return StdCodeCvt(pDst, nDst, (PCSTR)pSrc, nSrc);
1117 }
1118 inline PUSTR StdCodeCvt(PUSTR pDst, int nDst, PCSTR pSrc, int nSrc)
1119 {
1120         return (PUSTR)StdCodeCvt((PSTR)pDst, nDst, pSrc, nSrc);
1121 }
1122  
1123 inline PWSTR StdCodeCvt(PWSTR pDst, int nDst, PCWSTR pSrc, int nSrc)
1124 {
1125         int nChars = SSMIN(nSrc, nDst);
1126  
1127         if ( nChars > 0 )
1128         {
1129                 pDst[0]                         = '\0';
1130                 std::basic_string<wchar_t>::traits_type::copy(pDst, pSrc, nChars);
1131 //              std::char_traits<wchar_t>::copy(pDst, pSrc, nChars);
1132                 pDst[nChars]    = '\0';
1133         }
1134  
1135         return pDst;
1136 }
1137  
1138  
1139 // Define tstring -- generic name for std::basic_string<TCHAR>
1140  
1141 #if !defined(tstring) && !defined(TSTRING_DEFINED)
1142         typedef std::basic_string<TCHAR> tstring;
1143         #define TSTRING_DEFINED
1144 #endif
1145  
1146 // a very shorthand way of applying the fix for KB problem Q172398
1147 // (basic_string assignment bug)
1148  
1149 #if defined ( _MSC_VER ) && ( _MSC_VER < 1200 )
1150         #define Q172398(x) (x).erase()
1151 #else
1152         #define Q172398(x)
1153 #endif
1154  
1155 // =============================================================================
1156 // INLINE FUNCTIONS ON WHICH CSTDSTRING RELIES
1157 //
1158 // Usually for generic text mapping, we rely on preprocessor macro definitions
1159 // to map to string functions.  However the CStdStr<> template cannot use
1160 // macro-based generic text mappings because its character types do not get
1161 // resolved until template processing which comes AFTER macro processing.  In
1162 // other words, the preprocessor macro UNICODE is of little help to us in the
1163 // CStdStr template
1164 //
1165 // Therefore, to keep the CStdStr declaration simple, we have these inline
1166 // functions.  The template calls them often.  Since they are inline (and NOT
1167 // exported when this is built as a DLL), they will probably be resolved away
1168 // to nothing.
1169 //
1170 // Without these functions, the CStdStr<> template would probably have to broken
1171 // out into two, almost identical classes.  Either that or it would be a huge,
1172 // convoluted mess, with tons of "if" statements all over the place checking the
1173 // size of template parameter CT.
1174 // =============================================================================
1175  
182 roytam 1176 #ifdef SS_NO_LOCALE
1177  
1178         // --------------------------------------------------------------------------
1179         // Win32 GetStringTypeEx wrappers
1180         // --------------------------------------------------------------------------
1181         inline bool wsGetStringType(LCID lc, DWORD dwT, PCSTR pS, int nSize,
1182                 WORD* pWd)
1183         {
1184                 return FALSE != GetStringTypeExA(lc, dwT, pS, nSize, pWd);
1185         }
1186         inline bool wsGetStringType(LCID lc, DWORD dwT, PCWSTR pS, int nSize,
1187                 WORD* pWd)
1188         {
1189                 return FALSE != GetStringTypeExW(lc, dwT, pS, nSize, pWd);
1190         }
1191  
1192  
1193         template<typename CT>
1194                 inline bool ssisspace (CT t)
1195         {
1196                 WORD toYourMother;
1197                 return  wsGetStringType(GetThreadLocale(), CT_CTYPE1, &t, 1, &toYourMother)
1198                         && 0 != (C1_BLANK & toYourMother);
1199         }
1200  
1201 #endif
1202  
181 roytam 1203 // If they defined SS_NO_REFCOUNT, then we must convert all assignments
1204  
182 roytam 1205 #if defined (_MSC_VER) && (_MSC_VER < 1300)
1206         #ifdef SS_NO_REFCOUNT
1207                 #define SSREF(x) (x).c_str()
1208         #else
1209                 #define SSREF(x) (x)
1210         #endif
181 roytam 1211 #else
1212         #define SSREF(x) (x)
1213 #endif
1214  
1215 // -----------------------------------------------------------------------------
1216 // sslen: strlen/wcslen wrappers
1217 // -----------------------------------------------------------------------------
1218 template<typename CT> inline int sslen(const CT* pT)
1219 {
1220         return 0 == pT ? 0 : (int)std::basic_string<CT>::traits_type::length(pT);
1221 //      return 0 == pT ? 0 : std::char_traits<CT>::length(pT);
1222 }
1223 inline SS_NOTHROW int sslen(const std::string& s)
1224 {
1225         return static_cast<int>(s.length());
1226 }
1227 inline SS_NOTHROW int sslen(const std::wstring& s)
1228 {
1229         return static_cast<int>(s.length());
1230 }
1231  
1232 // -----------------------------------------------------------------------------
1233 // sstolower/sstoupper -- convert characters to upper/lower case
1234 // -----------------------------------------------------------------------------
1235  
182 roytam 1236 #ifdef SS_NO_LOCALE
1237         inline char sstoupper(char ch)          { return (char)::toupper(ch); }
1238         inline wchar_t sstoupper(wchar_t ch){ return (wchar_t)::towupper(ch); }
1239         inline char sstolower(char ch)          { return (char)::tolower(ch); }
1240         inline wchar_t sstolower(wchar_t ch){ return (wchar_t)::tolower(ch); }
1241 #else
1242         template<typename CT>
1243         inline CT sstolower(const CT& t, const std::locale& loc = std::locale())
1244         {
1245                 return std::tolower<CT>(t, loc);
1246         }
1247         template<typename CT>
1248         inline CT sstoupper(const CT& t, const std::locale& loc = std::locale())
1249         {
1250                 return std::toupper<CT>(t, loc);
1251         }
1252 #endif
1253  
181 roytam 1254 // -----------------------------------------------------------------------------
1255 // ssasn: assignment functions -- assign "sSrc" to "sDst"
1256 // -----------------------------------------------------------------------------
1257 typedef std::string::size_type          SS_SIZETYPE; // just for shorthand, really
1258 typedef std::string::pointer            SS_PTRTYPE;  
1259 typedef std::wstring::size_type         SW_SIZETYPE;
1260 typedef std::wstring::pointer           SW_PTRTYPE;  
1261  
1262 inline void     ssasn(std::string& sDst, const std::string& sSrc)
1263 {
1264         if ( sDst.c_str() != sSrc.c_str() )
1265         {
1266                 sDst.erase();
1267                 sDst.assign(SSREF(sSrc));
1268         }
1269 }
1270 inline void     ssasn(std::string& sDst, PCSTR pA)
1271 {
1272         // Watch out for NULLs, as always.
1273  
1274         if ( 0 == pA )
1275         {
1276                 sDst.erase();
1277         }
1278  
1279         // If pA actually points to part of sDst, we must NOT erase(), but
1280         // rather take a substring
1281  
1282         else if ( pA >= sDst.c_str() && pA <= sDst.c_str() + sDst.size() )
1283         {
1284                 sDst =sDst.substr(static_cast<SS_SIZETYPE>(pA-sDst.c_str()));
1285         }
1286  
1287         // Otherwise (most cases) apply the assignment bug fix, if applicable
1288         // and do the assignment
1289  
1290         else
1291         {
1292                 Q172398(sDst);
1293                 sDst.assign(pA);
1294         }
1295 }
1296 inline void     ssasn(std::string& sDst, const std::wstring& sSrc)
1297 {
1298         if ( sSrc.empty() )
1299         {
1300                 sDst.erase();
1301         }
1302         else
1303         {
1304                 int nDst        = static_cast<int>(sSrc.size());
1305  
1306                 // In MBCS builds, pad the buffer to account for the possibility of
1307                 // some 3 byte characters.  Not perfect but should get most cases.
1308  
1309 #ifdef SS_MBCS
1310                 nDst    = static_cast<int>(static_cast<double>(nDst) * 1.3);
1311 #endif
1312  
1313                 sDst.resize(nDst+1);
1314                 PCSTR szCvt = StdCodeCvt(const_cast<SS_PTRTYPE>(sDst.data()), nDst,
1315                         sSrc.c_str(), static_cast<int>(sSrc.size()));
1316  
1317                 // In MBCS builds, we don't know how long the destination string will be.
1318  
1319 #ifdef SS_MBCS
1320                 sDst.resize(sslen(szCvt));
1321 #else
1322                 szCvt;
1323                 sDst.resize(sSrc.size());
1324 #endif
1325         }
1326 }
1327 inline void     ssasn(std::string& sDst, PCWSTR pW)
1328 {
1329         int nSrc        = sslen(pW);
1330         if ( nSrc > 0 )
1331         {
1332                 int nSrc        = sslen(pW);
1333                 int nDst        = nSrc;
1334  
1335                 // In MBCS builds, pad the buffer to account for the possibility of
1336                 // some 3 byte characters.  Not perfect but should get most cases.
1337  
1338 #ifdef SS_MBCS
1339                 nDst    = static_cast<int>(static_cast<double>(nDst) * 1.3);
1340 #endif
1341  
1342                 sDst.resize(nDst + 1);
1343                 PCSTR szCvt = StdCodeCvt(const_cast<SS_PTRTYPE>(sDst.data()), nDst,
1344                         pW, nSrc);
1345  
1346                 // In MBCS builds, we don't know how long the destination string will be.
1347  
1348 #ifdef SS_MBCS
1349                 sDst.resize(sslen(szCvt));
1350 #else
1351                 sDst.resize(nDst);
1352                 szCvt;
1353 #endif
1354         }
1355         else
1356         {
1357                 sDst.erase();
1358         }
1359 }
1360 inline void ssasn(std::string& sDst, const int nNull)
1361 {
1362         UNUSED(nNull);
1363         ASSERT(nNull==0);
1364         sDst.assign("");
1365 }      
1366 inline void     ssasn(std::wstring& sDst, const std::wstring& sSrc)
1367 {
1368         if ( sDst.c_str() != sSrc.c_str() )
1369         {
1370                 sDst.erase();
1371                 sDst.assign(SSREF(sSrc));
1372         }
1373 }
1374 inline void     ssasn(std::wstring& sDst, PCWSTR pW)
1375 {
1376         // Watch out for NULLs, as always.
1377  
1378         if ( 0 == pW )
1379         {
1380                 sDst.erase();
1381         }
1382  
1383         // If pW actually points to part of sDst, we must NOT erase(), but
1384         // rather take a substring
1385  
1386         else if ( pW >= sDst.c_str() && pW <= sDst.c_str() + sDst.size() )
1387         {
1388                 sDst = sDst.substr(static_cast<SW_SIZETYPE>(pW-sDst.c_str()));
1389         }
1390  
1391         // Otherwise (most cases) apply the assignment bug fix, if applicable
1392         // and do the assignment
1393  
1394         else
1395         {
1396                 Q172398(sDst);
1397                 sDst.assign(pW);
1398         }
1399 }
1400 #undef StrSizeType
1401 inline void     ssasn(std::wstring& sDst, const std::string& sSrc)
1402 {
1403         if ( sSrc.empty() )
1404         {
1405                 sDst.erase();
1406         }
1407         else
1408         {
1409                 int nSrc        = static_cast<int>(sSrc.size());
1410                 int nDst        = nSrc;
1411  
1412                 sDst.resize(nSrc+1);
1413                 PCWSTR szCvt = StdCodeCvt(const_cast<SW_PTRTYPE>(sDst.data()), nDst,
1414                         sSrc.c_str(), nSrc);
1415  
1416                 sDst.resize(sslen(szCvt));
1417         }
1418 }
1419 inline void     ssasn(std::wstring& sDst, PCSTR pA)
1420 {
1421         int nSrc        = sslen(pA);
1422  
1423         if ( 0 == nSrc )
1424         {
1425                 sDst.erase();
1426         }
1427         else
1428         {
1429                 int nDst        = nSrc;
1430                 sDst.resize(nDst+1);
1431                 PCWSTR szCvt = StdCodeCvt(const_cast<SW_PTRTYPE>(sDst.data()), nDst, pA,
1432                         nSrc);
1433  
1434                 sDst.resize(sslen(szCvt));
1435         }
1436 }
1437 inline void ssasn(std::wstring& sDst, const int nNull)
1438 {
1439         UNUSED(nNull);
1440         ASSERT(nNull==0);
1441         sDst.assign(L"");
1442 }
1443  
1444  
1445 // -----------------------------------------------------------------------------
1446 // ssadd: string object concatenation -- add second argument to first
1447 // -----------------------------------------------------------------------------
1448 inline void     ssadd(std::string& sDst, const std::wstring& sSrc)
1449 {
1450         int nSrc        = static_cast<int>(sSrc.size());
1451  
1452         if ( nSrc > 0 )
1453         {
1454                 int nDst        = static_cast<int>(sDst.size());
1455                 int nAdd        = nSrc;
1456  
1457                 // In MBCS builds, pad the buffer to account for the possibility of
1458                 // some 3 byte characters.  Not perfect but should get most cases.
1459  
1460 #ifdef SS_MBCS
1461                 nAdd            = static_cast<int>(static_cast<double>(nAdd) * 1.3);
1462 #endif
1463  
1464                 sDst.resize(nDst+nAdd+1);
1465                 PCSTR szCvt = StdCodeCvt(const_cast<SS_PTRTYPE>(sDst.data()+nDst),
1466                         nAdd, sSrc.c_str(), nSrc);
1467  
1468 #ifdef SS_MBCS
1469                 sDst.resize(nDst + sslen(szCvt));
1470 #else
1471                 sDst.resize(nDst + nAdd);
1472                 szCvt;
1473 #endif
1474         }
1475 }
1476 inline void     ssadd(std::string& sDst, const std::string& sSrc)
1477 {
1478         sDst += sSrc;
1479 }
1480 inline void     ssadd(std::string& sDst, PCWSTR pW)
1481 {
1482         int nSrc                = sslen(pW);
1483         if ( nSrc > 0 )
1484         {
1485                 int nDst        = static_cast<int>(sDst.size());
1486                 int nAdd        = nSrc;
1487  
1488 #ifdef SS_MBCS
1489                 nAdd    = static_cast<int>(static_cast<double>(nAdd) * 1.3);
1490 #endif
1491  
1492                 sDst.resize(nDst + nAdd + 1);
1493                 PCSTR szCvt = StdCodeCvt(const_cast<SS_PTRTYPE>(sDst.data()+nDst),
1494                         nAdd, pW, nSrc);
1495  
1496 #ifdef SS_MBCS
1497                 sDst.resize(nDst + sslen(szCvt));
1498 #else
1499                 sDst.resize(nDst + nSrc);
1500                 szCvt;
1501 #endif
1502         }
1503 }
1504 inline void     ssadd(std::string& sDst, PCSTR pA)
1505 {
1506         if ( pA )
1507         {
1508                 // If the string being added is our internal string or a part of our
1509                 // internal string, then we must NOT do any reallocation without
1510                 // first copying that string to another object (since we're using a
1511                 // direct pointer)
1512  
1513                 if ( pA >= sDst.c_str() && pA <= sDst.c_str()+sDst.length())
1514                 {
1515                         if ( sDst.capacity() <= sDst.size()+sslen(pA) )
1516                                 sDst.append(std::string(pA));
1517                         else
1518                                 sDst.append(pA);
1519                 }
1520                 else
1521                 {
1522                         sDst.append(pA);
1523                 }
1524         }
1525 }
1526 inline void     ssadd(std::wstring& sDst, const std::wstring& sSrc)
1527 {
1528         sDst += sSrc;
1529 }
1530 inline void     ssadd(std::wstring& sDst, const std::string& sSrc)
1531 {
1532         if ( !sSrc.empty() )
1533         {
1534                 int nSrc        = static_cast<int>(sSrc.size());
1535                 int nDst        = static_cast<int>(sDst.size());
1536  
1537                 sDst.resize(nDst + nSrc + 1);
1538                 PCWSTR szCvt = StdCodeCvt(const_cast<SW_PTRTYPE>(sDst.data()+nDst),
1539                         nSrc, sSrc.c_str(), nSrc+1);
1540  
1541 #ifdef SS_MBCS
1542                 sDst.resize(nDst + sslen(szCvt));
1543 #else
1544                 sDst.resize(nDst + nSrc);
1545                 szCvt;
1546 #endif
1547         }
1548 }
1549 inline void     ssadd(std::wstring& sDst, PCSTR pA)
1550 {
1551         int nSrc                = sslen(pA);
1552  
1553         if ( nSrc > 0 )
1554         {
1555                 int nDst        = static_cast<int>(sDst.size());
1556  
1557                 sDst.resize(nDst + nSrc + 1);
1558                 PCWSTR szCvt = StdCodeCvt(const_cast<SW_PTRTYPE>(sDst.data()+nDst),
1559                         nSrc, pA, nSrc+1);
1560  
1561 #ifdef SS_MBCS
1562                 sDst.resize(nDst + sslen(szCvt));
1563 #else
1564                 sDst.resize(nDst + nSrc);
1565                 szCvt;
1566 #endif
1567         }
1568 }
1569 inline void     ssadd(std::wstring& sDst, PCWSTR pW)
1570 {
1571         if ( pW )
1572         {
1573                 // If the string being added is our internal string or a part of our
1574                 // internal string, then we must NOT do any reallocation without
1575                 // first copying that string to another object (since we're using a
1576                 // direct pointer)
1577  
1578                 if ( pW >= sDst.c_str() && pW <= sDst.c_str()+sDst.length())
1579                 {
1580                         if ( sDst.capacity() <= sDst.size()+sslen(pW) )
1581                                 sDst.append(std::wstring(pW));
1582                         else
1583                                 sDst.append(pW);
1584                 }
1585                 else
1586                 {
1587                         sDst.append(pW);
1588                 }
1589         }
1590 }
1591  
1592  
1593 // -----------------------------------------------------------------------------
1594 // sscmp: comparison (case sensitive, not affected by locale)
1595 // -----------------------------------------------------------------------------
1596 template<typename CT>
1597 inline int sscmp(const CT* pA1, const CT* pA2)
1598 {
1599     CT f;
1600     CT l;
1601  
1602     do
1603     {
1604             f = *(pA1++);
1605             l = *(pA2++);
1606     } while ( (f) && (f == l) );
1607  
1608     return (int)(f - l);
1609 }
1610  
1611 // -----------------------------------------------------------------------------
1612 // ssicmp: comparison (case INsensitive, not affected by locale)
1613 // -----------------------------------------------------------------------------
1614 template<typename CT>
1615 inline int ssicmp(const CT* pA1, const CT* pA2)
1616 {
1617         // Using the "C" locale = "not affected by locale"
1618  
1619         std::locale loc = std::locale::classic();
1620     const std::ctype<CT>& ct = SS_USE_FACET(loc, std::ctype<CT>);
1621     CT f;
1622     CT l;
1623  
1624     do
1625     {
1626             f = ct.tolower(*(pA1++));
1627             l = ct.tolower(*(pA2++));
1628     } while ( (f) && (f == l) );
1629  
1630     return (int)(f - l);
1631 }
1632  
1633 // -----------------------------------------------------------------------------
1634 // ssupr/sslwr: Uppercase/Lowercase conversion functions
1635 // -----------------------------------------------------------------------------
1636  
1637 template<typename CT>
1638 inline void sslwr(CT* pT, size_t nLen, const std::locale& loc=std::locale())
1639 {
1640         SS_USE_FACET(loc, std::ctype<CT>).tolower(pT, pT+nLen);
1641 }
1642 template<typename CT>
1643 inline void ssupr(CT* pT, size_t nLen, const std::locale& loc=std::locale())
1644 {
1645         SS_USE_FACET(loc, std::ctype<CT>).toupper(pT, pT+nLen);
1646 }
1647  
1648 // -----------------------------------------------------------------------------
1649 // vsprintf/vswprintf or _vsnprintf/_vsnwprintf equivalents.  In standard
1650 // builds we can't use _vsnprintf/_vsnwsprintf because they're MS extensions.
1651 //
1652 // -----------------------------------------------------------------------------
1653 // Borland's headers put some ANSI "C" functions in the 'std' namespace.
1654 // Promote them to the global namespace so we can use them here.
1655  
1656 #if defined(__BORLANDC__)
1657     using std::vsprintf;
1658     using std::vswprintf;
1659 #endif
1660  
1661         // GNU is supposed to have vsnprintf and vsnwprintf.  But only the newer
1662         // distributions do.
1663  
1664 #if defined(__GNUC__)
1665  
1666         inline int ssvsprintf(PSTR pA, size_t nCount, PCSTR pFmtA, va_list vl)
1667         {
1668                 return vsnprintf(pA, nCount, pFmtA, vl);
1669         }
1670         inline int ssvsprintf(PWSTR pW, size_t nCount, PCWSTR pFmtW, va_list vl)
1671         {
1672                 return vswprintf(pW, nCount, pFmtW, vl);
1673         }
1674  
182 roytam 1675         // Else if this is VC++ in a regular (non-ANSI) build
181 roytam 1676 #elif defined(_MSC_VER) && !defined(SS_ANSI)
1677  
182 roytam 1678         inline int      ssvsprintf(PSTR pA, size_t nCount, PCSTR pFmtA, va_list vl)
181 roytam 1679         {
1680                 return _vsnprintf(pA, nCount, pFmtA, vl);
1681         }
182 roytam 1682         inline int      ssvsprintf(PWSTR pW, size_t nCount, PCWSTR pFmtW, va_list vl)
181 roytam 1683         {
1684                 return _vsnwprintf(pW, nCount, pFmtW, vl);
1685         }
1686  
182 roytam 1687         // Else (an ANSI build) if they want to allow "dangerous" (i.e. non-length-
1688         // checked) formatting
1689 #elif defined (SS_DANGEROUS_FORMAT)  // ignore buffer size parameter if needed?
181 roytam 1690  
1691         inline int ssvsprintf(PSTR pA, size_t /*nCount*/, PCSTR pFmtA, va_list vl)
1692         {
1693                 return vsprintf(pA, pFmtA, vl);
1694         }
1695  
1696         inline int ssvsprintf(PWSTR pW, size_t nCount, PCWSTR pFmtW, va_list vl)
1697         {
1698                 // JMO: Some distributions of the "C" have a version of vswprintf that
1699         // takes 3 arguments (e.g. Microsoft, Borland, GNU).  Others have a
1700         // version which takes 4 arguments (an extra "count" argument in the
1701         // second position.  The best stab I can take at this so far is that if
1702         // you are NOT running with MS, Borland, or GNU, then I'll assume you
1703         // have the version that takes 4 arguments.
1704         //
1705         // I'm sure that these checks don't catch every platform correctly so if
1706         // you get compiler errors on one of the lines immediately below, it's
1707         // probably because your implemntation takes a different number of
1708         // arguments.  You can comment out the offending line (and use the
1709         // alternate version) or you can figure out what compiler flag to check
1710         // and add that preprocessor check in.  Regardless, if you get an error
1711         // on these lines, I'd sure like to hear from you about it.
1712         //
1713         // Thanks to Ronny Schulz for the SGI-specific checks here.
1714  
1715 //      #if !defined(__MWERKS__) && !defined(__SUNPRO_CC_COMPAT) && !defined(__SUNPRO_CC)
1716     #if    !defined(_MSC_VER) \
1717         && !defined (__BORLANDC__) \
1718         && !defined(__GNUC__) \
1719         && !defined(__sgi)
1720  
1721         return vswprintf(pW, nCount, pFmtW, vl);
1722  
1723     // suddenly with the current SGI 7.3 compiler there is no such function as
1724     // vswprintf and the substitute needs explicit casts to compile
1725  
1726     #elif defined(__sgi)
1727  
1728         nCount;
1729         return vsprintf( (char *)pW, (char *)pFmtW, vl);
1730  
1731     #else
1732  
1733         nCount;
1734         return vswprintf(pW, pFmtW, vl);
1735  
1736     #endif
1737  
1738         }
1739  
182 roytam 1740         // OK, it's some kind of ANSI build but no "dangerous" formatting allowed
1741 #else
1742  
1743         // GOT COMPILER PROBLEMS HERE?
1744         // ---------------------------
1745         // Does your compiler choke on one or more of the following 2 functions?  It
1746         // probably means that you don't have have either vsnprintf or vsnwprintf in
1747         // your version of the CRT.  This is understandable since neither is an ANSI
1748         // "C" function.  However it still leaves you in a dilemma.  In order to make
1749         // this code build, you're going to have to to use some non-length-checked
1750         // formatting functions that every CRT has:  vsprintf and vswprintf.  
1751         //
1752         // This is very dangerous.  With the proper erroneous (or malicious) code, it
1753         // can lead to buffer overlows and crashing your PC.  Use at your own risk
1754         // In order to use them, just #define SS_DANGEROUS_FORMAT at the top of
1755         // this file.
1756         //
1757         // Even THEN you might not be all the way home due to some non-conforming
1758         // distributions.  More on this in the comments below.
1759  
1760         inline int      ssvsprintf(PSTR pA, size_t nCount, PCSTR pFmtA, va_list vl)
1761         {
1762         #ifdef _MSC_VER
1763                         return _vsnprintf(pA, nCount, pFmtA, vl);
1764         #else
1765                         return vsnprintf(pA, nCount, pFmtA, vl);
1766         #endif
1767         }
1768         inline int      ssvsprintf(PWSTR pW, size_t nCount, PCWSTR pFmtW, va_list vl)
1769         {
1770         #ifdef _MSC_VER
1771                         return _vsnwprintf(pW, nCount, pFmtW, vl);
1772         #else
1773                         return vsnwprintf(pW, nCount, pFmtW, vl);
1774         #endif
1775         }
1776  
181 roytam 1777 #endif
1778  
1779  
1780  
182 roytam 1781  
181 roytam 1782 // -----------------------------------------------------------------------------
1783 // ssload: Type safe, overloaded ::LoadString wrappers
1784 // There is no equivalent of these in non-Win32-specific builds.  However, I'm
1785 // thinking that with the message facet, there might eventually be one
1786 // -----------------------------------------------------------------------------
1787 #if defined (SS_WIN32) && !defined(SS_ANSI)
1788         inline int ssload(HMODULE hInst, UINT uId, PSTR pBuf, int nMax)
1789         {
1790                 return ::LoadStringA(hInst, uId, pBuf, nMax);
1791         }
1792         inline int ssload(HMODULE hInst, UINT uId, PWSTR pBuf, int nMax)
1793         {
1794                 return ::LoadStringW(hInst, uId, pBuf, nMax);
1795         }
1796 #endif
1797  
1798  
1799 // -----------------------------------------------------------------------------
1800 // sscoll/ssicoll: Collation wrappers
1801 //              Note -- with MSVC I have reversed the arguments order here because the
1802 //              functions appear to return the opposite of what they should
1803 // -----------------------------------------------------------------------------
182 roytam 1804 #ifndef SS_NO_LOCALE
181 roytam 1805 template <typename CT>
1806 inline int sscoll(const CT* sz1, int nLen1, const CT* sz2, int nLen2)
1807 {
1808         const std::collate<CT>& coll =
1809                 SS_USE_FACET(std::locale(), std::collate<CT>);
1810  
1811         return coll.compare(sz2, sz2+nLen2, sz1, sz1+nLen1);
1812 }
1813 template <typename CT>
1814 inline int ssicoll(const CT* sz1, int nLen1, const CT* sz2, int nLen2)
1815 {
1816         const std::locale loc;
1817         const std::collate<CT>& coll = SS_USE_FACET(loc, std::collate<CT>);
1818  
1819         // Some implementations seem to have trouble using the collate<>
1820         // facet typedefs so we'll just default to basic_string and hope
1821         // that's what the collate facet uses (which it generally should)
1822  
1823 //      std::collate<CT>::string_type s1(sz1);
1824 //      std::collate<CT>::string_type s2(sz2);
1825         const std::basic_string<CT> sEmpty;
1826     std::basic_string<CT> s1(sz1 ? sz1 : sEmpty.c_str());
1827     std::basic_string<CT> s2(sz2 ? sz2 : sEmpty.c_str());
1828  
1829         sslwr(const_cast<CT*>(s1.c_str()), nLen1, loc);
1830         sslwr(const_cast<CT*>(s2.c_str()), nLen2, loc);
1831         return coll.compare(s2.c_str(), s2.c_str()+nLen2,
1832                                                 s1.c_str(), s1.c_str()+nLen1);
1833 }
182 roytam 1834 #endif
181 roytam 1835  
1836  
1837 // -----------------------------------------------------------------------------
1838 // ssfmtmsg: FormatMessage equivalents.  Needed because I added a CString facade
1839 // Again -- no equivalent of these on non-Win32 builds but their might one day
1840 // be one if the message facet gets implemented
1841 // -----------------------------------------------------------------------------
1842 #if defined (SS_WIN32) && !defined(SS_ANSI)
1843         inline DWORD ssfmtmsg(DWORD dwFlags, LPCVOID pSrc, DWORD dwMsgId,
1844                                                   DWORD dwLangId, PSTR pBuf, DWORD nSize,
1845                                                   va_list* vlArgs)
1846         {
1847                 return FormatMessageA(dwFlags, pSrc, dwMsgId, dwLangId,
1848                                                           pBuf, nSize,vlArgs);
1849         }
1850         inline DWORD ssfmtmsg(DWORD dwFlags, LPCVOID pSrc, DWORD dwMsgId,
1851                                                   DWORD dwLangId, PWSTR pBuf, DWORD nSize,
1852                                                   va_list* vlArgs)
1853         {
1854                 return FormatMessageW(dwFlags, pSrc, dwMsgId, dwLangId,
1855                                                           pBuf, nSize,vlArgs);
1856         }
1857 #else
1858 #endif
1859  
1860  
1861  
1862 // FUNCTION: sscpy.  Copies up to 'nMax' characters from pSrc to pDst.
1863 // -----------------------------------------------------------------------------
1864 // FUNCTION:  sscpy
1865 //              inline int sscpy(PSTR pDst, PCSTR pSrc, int nMax=-1);
1866 //              inline int sscpy(PUSTR pDst,  PCSTR pSrc, int nMax=-1)
1867 //              inline int sscpy(PSTR pDst, PCWSTR pSrc, int nMax=-1);
1868 //              inline int sscpy(PWSTR pDst, PCWSTR pSrc, int nMax=-1);
1869 //              inline int sscpy(PWSTR pDst, PCSTR pSrc, int nMax=-1);
1870 //
1871 // DESCRIPTION:
1872 //              This function is very much (but not exactly) like strcpy.  These
1873 //              overloads simplify copying one C-style string into another by allowing
1874 //              the caller to specify two different types of strings if necessary.
1875 //
1876 //              The strings must NOT overlap
1877 //
1878 //              "Character" is expressed in terms of the destination string, not
1879 //              the source.  If no 'nMax' argument is supplied, then the number of
1880 //              characters copied will be sslen(pSrc).  A NULL terminator will
1881 //              also be added so pDst must actually be big enough to hold nMax+1
1882 //              characters.  The return value is the number of characters copied,
1883 //              not including the NULL terminator.
1884 //
1885 // PARAMETERS:
1886 //              pSrc - the string to be copied FROM.  May be a char based string, an
1887 //                         MBCS string (in Win32 builds) or a wide string (wchar_t).
1888 //              pSrc - the string to be copied TO.  Also may be either MBCS or wide
1889 //              nMax - the maximum number of characters to be copied into szDest.  Note
1890 //                         that this is expressed in whatever a "character" means to pDst.
1891 //                         If pDst is a wchar_t type string than this will be the maximum
1892 //                         number of wchar_ts that my be copied.  The pDst string must be
1893 //                         large enough to hold least nMaxChars+1 characters.
1894 //                         If the caller supplies no argument for nMax this is a signal to
1895 //                         the routine to copy all the characters in pSrc, regardless of
1896 //                         how long it is.
1897 //
1898 // RETURN VALUE: none
1899 // -----------------------------------------------------------------------------
1900 template<typename CT1, typename CT2>
1901 inline int sscpycvt(CT1* pDst, const CT2* pSrc, int nMax)
1902 {
1903         // Note -- we assume pDst is big enough to hold pSrc.  If not, we're in
1904         // big trouble.  No bounds checking.  Caveat emptor.
1905  
1906         int nSrc = sslen(pSrc);
1907  
1908         const CT1* szCvt = StdCodeCvt(pDst, nMax, pSrc, nSrc);
1909  
1910         // If we're copying the same size characters, then all the "code convert"
1911         // just did was basically memcpy so the #of characters copied is the same
1912         // as the number requested.  I should probably specialize this function
1913         // template to achieve this purpose as it is silly to do a runtime check
1914         // of a fact known at compile time.  I'll get around to it.
1915  
1916         return sslen(szCvt);
1917 }
1918  
1919 inline int sscpycvt(PSTR pDst, PCSTR pSrc, int nMax)
1920 {
1921         int nCount = nMax;
1922         for (; nCount > 0 && *pSrc; ++pSrc, ++pDst, --nCount)
1923                 std::basic_string<char>::traits_type::assign(*pDst, *pSrc);
1924  
1925         *pDst =  '\0';
1926         return nMax - nCount;
1927 }
1928 inline int sscpycvt(PWSTR pDst, PCWSTR pSrc, int nMax)
1929 {
1930         int nCount = nMax;
1931         for (; nCount > 0 && *pSrc; ++pSrc, ++pDst, --nCount)
1932                 std::basic_string<wchar_t>::traits_type::assign(*pDst, *pSrc);
1933  
1934         *pDst = L'\0';
1935         return nMax - nCount;
1936 }
1937 inline int sscpycvt(PWSTR pDst, PCSTR pSrc, int nMax)
1938 {
1939         // Note -- we assume pDst is big enough to hold pSrc.  If not, we're in
1940         // big trouble.  No bounds checking.  Caveat emptor.
1941  
1942         const PWSTR szCvt = StdCodeCvt(pDst, nMax, pSrc, nMax);
1943         return sslen(szCvt);
1944 }
1945  
1946 template<typename CT1, typename CT2>
1947 inline int sscpy(CT1* pDst, const CT2* pSrc, int nMax, int nLen)
1948 {
1949         return sscpycvt(pDst, pSrc, SSMIN(nMax, nLen));
1950 }
1951 template<typename CT1, typename CT2>
1952 inline int sscpy(CT1* pDst, const CT2* pSrc, int nMax)
1953 {
1954         return sscpycvt(pDst, pSrc, SSMIN(nMax, sslen(pSrc)));
1955 }
1956 template<typename CT1, typename CT2>
1957 inline int sscpy(CT1* pDst, const CT2* pSrc)
1958 {
1959         return sscpycvt(pDst, pSrc, sslen(pSrc));
1960 }
1961 template<typename CT1, typename CT2>
1962 inline int sscpy(CT1* pDst, const std::basic_string<CT2>& sSrc, int nMax)
1963 {
1964         return sscpycvt(pDst, sSrc.c_str(), SSMIN(nMax, (int)sSrc.length()));
1965 }
1966 template<typename CT1, typename CT2>
1967 inline int sscpy(CT1* pDst, const std::basic_string<CT2>& sSrc)
1968 {
1969         return sscpycvt(pDst, sSrc.c_str(), (int)sSrc.length());
1970 }
1971  
1972 #ifdef SS_INC_COMDEF
1973         template<typename CT1>
1974         inline int sscpy(CT1* pDst, const _bstr_t& bs, int nMax)
1975         {
1976                 return sscpycvt(pDst, static_cast<PCOLESTR>(bs),
1977             SSMIN(nMax, static_cast<int>(bs.length())));
1978         }
1979         template<typename CT1>
1980         inline int sscpy(CT1* pDst, const _bstr_t& bs)
1981         {
1982                 return sscpy(pDst, bs, static_cast<int>(bs.length()));
1983         }
1984 #endif
1985  
1986  
1987 // -----------------------------------------------------------------------------
1988 // Functional objects for changing case.  They also let you pass locales
1989 // -----------------------------------------------------------------------------
1990  
182 roytam 1991 #ifdef SS_NO_LOCALE
1992         template<typename CT>
1993         struct SSToUpper : public std::unary_function<CT, CT>
1994         {
1995                 inline CT operator()(const CT& t) const
1996                 {
1997                         return sstoupper(t);
1998                 }
1999         };
2000         template<typename CT>
2001         struct SSToLower : public std::unary_function<CT, CT>
2002         {
2003                 inline CT operator()(const CT& t) const
2004                 {
2005                         return sstolower(t);
2006                 }
2007         };
2008 #else
2009         template<typename CT>
2010         struct SSToUpper : public std::binary_function<CT, std::locale, CT>
2011         {
2012                 inline CT operator()(const CT& t, const std::locale& loc) const
2013                 {
2014                         return sstoupper<CT>(t, loc);
2015                 }
2016         };
2017         template<typename CT>
2018         struct SSToLower : public std::binary_function<CT, std::locale, CT>
2019         {
2020                 inline CT operator()(const CT& t, const std::locale& loc) const
2021                 {
2022                         return sstolower<CT>(t, loc);
2023                 }
2024         };
2025 #endif
181 roytam 2026  
2027 // This struct is used for TrimRight() and TrimLeft() function implementations.
2028 //template<typename CT>
2029 //struct NotSpace : public std::unary_function<CT, bool>
2030 //{
2031 //      const std::locale& loc;
2032 //      inline NotSpace(const std::locale& locArg) : loc(locArg) {}
2033 //      inline bool operator() (CT t) { return !std::isspace(t, loc); }
2034 //};
2035 template<typename CT>
2036 struct NotSpace : public std::unary_function<CT, bool>
2037 {
2038         // DINKUMWARE BUG:
2039         // Note -- using std::isspace in a COM DLL gives us access violations
2040         // because it causes the dynamic addition of a function to be called
2041         // when the library shuts down.  Unfortunately the list is maintained
2042         // in DLL memory but the function is in static memory.  So the COM DLL
2043         // goes away along with the function that was supposed to be called,
2044         // and then later when the DLL CRT shuts down it unloads the list and
2045         // tries to call the long-gone function.
2046         // This is DinkumWare's implementation problem.  If you encounter this
2047         // problem, you may replace the calls here with good old isspace() and
2048         // iswspace() from the CRT unless they specify SS_ANSI
2049  
182 roytam 2050 #ifdef SS_NO_LOCALE
2051  
2052         bool operator() (CT t) const { return !ssisspace(t); }
2053  
2054 #else
181 roytam 2055         const std::locale loc;
2056         NotSpace(const std::locale& locArg=std::locale()) : loc(locArg) {}
2057         bool operator() (CT t) const { return !std::isspace(t, loc); }
182 roytam 2058 #endif
181 roytam 2059 };
2060  
2061  
2062  
2063  
2064 //                      Now we can define the template (finally!)
2065 // =============================================================================
2066 // TEMPLATE: CStdStr
2067 //              template<typename CT> class CStdStr : public std::basic_string<CT>
2068 //
2069 // REMARKS:
2070 //              This template derives from basic_string<CT> and adds some MFC CString-
2071 //              like functionality
2072 //
2073 //              Basically, this is my attempt to make Standard C++ library strings as
2074 //              easy to use as the MFC CString class.
2075 //
2076 //              Note that although this is a template, it makes the assumption that the
2077 //              template argument (CT, the character type) is either char or wchar_t.  
2078 // =============================================================================
2079  
2080 //#define CStdStr _SS   // avoid compiler warning 4786
2081  
2082 //    template<typename ARG> ARG& FmtArg(ARG& arg)  { return arg; }
2083 //    PCSTR  FmtArg(const std::string& arg)  { return arg.c_str(); }
2084 //    PCWSTR FmtArg(const std::wstring& arg) { return arg.c_str(); }
2085  
2086 template<typename ARG>
2087 struct FmtArg
2088 {
2089     explicit FmtArg(const ARG& arg) : a_(arg) {}
2090     const ARG& operator()() const { return a_; }
2091     const ARG& a_;
2092 private:
2093     FmtArg& operator=(const FmtArg&) { return *this; }
2094 };
2095  
2096 template<typename CT>
2097 class CStdStr : public std::basic_string<CT>
2098 {
2099         // Typedefs for shorter names.  Using these names also appears to help
2100         // us avoid some ambiguities that otherwise arise on some platforms
2101  
2102         #define MYBASE std::basic_string<CT>                             // my base class
2103         //typedef typename std::basic_string<CT>                MYBASE;  // my base class
2104         typedef CStdStr<CT>                                                     MYTYPE;  // myself
2105         typedef typename MYBASE::const_pointer          PCMYSTR; // PCSTR or PCWSTR
2106         typedef typename MYBASE::pointer                        PMYSTR;  // PSTR or PWSTR
2107         typedef typename MYBASE::iterator                       MYITER;  // my iterator type
2108         typedef typename MYBASE::const_iterator         MYCITER; // you get the idea...
2109         typedef typename MYBASE::reverse_iterator       MYRITER;
2110         typedef typename MYBASE::size_type                      MYSIZE;  
2111         typedef typename MYBASE::value_type                     MYVAL;
2112         typedef typename MYBASE::allocator_type         MYALLOC;
2113  
2114 public:
2115         // shorthand conversion from PCTSTR to string resource ID
2116         #define SSRES(pctstr)  LOWORD(reinterpret_cast<unsigned long>(pctstr)) 
2117  
2118         bool TryLoad(const void* pT)
2119         {
2120                 bool bLoaded = false;
2121  
2122 #if defined(SS_WIN32) && !defined(SS_ANSI)
2123                 if ( ( pT != NULL ) && SS_IS_INTRESOURCE(pT) )
2124                 {
2125                         UINT nId = LOWORD(reinterpret_cast<unsigned long>(pT));
2126                         if ( !LoadString(nId) )
2127                         {
2128                                 TRACE(_T("Can't load string %u\n"), SSRES(pT));
2129                         }
2130                         bLoaded = true;
2131                 }
2132 #endif
2133  
2134                 return bLoaded;
2135         }
2136  
2137  
2138         // CStdStr inline constructors
2139         CStdStr()
2140         {
2141         }
2142  
2143         CStdStr(const MYTYPE& str) : MYBASE(SSREF(str))
2144         {
2145         }
2146  
2147         CStdStr(const std::string& str)
2148         {
2149                 ssasn(*this, SSREF(str));
2150         }
2151  
2152         CStdStr(const std::wstring& str)
2153         {
2154                 ssasn(*this, SSREF(str));
2155         }
2156  
2157         CStdStr(PCMYSTR pT, MYSIZE n) : MYBASE(pT, n)
2158         {
2159         }
2160  
2161 #ifdef SS_UNSIGNED
2162         CStdStr(PCUSTR pU)
2163         {
2164                 *this = reinterpret_cast<PCSTR>(pU);
2165         }
2166 #endif
2167  
2168         CStdStr(PCSTR pA)
2169         {
2170         #ifdef SS_ANSI
2171                 *this = pA;
2172         #else
2173                 if ( !TryLoad(pA) )
2174                         *this = pA;
2175         #endif
2176         }
2177  
2178         CStdStr(PCWSTR pW)
2179         {
2180         #ifdef SS_ANSI
2181                 *this = pW;
2182         #else
2183                 if ( !TryLoad(pW) )
2184                         *this = pW;
2185         #endif
2186         }
2187  
2188         CStdStr(MYCITER first, MYCITER last)
2189                 : MYBASE(first, last)
2190         {
2191         }
2192  
2193         CStdStr(MYSIZE nSize, MYVAL ch, const MYALLOC& al=MYALLOC())
2194                 : MYBASE(nSize, ch, al)
2195         {
2196         }
2197  
2198         #ifdef SS_INC_COMDEF
2199                 CStdStr(const _bstr_t& bstr)
2200                 {
2201                         if ( bstr.length() > 0 )
2202                                 this->append(static_cast<PCMYSTR>(bstr), bstr.length());
2203                 }
2204         #endif
2205  
2206         // CStdStr inline assignment operators -- the ssasn function now takes care
2207         // of fixing  the MSVC assignment bug (see knowledge base article Q172398).
2208         MYTYPE& operator=(const MYTYPE& str)
2209         {
2210                 ssasn(*this, str);
2211                 return *this;
2212         }
2213  
2214         MYTYPE& operator=(const std::string& str)
2215         {
2216                 ssasn(*this, str);
2217                 return *this;
2218         }
2219  
2220         MYTYPE& operator=(const std::wstring& str)
2221         {
2222                 ssasn(*this, str);
2223                 return *this;
2224         }
2225  
2226         MYTYPE& operator=(PCSTR pA)
2227         {
2228                 ssasn(*this, pA);
2229                 return *this;
2230         }
2231  
2232         MYTYPE& operator=(PCWSTR pW)
2233         {
2234                 ssasn(*this, pW);
2235                 return *this;
2236         }
2237  
2238 #ifdef SS_UNSIGNED
2239         MYTYPE& operator=(PCUSTR pU)
2240         {
2241                 ssasn(*this, reinterpret_cast<PCSTR>(pU));
2242                 return *this;
2243         }
2244 #endif
2245  
2246         MYTYPE& operator=(CT t)
2247         {
2248                 Q172398(*this);
2249                 this->assign(1, t);
2250                 return *this;
2251         }
2252  
2253         #ifdef SS_INC_COMDEF
2254                 MYTYPE& operator=(const _bstr_t& bstr)
2255                 {
2256                         if ( bstr.length() > 0 )
2257                         {
2258                                 this->assign(static_cast<PCMYSTR>(bstr), bstr.length());
2259                                 return *this;
2260                         }
2261                         else
2262                         {
2263                                 this->erase();
2264                                 return *this;
2265                         }
2266                 }
2267         #endif
2268  
2269  
2270         // Overloads  also needed to fix the MSVC assignment bug (KB: Q172398)
2271         //  *** Thanks to Pete The Plumber for catching this one ***
2272         // They also are compiled if you have explicitly turned off refcounting
2273         #if ( defined(_MSC_VER) && ( _MSC_VER < 1200 ) ) || defined(SS_NO_REFCOUNT)
2274  
2275                 MYTYPE& assign(const MYTYPE& str)
2276                 {
2277                         Q172398(*this);
2278                         sscpy(GetBuffer(str.size()+1), SSREF(str));
2279                         this->ReleaseBuffer(str.size());
2280                         return *this;
2281                 }
2282  
2283                 MYTYPE& assign(const MYTYPE& str, MYSIZE nStart, MYSIZE nChars)
2284                 {
2285                         // This overload of basic_string::assign is supposed to assign up to
2286                         // <nChars> or the NULL terminator, whichever comes first.  Since we
2287                         // are about to call a less forgiving overload (in which <nChars>
2288                         // must be a valid length), we must adjust the length here to a safe
2289                         // value.  Thanks to Ullrich Pollähne for catching this bug
2290  
2291                         nChars          = SSMIN(nChars, str.length() - nStart);
2292                         MYTYPE strTemp(str.c_str()+nStart, nChars);
2293                         Q172398(*this);
2294                         this->assign(strTemp);
2295                         return *this;
2296                 }
2297  
2298                 MYTYPE& assign(const MYBASE& str)
2299                 {
2300                         ssasn(*this, str);
2301                         return *this;
2302                 }
2303  
2304                 MYTYPE& assign(const MYBASE& str, MYSIZE nStart, MYSIZE nChars)
2305                 {
2306                         // This overload of basic_string::assign is supposed to assign up to
2307                         // <nChars> or the NULL terminator, whichever comes first.  Since we
2308                         // are about to call a less forgiving overload (in which <nChars>
2309                         // must be a valid length), we must adjust the length here to a safe
2310                         // value. Thanks to Ullrich Pollähne for catching this bug
2311  
2312                         nChars          = SSMIN(nChars, str.length() - nStart);
2313  
2314                         // Watch out for assignment to self
2315  
2316                         if ( this == &str )
2317                         {
2318                                 MYTYPE strTemp(str.c_str() + nStart, nChars);
2319                                 static_cast<MYBASE*>(this)->assign(strTemp);
2320                         }
2321                         else
2322                         {
2323                                 Q172398(*this);
2324                                 static_cast<MYBASE*>(this)->assign(str.c_str()+nStart, nChars);
2325                         }
2326                         return *this;
2327                 }
2328  
2329                 MYTYPE& assign(const CT* pC, MYSIZE nChars)
2330                 {
2331                         // Q172398 only fix -- erase before assigning, but not if we're
2332                         // assigning from our own buffer
2333  
2334         #if defined ( _MSC_VER ) && ( _MSC_VER < 1200 )
2335                         if ( !this->empty() &&
2336                                 ( pC < this->data() || pC > this->data() + this->capacity() ) )
2337                         {
2338                                 this->erase();
2339                         }
2340         #endif
2341                         Q172398(*this);
2342                         static_cast<MYBASE*>(this)->assign(pC, nChars);
2343                         return *this;
2344                 }
2345  
2346                 MYTYPE& assign(MYSIZE nChars, MYVAL val)
2347                 {
2348                         Q172398(*this);
2349                         static_cast<MYBASE*>(this)->assign(nChars, val);
2350                         return *this;
2351                 }
2352  
2353                 MYTYPE& assign(const CT* pT)
2354                 {
2355                         return this->assign(pT, MYBASE::traits_type::length(pT));
2356                 }
2357  
2358                 MYTYPE& assign(MYCITER iterFirst, MYCITER iterLast)
2359                 {
2360         #if defined ( _MSC_VER ) && ( _MSC_VER < 1200 )
2361                         // Q172398 fix.  don't call erase() if we're assigning from ourself
2362                         if ( iterFirst < this->begin() ||
2363                  iterFirst > this->begin() + this->size() )
2364             {
2365                                 this->erase()
2366             }
2367         #endif
2368                         this->replace(this->begin(), this->end(), iterFirst, iterLast);
2369                         return *this;
2370                 }
2371         #endif
2372  
2373  
2374         // -------------------------------------------------------------------------
2375         // CStdStr inline concatenation.
2376         // -------------------------------------------------------------------------
2377         MYTYPE& operator+=(const MYTYPE& str)
2378         {
2379                 ssadd(*this, str);
2380                 return *this;
2381         }
2382  
2383         MYTYPE& operator+=(const std::string& str)
2384         {
2385                 ssadd(*this, str);
2386                 return *this;
2387         }
2388  
2389         MYTYPE& operator+=(const std::wstring& str)
2390         {
2391                 ssadd(*this, str);
2392                 return *this;
2393         }
2394  
2395         MYTYPE& operator+=(PCSTR pA)
2396         {
2397                 ssadd(*this, pA);
2398                 return *this;
2399         }
2400  
2401         MYTYPE& operator+=(PCWSTR pW)
2402         {
2403                 ssadd(*this, pW);
2404                 return *this;
2405         }
2406  
2407         MYTYPE& operator+=(CT t)
2408         {
2409                 this->append(1, t);
2410                 return *this;
2411         }
2412         #ifdef SS_INC_COMDEF    // if we have _bstr_t, define a += for it too.
2413                 MYTYPE& operator+=(const _bstr_t& bstr)
2414                 {
2415                         return this->operator+=(static_cast<PCMYSTR>(bstr));
2416                 }
2417         #endif
2418  
2419  
2420         // -------------------------------------------------------------------------
2421         // Case changing functions
2422         // -------------------------------------------------------------------------
2423  
2424     MYTYPE& ToUpper(const std::locale& loc=std::locale())
2425         {
2426                 // Note -- if there are any MBCS character sets in which the lowercase
2427                 // form a character takes up a different number of bytes than the
2428                 // uppercase form, this would probably not work...
2429  
2430                 std::transform(this->begin(),
2431                                            this->end(),
2432                                            this->begin(),
182 roytam 2433 #ifdef SS_NO_LOCALE
2434                                            SSToUpper<CT>());
2435 #else
181 roytam 2436                                            std::bind2nd(SSToUpper<CT>(), loc));
182 roytam 2437 #endif
181 roytam 2438  
2439                 // ...but if it were, this would probably work better.  Also, this way
2440                 // seems to be a bit faster when anything other then the "C" locale is
2441                 // used...
2442  
2443 //              if ( !empty() )
2444 //              {
2445 //                      ssupr(this->GetBuf(), this->size(), loc);
2446 //                      this->RelBuf();
2447 //              }
2448  
2449                 return *this;
2450         }
2451  
2452         MYTYPE& ToLower(const std::locale& loc=std::locale())
2453         {
2454                 // Note -- if there are any MBCS character sets in which the lowercase
2455                 // form a character takes up a different number of bytes than the
2456                 // uppercase form, this would probably not work...
2457  
2458                 std::transform(this->begin(),
2459                                            this->end(),
2460                                            this->begin(),
182 roytam 2461 #ifdef SS_NO_LOCALE
2462                                            SSToLower<CT>());
2463 #else
181 roytam 2464                                            std::bind2nd(SSToLower<CT>(), loc));
182 roytam 2465 #endif
181 roytam 2466  
2467                 // ...but if it were, this would probably work better.  Also, this way
2468                 // seems to be a bit faster when anything other then the "C" locale is
2469                 // used...
2470  
2471 //              if ( !empty() )
2472 //              {
2473 //                      sslwr(this->GetBuf(), this->size(), loc);
2474 //                      this->RelBuf();
2475 //              }
2476                 return *this;
2477         }
2478  
2479  
2480         MYTYPE& Normalize()
2481         {
2482                 return Trim().ToLower();
2483         }
2484  
2485  
2486         // -------------------------------------------------------------------------
2487         // CStdStr -- Direct access to character buffer.  In the MS' implementation,
2488         // the at() function that we use here also calls _Freeze() providing us some
2489         // protection from multithreading problems associated with ref-counting.
2490     // In VC 7 and later, of course, the ref-counting stuff is gone.
2491         // -------------------------------------------------------------------------
2492  
2493         CT* GetBuf(int nMinLen=-1)
2494         {
2495                 if ( static_cast<int>(this->size()) < nMinLen )
2496                         this->resize(static_cast<MYSIZE>(nMinLen));
2497  
2498                 return this->empty() ? const_cast<CT*>(this->data()) : &(this->at(0));
2499         }
2500  
2501         CT* SetBuf(int nLen)
2502         {
2503                 nLen = ( nLen > 0 ? nLen : 0 );
2504                 if ( this->capacity() < 1 && nLen == 0 )
2505                         this->resize(1);
2506  
2507                 this->resize(static_cast<MYSIZE>(nLen));
2508                 return const_cast<CT*>(this->data());
2509         }
2510         void RelBuf(int nNewLen=-1)
2511         {
2512                 this->resize(static_cast<MYSIZE>(nNewLen > -1 ? nNewLen :
2513                                                         sslen(this->c_str())));
2514         }
2515  
2516         void BufferRel()                 { RelBuf(); }                  // backwards compatability
2517         CT*  Buffer()                    { return GetBuf(); }   // backwards compatability
2518         CT*  BufferSet(int nLen) { return SetBuf(nLen);}// backwards compatability
2519  
2520         bool Equals(const CT* pT, bool bUseCase=false) const
2521         {
2522                 return  0 == (bUseCase ? this->compare(pT) : ssicmp(this->c_str(), pT));
2523         }
2524  
2525         // -------------------------------------------------------------------------
2526         // FUNCTION:  CStdStr::Load
2527         // REMARKS:
2528         //              Loads string from resource specified by nID
2529         //
2530         // PARAMETERS:
2531         //              nID - resource Identifier.  Purely a Win32 thing in this case
2532         //
2533         // RETURN VALUE:
2534         //              true if successful, false otherwise
2535         // -------------------------------------------------------------------------
2536  
2537 #ifndef SS_ANSI
2538  
2539         bool Load(UINT nId, HMODULE hModule=NULL)
2540         {
2541                 bool bLoaded            = false;        // set to true of we succeed.
2542  
2543         #ifdef _MFC_VER         // When in Rome (or MFC land)...
2544  
2545                 // If they gave a resource handle, use it.  Note - this is archaic
2546                 // and not really what I would recommend.  But then again, in MFC
2547                 // land, you ought to be using CString for resources anyway since
2548                 // it walks the resource chain for you.
2549  
2550                 HMODULE hModuleOld = NULL;
2551  
2552                 if ( NULL != hModule )
2553                 {
2554                         hModuleOld = AfxGetResourceHandle();
2555                         AfxSetResourceHandle(hModule);
2556                 }
2557  
2558                 // ...load the string
2559  
2560                 CString strRes;
2561                 bLoaded                         = FALSE != strRes.LoadString(nId);
2562  
2563                 // ...and if we set the resource handle, restore it.
2564  
2565                 if ( NULL != hModuleOld )
2566                         AfxSetResourceHandle(hModule);
2567  
2568                 if ( bLoaded )
2569                         *this                   = strRes;
2570  
2571         #else // otherwise make our own hackneyed version of CString's Load
2572  
2573                 // Get the resource name and module handle
2574  
2575                 if ( NULL == hModule )
2576                         hModule                 = GetResourceHandle();
2577  
2578                 PCTSTR szName           = MAKEINTRESOURCE((nId>>4)+1); // lifted
2579                 DWORD dwSize            = 0;
2580  
2581                 // No sense continuing if we can't find the resource
2582  
2583                 HRSRC hrsrc                     = ::FindResource(hModule, szName, RT_STRING);
2584  
2585                 if ( NULL == hrsrc )
2586                 {
2587                         TRACE(_T("Cannot find resource %d: 0x%X"), nId, ::GetLastError());
2588                 }
2589                 else if ( 0 == (dwSize = ::SizeofResource(hModule, hrsrc) / sizeof(CT)))
2590                 {
2591                         TRACE(_T("Cant get size of resource %d 0x%X\n"),nId,GetLastError());
2592                 }
2593                 else
2594                 {
2595                         bLoaded                 = 0 != ssload(hModule, nId, GetBuf(dwSize), dwSize);
2596                         ReleaseBuffer();
2597                 }
2598  
2599         #endif  // #ifdef _MFC_VER
2600  
2601                 if ( !bLoaded )
2602                         TRACE(_T("String not loaded 0x%X\n"), ::GetLastError());
2603  
2604                 return bLoaded;
2605         }
2606  
2607 #endif  // #ifdef SS_ANSI
2608  
2609         // -------------------------------------------------------------------------
2610         // FUNCTION:  CStdStr::Format
2611         //              void _cdecl Formst(CStdStringA& PCSTR szFormat, ...)
2612         //              void _cdecl Format(PCSTR szFormat);
2613         //          
2614         // DESCRIPTION:
2615         //              This function does sprintf/wsprintf style formatting on CStdStringA
2616         //              objects.  It looks a lot like MFC's CString::Format.  Some people
2617         //              might even call this identical.  Fortunately, these people are now
2618         //              dead... heh heh.
2619         //
2620         // PARAMETERS:
2621         //              nId - ID of string resource holding the format string
2622         //              szFormat - a PCSTR holding the format specifiers
2623         //              argList - a va_list holding the arguments for the format specifiers.
2624         //
2625         // RETURN VALUE:  None.
2626         // -------------------------------------------------------------------------
2627         // formatting (using wsprintf style formatting)
2628  
2629     // If they want a Format() function that safely handles string objects
2630     // without casting
2631  
2632 #ifdef SS_SAFE_FORMAT      
2633  
2634     // Question:  Joe, you wacky coder you, why do you have so many overloads
2635     //      of the Format() function
2636     // Answer:  One reason only - CString compatability.  In short, by making
2637     //      the Format() function a template this way, I can do strong typing
2638     //      and allow people to pass CStdString arguments as fillers for
2639     //      "%s" format specifiers without crashing their program!  The downside
2640     //      is that I need to overload on the number of arguments.   If you are
2641     //      passing more arguments than I have listed below in any of my
2642     //      overloads, just add another one.
2643     //
2644     //      Yes, yes, this is really ugly.  In essence what I am doing here is
2645     //      protecting people from a bad (and incorrect) programming practice
2646     //      that they should not be doing anyway.  I am protecting them from
2647     //      themselves.  Why am I doing this?  Well, if you had any idea the
2648     //      number of times I've been emailed by people about this
2649     //      "incompatability" in my code, you wouldn't ask.
2650  
2651         void Fmt(const CT* szFmt, ...)
2652         {
2653                 va_list argList;
2654                 va_start(argList, szFmt);
2655                 FormatV(szFmt, argList);
2656                 va_end(argList);
2657         }
2658  
2659 #ifndef SS_ANSI
2660  
2661     void Format(UINT nId)
2662     {
2663                 MYTYPE strFmt;
2664                 if ( strFmt.Load(nId) )
2665             this->swap(strFmt);
2666     }
2667     template<class A1>
2668     void Format(UINT nId, const A1& v)
2669     {
2670                 MYTYPE strFmt;
2671                 if ( strFmt.Load(nId) )
2672             Fmt(strFmt, FmtArg<A1>(v)());
2673     }
2674     template<class A1, class A2>
2675     void Format(UINT nId, const A1& v1, const A2& v2)
2676     {
2677                 MYTYPE strFmt;
2678                 if ( strFmt.Load(nId) )
2679            Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)());
2680     }
2681     template<class A1, class A2, class A3>
2682     void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3)
2683     {
2684                 MYTYPE strFmt;
2685                 if ( strFmt.Load(nId) )
2686         {
2687             Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
2688             FmtArg<A3>(v3)());
2689         }
2690     }
2691     template<class A1, class A2, class A3, class A4>
2692     void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,
2693                 const A4& v4)
2694     {
2695                 MYTYPE strFmt;
2696                 if ( strFmt.Load(nId) )
2697         {
2698             Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
2699                 FmtArg<A3>(v3)(), FmtArg<A4>(v4)());
2700         }
2701     }
2702     template<class A1, class A2, class A3, class A4, class A5>
2703     void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,
2704                 const A4& v4, const A5& v5)
2705     {
2706                 MYTYPE strFmt;
2707                 if ( strFmt.Load(nId) )
2708         {
2709             Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
2710                 FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)());
2711         }
2712     }
2713     template<class A1, class A2, class A3, class A4, class A5, class A6>
2714     void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,
2715                 const A4& v4, const A5& v5, const A6& v6)
2716     {
2717                 MYTYPE strFmt;
2718                 if ( strFmt.Load(nId) )
2719         {
2720             Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
2721                 FmtArg<A3>(v3)(), FmtArg<A4>(v4)(),FmtArg<A5>(v5)(),
2722                 FmtArg<A6>(v6)());
2723         }
2724     }
2725     template<class A1, class A2, class A3, class A4, class A5, class A6,
2726         class A7>
2727     void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,
2728                 const A4& v4, const A5& v5, const A6& v6, const A7& v7)
2729     {
2730                 MYTYPE strFmt;
2731                 if ( strFmt.Load(nId) )
2732         {
2733             Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
2734                 FmtArg<A3>(v3)(), FmtArg<A4>(v4)(),FmtArg<A5>(v5)(),
2735                 FmtArg<A6>(v6)(), FmtArg<A7>(v7)());
2736         }
2737     }
2738     template<class A1, class A2, class A3, class A4, class A5, class A6,
2739         class A7, class A8>
2740     void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,
2741                 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
2742                 const A8& v8)
2743     {
2744                 MYTYPE strFmt;
2745                 if ( strFmt.Load(nId) )
2746         {
2747            Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
2748                 FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
2749                 FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)());
2750         }
2751     }
2752     template<class A1, class A2, class A3, class A4, class A5, class A6,
2753         class A7, class A8, class A9>
2754     void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,
2755                 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
2756                 const A8& v8, const A9& v9)
2757     {
2758                 MYTYPE strFmt;
2759                 if ( strFmt.Load(nId) )
2760         {
2761             Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
2762                 FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
2763                 FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),
2764                 FmtArg<A9>(v9)());
2765         }
2766     }
2767     template<class A1, class A2, class A3, class A4, class A5, class A6,
2768         class A7, class A8, class A9, class A10>
2769     void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,
2770                 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
2771                 const A8& v8, const A9& v9, const A10& v10)
2772     {
2773                 MYTYPE strFmt;
2774                 if ( strFmt.Load(nId) )
2775         {
2776             Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
2777                 FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
2778                 FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),
2779                 FmtArg<A9>(v9)(), FmtArg<A10>(v10)());
2780         }
2781     }
2782     template<class A1, class A2, class A3, class A4, class A5, class A6,
2783         class A7, class A8, class A9, class A10, class A11>
2784     void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,
2785                 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
2786                 const A8& v8, const A9& v9, const A10& v10, const A11& v11)
2787     {
2788                 MYTYPE strFmt;
2789                 if ( strFmt.Load(nId) )
2790         {
2791             Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
2792                 FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
2793                 FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),
2794                 FmtArg<A9>(v9)(),FmtArg<A10>(v10)(),FmtArg<A11>(v11)());
2795         }
2796     }
2797     template<class A1, class A2, class A3, class A4, class A5, class A6,
2798         class A7, class A8, class A9, class A10, class A11, class A12>
2799     void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,
2800                 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
2801                 const A8& v8, const A9& v9, const A10& v10, const A11& v11,
2802                 const A12& v12)
2803     {
2804                 MYTYPE strFmt;
2805                 if ( strFmt.Load(nId) )
2806         {
2807             Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
2808                 FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
2809                 FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),
2810                 FmtArg<A9>(v9)(), FmtArg<A10>(v10)(),FmtArg<A11>(v11)(),
2811                 FmtArg<A12>(v12)());
2812         }
2813     }
2814     template<class A1, class A2, class A3, class A4, class A5, class A6,
2815         class A7, class A8, class A9, class A10, class A11, class A12,
2816         class A13>
2817     void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,
2818                 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
2819                 const A8& v8, const A9& v9, const A10& v10, const A11& v11,
2820                 const A12& v12, const A13& v13)
2821     {
2822                 MYTYPE strFmt;
2823                 if ( strFmt.Load(nId) )
2824         {
2825             Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
2826                 FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
2827                 FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),
2828                 FmtArg<A9>(v9)(), FmtArg<A10>(v10)(),FmtArg<A11>(v11)(),
2829                 FmtArg<A12>(v12)(), FmtArg<A13>(v13)());
2830         }
2831     }
2832     template<class A1, class A2, class A3, class A4, class A5, class A6,
2833         class A7, class A8, class A9, class A10, class A11, class A12,
2834         class A13, class A14>
2835     void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,
2836                 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
2837                 const A8& v8, const A9& v9, const A10& v10, const A11& v11,
2838                 const A12& v12, const A13& v13, const A14& v14)
2839     {
2840                 MYTYPE strFmt;
2841                 if ( strFmt.Load(nId) )
2842         {
2843             Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
2844                 FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
2845                 FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),
2846                 FmtArg<A9>(v9)(), FmtArg<A10>(v10)(),FmtArg<A11>(v11)(),
2847                 FmtArg<A12>(v12)(), FmtArg<A13>(v13)(),FmtArg<A14>(v14)());
2848         }
2849     }
2850     template<class A1, class A2, class A3, class A4, class A5, class A6,
2851         class A7, class A8, class A9, class A10, class A11, class A12,
2852         class A13, class A14, class A15>
2853     void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,
2854                 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
2855                 const A8& v8, const A9& v9, const A10& v10, const A11& v11,
2856                 const A12& v12, const A13& v13, const A14& v14, const A15& v15)
2857     {
2858                 MYTYPE strFmt;
2859                 if ( strFmt.Load(nId) )
2860         {
2861             Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
2862                 FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
2863                 FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),
2864                 FmtArg<A9>(v9)(), FmtArg<A10>(v10)(),FmtArg<A11>(v11)(),
2865                 FmtArg<A12>(v12)(),FmtArg<A13>(v13)(),FmtArg<A14>(v14)(),
2866                 FmtArg<A15>(v15)());
2867         }
2868     }
2869     template<class A1, class A2, class A3, class A4, class A5, class A6,
2870         class A7, class A8, class A9, class A10, class A11, class A12,
2871         class A13, class A14, class A15, class A16>
2872     void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,
2873                 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
2874                 const A8& v8, const A9& v9, const A10& v10, const A11& v11,
2875                 const A12& v12, const A13& v13, const A14& v14, const A15& v15,
2876                 const A16& v16)
2877     {
2878                 MYTYPE strFmt;
2879                 if ( strFmt.Load(nId) )
2880         {
2881             Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
2882                 FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
2883                 FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),
2884                 FmtArg<A9>(v9)(), FmtArg<A10>(v10)(),FmtArg<A11>(v11)(),
2885                 FmtArg<A12>(v12)(),FmtArg<A13>(v13)(),FmtArg<A14>(v14)(),
2886                 FmtArg<A15>(v15)(), FmtArg<A16>(v16)());
2887         }
2888     }
2889     template<class A1, class A2, class A3, class A4, class A5, class A6,
2890         class A7, class A8, class A9, class A10, class A11, class A12,
2891         class A13, class A14, class A15, class A16, class A17>
2892     void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,
2893                 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
2894                 const A8& v8, const A9& v9, const A10& v10, const A11& v11,
2895                 const A12& v12, const A13& v13, const A14& v14, const A15& v15,
2896                 const A16& v16, const A17& v17)
2897     {
2898                 MYTYPE strFmt;
2899                 if ( strFmt.Load(nId) )
2900         {
2901             Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
2902                 FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
2903                 FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),
2904                 FmtArg<A9>(v9)(), FmtArg<A10>(v10)(),FmtArg<A11>(v11)(),
2905                 FmtArg<A12>(v12)(),FmtArg<A13>(v13)(),FmtArg<A14>(v14)(),
2906                 FmtArg<A15>(v15)(),FmtArg<A16>(v16)(),FmtArg<A17>(v17)());
2907         }
2908     }
2909  
2910 #endif // #ifndef SS_ANSI
2911  
2912     // ...now the other overload of Format: the one that takes a string literal
2913  
2914     void Format(const CT* szFmt)
2915     {
2916         *this = szFmt;
2917     }
2918     template<class A1>
2919     void Format(const CT* szFmt, const A1& v)
2920     {
2921         Fmt(szFmt, FmtArg<A1>(v)());
2922     }
2923     template<class A1, class A2>
2924     void Format(const CT* szFmt, const A1& v1, const A2& v2)
2925     {
2926         Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)());
2927     }
2928     template<class A1, class A2, class A3>
2929     void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3)
2930     {
2931         Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
2932             FmtArg<A3>(v3)());
2933     }
2934     template<class A1, class A2, class A3, class A4>
2935     void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,
2936                 const A4& v4)
2937     {
2938         Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
2939             FmtArg<A3>(v3)(), FmtArg<A4>(v4)());
2940     }
2941     template<class A1, class A2, class A3, class A4, class A5>
2942     void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,
2943                 const A4& v4, const A5& v5)
2944     {
2945         Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
2946             FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)());
2947     }
2948     template<class A1, class A2, class A3, class A4, class A5, class A6>
2949     void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,
2950                 const A4& v4, const A5& v5, const A6& v6)
2951     {
2952         Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
2953             FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
2954             FmtArg<A6>(v6)());
2955     }
2956     template<class A1, class A2, class A3, class A4, class A5, class A6,
2957         class A7>
2958     void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,
2959                 const A4& v4, const A5& v5, const A6& v6, const A7& v7)
2960     {
2961         Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
2962             FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
2963             FmtArg<A6>(v6)(), FmtArg<A7>(v7)());
2964     }
2965     template<class A1, class A2, class A3, class A4, class A5, class A6,
2966         class A7, class A8>
2967     void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,
2968                 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
2969                 const A8& v8)
2970     {
2971         Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
2972             FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
2973             FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)());
2974     }
2975     template<class A1, class A2, class A3, class A4, class A5, class A6,
2976         class A7, class A8, class A9>
2977     void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,
2978                 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
2979                 const A8& v8, const A9& v9)
2980     {
2981         Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
2982             FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
2983             FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),
2984             FmtArg<A9>(v9)());
2985     }
2986     template<class A1, class A2, class A3, class A4, class A5, class A6,
2987         class A7, class A8, class A9, class A10>
2988     void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,
2989                 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
2990                 const A8& v8, const A9& v9, const A10& v10)
2991     {
2992         Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
2993             FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
2994             FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),
2995             FmtArg<A9>(v9)(), FmtArg<A10>(v10)());
2996     }
2997     template<class A1, class A2, class A3, class A4, class A5, class A6,
2998         class A7, class A8, class A9, class A10, class A11>
2999     void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,
3000                 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
3001                 const A8& v8, const A9& v9, const A10& v10, const A11& v11)
3002     {
3003         Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
3004             FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
3005             FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),
3006             FmtArg<A9>(v9)(),FmtArg<A10>(v10)(),FmtArg<A11>(v11)());
3007     }
3008     template<class A1, class A2, class A3, class A4, class A5, class A6,
3009         class A7, class A8, class A9, class A10, class A11, class A12>
3010     void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,
3011                 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
3012                 const A8& v8, const A9& v9, const A10& v10, const A11& v11,
3013                 const A12& v12)
3014     {
3015         Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
3016             FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
3017             FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),
3018             FmtArg<A9>(v9)(), FmtArg<A10>(v10)(),FmtArg<A11>(v11)(),
3019             FmtArg<A12>(v12)());
3020     }
3021     template<class A1, class A2, class A3, class A4, class A5, class A6,
3022         class A7, class A8, class A9, class A10, class A11, class A12,
3023         class A13>
3024     void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,
3025                 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
3026                 const A8& v8, const A9& v9, const A10& v10, const A11& v11,
3027                 const A12& v12, const A13& v13)
3028     {
3029         Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
3030             FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
3031             FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),
3032             FmtArg<A9>(v9)(), FmtArg<A10>(v10)(),FmtArg<A11>(v11)(),
3033             FmtArg<A12>(v12)(), FmtArg<A13>(v13)());
3034     }
3035     template<class A1, class A2, class A3, class A4, class A5, class A6,
3036         class A7, class A8, class A9, class A10, class A11, class A12,
3037         class A13, class A14>
3038     void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,
3039                 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
3040                 const A8& v8, const A9& v9, const A10& v10, const A11& v11,
3041                 const A12& v12, const A13& v13, const A14& v14)
3042     {
3043         Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
3044             FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
3045             FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),
3046             FmtArg<A9>(v9)(), FmtArg<A10>(v10)(),FmtArg<A11>(v11)(),
3047             FmtArg<A12>(v12)(), FmtArg<A13>(v13)(),FmtArg<A14>(v14)());
3048     }
3049     template<class A1, class A2, class A3, class A4, class A5, class A6,
3050         class A7, class A8, class A9, class A10, class A11, class A12,
3051         class A13, class A14, class A15>
3052     void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,
3053                 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
3054                 const A8& v8, const A9& v9, const A10& v10, const A11& v11,
3055                 const A12& v12, const A13& v13, const A14& v14, const A15& v15)
3056     {
3057         Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
3058             FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
3059             FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),
3060             FmtArg<A9>(v9)(), FmtArg<A10>(v10)(),FmtArg<A11>(v11)(),
3061             FmtArg<A12>(v12)(),FmtArg<A13>(v13)(),FmtArg<A14>(v14)(),
3062             FmtArg<A15>(v15)());
3063     }
3064     template<class A1, class A2, class A3, class A4, class A5, class A6,
3065         class A7, class A8, class A9, class A10, class A11, class A12,
3066         class A13, class A14, class A15, class A16>
3067     void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,
3068                 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
3069                 const A8& v8, const A9& v9, const A10& v10, const A11& v11,
3070                 const A12& v12, const A13& v13, const A14& v14, const A15& v15,
3071                 const A16& v16)
3072     {
3073         Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
3074             FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
3075             FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),
3076             FmtArg<A9>(v9)(), FmtArg<A10>(v10)(),FmtArg<A11>(v11)(),
3077             FmtArg<A12>(v12)(),FmtArg<A13>(v13)(),FmtArg<A14>(v14)(),
3078             FmtArg<A15>(v15)(), FmtArg<A16>(v16)());
3079     }
3080     template<class A1, class A2, class A3, class A4, class A5, class A6,
3081         class A7, class A8, class A9, class A10, class A11, class A12,
3082         class A13, class A14, class A15, class A16, class A17>
3083     void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,
3084                 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
3085                 const A8& v8, const A9& v9, const A10& v10, const A11& v11,
3086                 const A12& v12, const A13& v13, const A14& v14, const A15& v15,
3087                 const A16& v16, const A17& v17)
3088     {
3089         Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
3090             FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
3091             FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),
3092             FmtArg<A9>(v9)(), FmtArg<A10>(v10)(),FmtArg<A11>(v11)(),
3093             FmtArg<A12>(v12)(),FmtArg<A13>(v13)(),FmtArg<A14>(v14)(),
3094             FmtArg<A15>(v15)(),FmtArg<A16>(v16)(),FmtArg<A17>(v17)());
3095     }
3096  
3097 #else  // #ifdef SS_SAFE_FORMAT
3098  
3099  
3100 #ifndef SS_ANSI
3101  
3102         void Format(UINT nId, ...)
3103         {
3104                 va_list argList;
3105                 va_start(argList, nId);
3106  
3107                 MYTYPE strFmt;
3108                 if ( strFmt.Load(nId) )
3109                         FormatV(strFmt, argList);
3110  
3111                 va_end(argList);
3112         }
3113  
3114 #endif  // #ifdef SS_ANSI
3115  
3116         void Format(const CT* szFmt, ...)
3117         {
3118                 va_list argList;
3119                 va_start(argList, szFmt);
3120                 FormatV(szFmt, argList);
3121                 va_end(argList);
3122         }
3123  
3124 #endif // #ifdef SS_SAFE_FORMAT
3125  
3126         void AppendFormat(const CT* szFmt, ...)
3127         {
3128                 va_list argList;
3129                 va_start(argList, szFmt);
3130                 AppendFormatV(szFmt, argList);
3131                 va_end(argList);
3132         }
3133  
3134         #define MAX_FMT_TRIES           5        // #of times we try
3135         #define FMT_BLOCK_SIZE          2048 // # of bytes to increment per try
3136         #define BUFSIZE_1ST     256
3137         #define BUFSIZE_2ND 512
3138         #define STD_BUF_SIZE            1024
3139  
3140         // an efficient way to add formatted characters to the string.  You may only
3141         // add up to STD_BUF_SIZE characters at a time, though
3142         void AppendFormatV(const CT* szFmt, va_list argList)
3143         {
3144                 CT szBuf[STD_BUF_SIZE];
3145                 int nLen = ssvsprintf(szBuf, STD_BUF_SIZE-1, szFmt, argList);
182 roytam 3146  
181 roytam 3147                 if ( 0 < nLen )
3148                         this->append(szBuf, nLen);
3149         }
3150  
3151         // -------------------------------------------------------------------------
3152         // FUNCTION:  FormatV
3153         //              void FormatV(PCSTR szFormat, va_list, argList);
3154         //          
3155         // DESCRIPTION:
3156         //              This function formats the string with sprintf style format-specs.
3157         //              It makes a general guess at required buffer size and then tries
3158         //              successively larger buffers until it finds one big enough or a
3159         //              threshold (MAX_FMT_TRIES) is exceeded.
3160         //
3161         // PARAMETERS:
3162         //              szFormat - a PCSTR holding the format of the output
3163         //              argList - a Microsoft specific va_list for variable argument lists
3164         //
3165         // RETURN VALUE:
3166         // -------------------------------------------------------------------------
3167  
3168         void FormatV(const CT* szFormat, va_list argList)
3169         {
3170         #ifdef SS_ANSI
182 roytam 3171                 MYTYPE str;
181 roytam 3172                 int nLen        = sslen(szFormat) + STD_BUF_SIZE;
182 roytam 3173                 ssvsprintf(str.GetBuffer(nLen), nLen-1, szFormat, argList);
3174                 str.ReleaseBuffer();
3175                 *this = str;
181 roytam 3176  
3177         #else
3178  
3179                 CT* pBuf                        = NULL;
3180                 int nChars                      = 1;
3181                 int nUsed                       = 0;
3182                 size_type nActual       = 0;
3183                 int nTry                        = 0;
3184  
3185                 do     
3186                 {
3187                         // Grow more than linearly (e.g. 512, 1536, 3072, etc)
3188  
3189                         nChars                  += ((nTry+1) * FMT_BLOCK_SIZE);
3190                         pBuf                    = reinterpret_cast<CT*>(_alloca(sizeof(CT)*nChars));
182 roytam 3191                         nUsed                   = ssvsprintf(pBuf, nChars-1, szFormat, argList);