2 #include "lib/platform/os.h"
7 #if defined(_WIN32) && !defined(va_copy)
8 #define va_copy(dst, src) ((dst) = (src))
11 // =============================================================================
13 // AUTHOR: Joe O'Leary (with outside help noted in comments)
15 // If you find any bugs in this code, please let me know:
17 // jmoleary@earthlink.net
18 // http://www.joeo.net/stdstring.htm (a bit outdated)
20 // The latest version of this code should always be available at the
23 // http://www.joeo.net/code/StdString.zip (Dec 6, 2003)
27 // This header file declares the CStdStr template. This template derives
28 // the Standard C++ Library basic_string<> template and add to it the
29 // the following conveniences:
30 // - The full MFC CString set of functions (including implicit cast)
31 // - writing to/reading from COM IStream interfaces
32 // - Functional objects for use in STL algorithms
34 // From this template, we intstantiate two classes: CStdStringA and
35 // CStdStringW. The name "CStdString" is just a #define of one of these,
36 // based upone the UNICODE macro setting
38 // This header also declares our own version of the MFC/ATL UNICODE-MBCS
39 // conversion macros. Our version looks exactly like the Microsoft's to
40 // facilitate portability.
43 // If you you use this in an MFC or ATL build, you should include either
44 // afx.h or atlbase.h first, as appropriate.
46 // PEOPLE WHO HAVE CONTRIBUTED TO THIS CLASS:
48 // Several people have helped me iron out problems and othewise improve
49 // this class. OK, this is a long list but in my own defense, this code
50 // has undergone two major rewrites. Many of the improvements became
51 // necessary after I rewrote the code as a template. Others helped me
52 // improve the CString facade.
54 // Anyway, these people are (in chronological order):
56 // - Pete the Plumber (???)
58 // - Chris (of Melbsys)
71 // - Baptiste Lepilleur
79 // - Aaron (no last name)
80 // - Joldakowski (???)
84 // - Farrokh Nejadlotfi
94 // - Bagira (full name?)
107 // 2005-JAN-10 - Thanks to Don Beusee for pointing out the danger in mapping
108 // length-checked formatting functions to non-length-checked
109 // CRT equivalents. Also thanks to him for motivating me to
110 // optimize my implementation of Replace()
112 // 2004-APR-22 - A big, big thank you to "MKingman" (whoever you are) for
113 // finally spotting a silly little error in StdCodeCvt that
114 // has been causing me (and users of CStdString) problems for
115 // years in some relatively rare conversions. I had reversed
116 // two length arguments.
118 // 2003-NOV-24 - Thanks to a bunch of people for helping me clean up many
119 // compiler warnings (and yes, even a couple of actual compiler
120 // errors). These include Henk Demper for figuring out how
121 // to make the Intellisense work on with CStdString on VC6,
122 // something I was never able to do. Greg Marr pointed out
123 // a compiler warning about an unreferenced symbol and a
124 // problem with my version of Load in MFC builds. Bill
125 // Carducci took a lot of time with me to help me figure out
126 // why some implementations of the Standard C++ Library were
127 // returning error codes for apparently successful conversions
128 // between ASCII and UNICODE. Finally thanks to Brian Groose
129 // for helping me fix compiler signed unsigned warnings in
130 // several functions.
132 // 2003-JUL-10 - Thanks to Charles Godwin for making me realize my 'FmtArg'
133 // fixes had inadvertently broken the DLL-export code (which is
134 // normally commented out. I had to move it up higher. Also
135 // this helped me catch a bug in ssicoll that would prevent
136 // compilation, otherwise.
138 // 2003-MAR-14 - Thanks to Jakko Van Hunen for pointing out a copy-and-paste
139 // bug in one of the overloads of FmtArg.
141 // 2003-MAR-10 - Thanks to Ronny Schulz for (twice!) sending me some changes
142 // to help CStdString build on SGI and for pointing out an
143 // error in placement of my preprocessor macros for ssfmtmsg.
145 // 2002-NOV-26 - Thanks to Bagira for pointing out that my implementation of
146 // SpanExcluding was not properly handling the case in which
147 // the string did NOT contain any of the given characters
149 // 2002-OCT-21 - Many thanks to Paul DeMarco who was invaluable in helping me
150 // get this code working with Borland's free compiler as well
151 // as the Dev-C++ compiler (available free at SourceForge).
153 // 2002-SEP-13 - Thanks to Glen Maynard who helped me get rid of some loud
154 // but harmless warnings that were showing up on g++. Glen
155 // also pointed out that some pre-declarations of FmtArg<>
156 // specializations were unnecessary (and no good on G++)
158 // 2002-JUN-26 - Thanks to Arnt Witteveen for pointing out that I was using
159 // static_cast<> in a place in which I should have been using
160 // reinterpret_cast<> (the ctor for unsigned char strings).
161 // That's what happens when I don't unit-test properly!
162 // Arnt also noticed that CString was silently correcting the
163 // 'nCount' argument to Left() and Right() where CStdString was
164 // not (and crashing if it was bad). That is also now fixed!
166 // 2002-FEB-25 - Thanks to Tim Dowty for pointing out (and giving me the fix
167 // for) a conversion problem with non-ASCII MBCS characters.
168 // CStdString is now used in my favorite commercial MP3 player!
170 // 2001-DEC-06 - Thanks to Wang Haifeng for spotting a problem in one of the
171 // assignment operators (for _bstr_t) that would cause compiler
172 // errors when refcounting protection was turned off.
174 // 2001-NOV-27 - Remove calls to operator!= which involve reverse_iterators
175 // due to a conflict with the rel_ops operator!=. Thanks to
176 // John James for pointing this out.
178 // 2001-OCT-29 - Added a minor range checking fix for the Mid function to
179 // make it as forgiving as CString's version is. Thanks to
180 // Igor Kholodov for noticing this.
181 // - Added a specialization of std::swap for CStdString. Thanks
182 // to Mike Crusader for suggesting this! It's commented out
183 // because you're not supposed to inject your own code into the
184 // 'std' namespace. But if you don't care about that, it's
185 // there if you want it
186 // - Thanks to Jason Mills for catching a case where CString was
187 // more forgiving in the Delete() function than I was.
189 // 2001-JUN-06 - I was violating the Standard name lookup rules stated
190 // in [14.6.2(3)]. None of the compilers I've tried so
191 // far apparently caught this but HP-UX aCC 3.30 did. The
192 // fix was to add 'this->' prefixes in many places.
193 // Thanks to Farrokh Nejadlotfi for this!
195 // 2001-APR-27 - StreamLoad was calculating the number of BYTES in one
196 // case, not characters. Thanks to Pablo Presedo for this.
198 // 2001-FEB-23 - Replace() had a bug which caused infinite loops if the
199 // source string was empty. Fixed thanks to Eric Nitzsche.
201 // 2001-FEB-23 - Scott Hathaway was a huge help in providing me with the
202 // ability to build CStdString on Sun Unix systems. He
203 // sent me detailed build reports about what works and what
204 // does not. If CStdString compiles on your Unix box, you
205 // can thank Scott for it.
207 // 2000-DEC-29 - Joldakowski noticed one overload of Insert failed to do a
208 // range check as CString's does. Now fixed -- thanks!
210 // 2000-NOV-07 - Aaron pointed out that I was calling static member
211 // functions of char_traits via a temporary. This was not
212 // technically wrong, but it was unnecessary and caused
213 // problems for poor old buggy VC5. Thanks Aaron!
215 // 2000-JUL-11 - Joe Woodbury noted that the CString::Find docs don't match
216 // what the CString::Find code really ends up doing. I was
217 // trying to match the docs. Now I match the CString code
218 // - Joe also caught me truncating strings for GetBuffer() calls
219 // when the supplied length was less than the current length.
221 // 2000-MAY-25 - Better support for STLPORT's Standard library distribution
222 // - Got rid of the NSP macro - it interfered with Koenig lookup
223 // - Thanks to Joe Woodbury for catching a TrimLeft() bug that
224 // I introduced in January. Empty strings were not getting
227 // 2000-APR-17 - Thanks to Joe Vitaterna for pointing out that ReverseFind
228 // is supposed to be a const function.
230 // 2000-MAR-07 - Thanks to Ullrich Poll�hne for catching a range bug in one
231 // of the overloads of assign.
233 // 2000-FEB-01 - You can now use CStdString on the Mac with CodeWarrior!
234 // Thanks to Todd Heckel for helping out with this.
236 // 2000-JAN-23 - Thanks to Jim Cline for pointing out how I could make the
237 // Trim() function more efficient.
238 // - Thanks to Jeff Kohn for prompting me to find and fix a typo
239 // in one of the addition operators that takes _bstr_t.
240 // - Got rid of the .CPP file - you only need StdString.h now!
242 // 1999-DEC-22 - Thanks to Greg Pickles for helping me identify a problem
243 // with my implementation of CStdString::FormatV in which
244 // resulting string might not be properly NULL terminated.
246 // 1999-DEC-06 - Chris Conti pointed yet another basic_string<> assignment
247 // bug that MS has not fixed. CStdString did nothing to fix
248 // it either but it does now! The bug was: create a string
249 // longer than 31 characters, get a pointer to it (via c_str())
250 // and then assign that pointer to the original string object.
251 // The resulting string would be empty. Not with CStdString!
253 // 1999-OCT-06 - BufferSet was erasing the string even when it was merely
254 // supposed to shrink it. Fixed. Thanks to Chris Conti.
255 // - Some of the Q172398 fixes were not checking for assignment-
256 // to-self. Fixed. Thanks to Baptiste Lepilleur.
258 // 1999-AUG-20 - Improved Load() function to be more efficient by using
259 // SizeOfResource(). Thanks to Rich Zuris for this.
260 // - Corrected resource ID constructor, again thanks to Rich.
261 // - Fixed a bug that occurred with UNICODE characters above
262 // the first 255 ANSI ones. Thanks to Craig Watson.
263 // - Added missing overloads of TrimLeft() and TrimRight().
264 // Thanks to Karim Ratib for pointing them out
266 // 1999-JUL-21 - Made all calls to GetBuf() with no args check length first.
268 // 1999-JUL-10 - Improved MFC/ATL independence of conversion macros
269 // - Added SS_NO_REFCOUNT macro to allow you to disable any
270 // reference-counting your basic_string<> impl. may do.
271 // - Improved ReleaseBuffer() to be as forgiving as CString.
272 // Thanks for Fan Xia for helping me find this and to
273 // Matthew Williams for pointing it out directly.
275 // 1999-JUL-06 - Thanks to Nigel Nunn for catching a very sneaky bug in
276 // ToLower/ToUpper. They should call GetBuf() instead of
277 // data() in order to ensure the changed string buffer is not
278 // reference-counted (in those implementations that refcount).
280 // 1999-JUL-01 - Added a true CString facade. Now you can use CStdString as
281 // a drop-in replacement for CString. If you find this useful,
282 // you can thank Chris Sells for finally convincing me to give
283 // in and implement it.
284 // - Changed operators << and >> (for MFC CArchive) to serialize
285 // EXACTLY as CString's do. So now you can send a CString out
286 // to a CArchive and later read it in as a CStdString. I have
287 // no idea why you would want to do this but you can.
289 // 1999-JUN-21 - Changed the CStdString class into the CStdStr template.
290 // - Fixed FormatV() to correctly decrement the loop counter.
291 // This was harmless bug but a bug nevertheless. Thanks to
292 // Chris (of Melbsys) for pointing it out
293 // - Changed Format() to try a normal stack-based array before
294 // using to _alloca().
295 // - Updated the text conversion macros to properly use code
296 // pages and to fit in better in MFC/ATL builds. In other
297 // words, I copied Microsoft's conversion stuff again.
298 // - Added equivalents of CString::GetBuffer, GetBufferSetLength
299 // - new sscpy() replacement of CStdString::CopyString()
300 // - a Trim() function that combines TrimRight() and TrimLeft().
302 // 1999-MAR-13 - Corrected the "NotSpace" functional object to use _istpace()
303 // instead of _isspace() Thanks to Dave Plummer for this.
305 // 1999-FEB-26 - Removed errant line (left over from testing) that #defined
306 // _MFC_VER. Thanks to John C Sipos for noticing this.
308 // 1999-FEB-03 - Fixed a bug in a rarely-used overload of operator+() that
309 // caused infinite recursion and stack overflow
310 // - Added member functions to simplify the process of
311 // persisting CStdStrings to/from DCOM IStream interfaces
312 // - Added functional objects (e.g. StdStringLessNoCase) that
313 // allow CStdStrings to be used as keys STL map objects with
314 // case-insensitive comparison
315 // - Added array indexing operators (i.e. operator[]). I
316 // originally assumed that these were unnecessary and would be
317 // inherited from basic_string. However, without them, Visual
318 // C++ complains about ambiguous overloads when you try to use
319 // them. Thanks to Julian Selman to pointing this out.
321 // 1998-FEB-?? - Added overloads of assign() function to completely account
322 // for Q172398 bug. Thanks to "Pete the Plumber" for this
324 // 1998-FEB-?? - Initial submission
327 // 2002 Joseph M. O'Leary. This code is 100% free. Use it anywhere you
328 // want. Rewrite it, restructure it, whatever. If you can write software
329 // that makes money off of it, good for you. I kinda like capitalism.
330 // Please don't blame me if it causes your $30 billion dollar satellite
331 // explode in orbit. If you redistribute it in any form, I'd appreciate it
332 // if you would leave this notice here.
333 // =============================================================================
335 // Avoid multiple inclusion
340 // When using VC, turn off browser references
341 // Turn off unavoidable compiler warnings
343 #if defined(_MSC_VER) && (_MSC_VER > 1100)
344 #pragma component(browser, off, references, "CStdString")
345 #pragma warning (disable : 4290) // C++ Exception Specification ignored
346 #pragma warning (disable : 4127) // Conditional expression is constant
347 #pragma warning (disable : 4097) // typedef name used as synonym for class name
350 // Borland warnings to turn off
353 #pragma option push -w-inl
354 // #pragma warn -inl // Turn off inline function warnings
359 // A copy of IS_INTRESOURCE from VC7. Because old VC6 version of winuser.h
360 // doesn't have this.
362 #define SS_IS_INTRESOURCE(_r) (false)
364 #if !defined (SS_ANSI) && defined(_MSC_VER)
365 #undef SS_IS_INTRESOURCE
367 #define SS_IS_INTRESOURCE(_r) (((unsigned __int64)(_r) >> 16) == 0)
369 #define SS_IS_INTRESOURCE(_r) (((unsigned long)(_r) >> 16) == 0)
374 // MACRO: SS_UNSIGNED
375 // ------------------
376 // This macro causes the addition of a constructor and assignment operator
377 // which take unsigned characters. CString has such functions and in order
378 // to provide maximum CString-compatability, this code needs them as well.
379 // In practice you will likely never need these functions...
381 //#define SS_UNSIGNED
383 #ifdef SS_ALLOW_UNSIGNED_CHARS
387 // MACRO: SS_SAFE_FORMAT
388 // ---------------------
389 // This macro provides limited compatability with a questionable CString
390 // "feature". You can define it in order to avoid a common problem that
391 // people encounter when switching from CString to CStdString.
393 // To illustrate the problem -- With CString, you can do this:
395 // CString sName("Joe");
397 // sTmp.Format("My name is %s", sName); // WORKS!
399 // However if you were to try this with CStdString, your program would
402 // CStdString sName("Joe");
404 // sTmp.Format("My name is %s", sName); // CRASHES!
406 // You must explicitly call c_str() or cast the object to the proper type
408 // sTmp.Format("My name is %s", sName.c_str()); // WORKS!
409 // sTmp.Format("My name is %s", static_cast<PCSTR>(sName));// WORKS!
410 // sTmp.Format("My name is %s", (PCSTR)sName); // WORKS!
412 // This is because it is illegal to pass anything but a POD type as a
413 // variadic argument to a variadic function (i.e. as one of the "..."
414 // arguments). The type const char* is a POD type. The type CStdString
415 // is not. Of course, neither is the type CString, but CString lets you do
416 // it anyway due to the way they laid out the class in binary. I have no
417 // control over this in CStdString since I derive from whatever
418 // implementation of basic_string is available.
420 // However if you have legacy code (which does this) that you want to take
421 // out of the MFC world and you don't want to rewrite all your calls to
422 // Format(), then you can define this flag and it will no longer crash.
424 // Note however that this ONLY works for Format(), not sprintf, fprintf,
425 // etc. If you pass a CStdString object to one of those functions, your
426 // program will crash. Not much I can do to get around this, short of
427 // writing substitutes for those functions as well.
429 #define SS_SAFE_FORMAT // use new template style Format() function
432 // MACRO: SS_NO_IMPLICIT_CAST
433 // --------------------------
434 // Some people don't like the implicit cast to const char* (or rather to
435 // const CT*) that CStdString (and MFC's CString) provide. That was the
436 // whole reason I created this class in the first place, but hey, whatever
437 // bakes your cake. Just #define this macro to get rid of the the implicit
440 //#define SS_NO_IMPLICIT_CAST // gets rid of operator const CT*()
443 // MACRO: SS_NO_REFCOUNT
444 // ---------------------
445 // turns off reference counting at the assignment level. Only needed
446 // for the version of basic_string<> that comes with Visual C++ versions
447 // 6.0 or earlier, and only then in some heavily multithreaded scenarios.
448 // Uncomment it if you feel you need it.
450 //#define SS_NO_REFCOUNT
454 // When this flag is set, we are building code for the Win32 platform and
455 // may use Win32 specific functions (such as LoadString). This gives us
456 // a couple of nice extras for the code.
458 // Obviously, Microsoft's is not the only compiler available for Win32 out
459 // there. So I can't just check to see if _MSC_VER is defined to detect
460 // if I'm building on Win32. So for now, if you use MS Visual C++ or
461 // Borland's compiler, I turn this on. Otherwise you may turn it on
462 // yourself, if you prefer
464 #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(_WIN32)
470 // When this macro is defined, the code attempts only to use ANSI/ISO
471 // standard library functions to do it's work. It will NOT attempt to use
472 // any Win32 of Visual C++ specific functions -- even if they are
473 // available. You may define this flag yourself to prevent any Win32
474 // of VC++ specific functions from being called.
476 // If we're not on Win32, we MUST use an ANSI build
479 #if !defined(SS_NO_ANSI)
486 // Some implementations of the Standard C Library have a non-standard
487 // function known as alloca(). This functions allows one to allocate a
488 // variable amount of memory on the stack. It is needed to implement
489 // the ASCII/MBCS conversion macros.
491 // I wanted to find some way to determine automatically if alloca() is
492 // available on this platform via compiler flags but that is asking for
493 // trouble. The crude test presented here will likely need fixing on
494 // other platforms. Therefore I'll leave it up to you to fiddle with
495 // this test to determine if it exists. Just make sure SS_ALLOCA is or
496 // is not defined as appropriate and you control this feature.
498 #if defined(_MSC_VER) && !defined(SS_ANSI)
505 // Setting this macro means you are using MBCS characters. In MSVC builds,
506 // this macro gets set automatically by detection of the preprocessor flag
507 // _MBCS. For other platforms you may set it manually if you wish. The
508 // only effect it currently has is to cause the allocation of more space
509 // for wchar_t --> char conversions.
510 // Note that MBCS does not mean UNICODE.
520 // MACRO SS_NO_LOCALE
521 // ------------------
522 // If your implementation of the Standard C++ Library lacks the <locale> header,
523 // you can #define this macro to make your code build properly. Note that this
524 // is some of my newest code and frankly I'm not very sure of it, though it does
525 // pass my unit tests.
527 // #define SS_NO_LOCALE
530 // Compiler Error regarding _UNICODE and UNICODE
531 // -----------------------------------------------
532 // Microsoft header files are screwy. Sometimes they depend on a preprocessor
533 // flag named "_UNICODE". Other times they check "UNICODE" (note the lack of
534 // leading underscore in the second version". In several places, they silently
535 // "synchronize" these two flags this by defining one of the other was defined.
536 // In older version of this header, I used to try to do the same thing.
538 // However experience has taught me that this is a bad idea. You get weird
539 // compiler errors that seem to indicate things like LPWSTR and LPTSTR not being
540 // equivalent in UNICODE builds, stuff like that (when they MUST be in a proper
541 // UNICODE build). You end up scratching your head and saying, "But that HAS
544 // So what should you do if you get this error?
546 // Make sure that both macros (_UNICODE and UNICODE) are defined before this
547 // file is included. You can do that by either
549 // a) defining both yourself before any files get included
550 // b) including the proper MS headers in the proper order
551 // c) including this file before any other file, uncommenting
552 // the #defines below, and commenting out the #errors
554 // Personally I recommend solution a) but it's your call.
557 #if defined (_UNICODE) && !defined (UNICODE)
558 #error UNICODE defined but not UNICODE
559 // #define UNICODE // no longer silently fix this
561 #if defined (UNICODE) && !defined (_UNICODE)
562 #error Warning, UNICODE defined but not _UNICODE
563 // #define _UNICODE // no longer silently fix this
568 // -----------------------------------------------------------------------------
569 // MIN and MAX. The Standard C++ template versions go by so many names (at
570 // at least in the MS implementation) that you never know what's available
571 // -----------------------------------------------------------------------------
573 inline const Type
& SSMIN(const Type
& arg1
, const Type
& arg2
)
575 return arg2
< arg1
? arg2
: arg1
;
578 inline const Type
& SSMAX(const Type
& arg1
, const Type
& arg2
)
580 return arg2
> arg1
? arg2
: arg1
;
583 // If they have not #included W32Base.h (part of my W32 utility library) then
584 // we need to define some stuff. Otherwise, this is all defined there.
586 #if !defined(W32BASE_H)
588 // If they want us to use only standard C++ stuff (no Win32 stuff)
592 // On Win32 we have TCHAR.H so just include it. This is NOT violating
593 // the spirit of SS_ANSI as we are not calling any Win32 functions here.
603 // ... but on non-Win32 platforms, we must #define the types we need.
607 typedef const char* PCSTR
;
609 typedef const wchar_t* PCWSTR
;
610 typedef wchar_t* PWSTR
;
612 typedef wchar_t TCHAR
;
616 typedef wchar_t OLECHAR
;
618 #endif // #ifndef _WIN32
621 // Make sure ASSERT and verify are defined using only ANSI stuff
625 #define ASSERT(f) assert((f))
629 #define VERIFY(x) ASSERT((x))
635 #else // ...else SS_ANSI is NOT defined
643 // Make sure ASSERT and verify are defined
647 #define ASSERT(f) _ASSERTE((f))
651 #define VERIFY(x) ASSERT((x))
657 #endif // #ifdef SS_ANSI
663 #endif // #ifndef W32BASE_H
665 // Standard headers needed
667 #include <string> // basic_string
668 #include <algorithm> // for_each, etc.
669 #include <functional> // for StdStringLessNoCase, et al
671 #include <locale> // for various facets
674 // If this is a recent enough version of VC include comdef.h, so we can write
675 // member functions to deal with COM types & compiler support classes e.g.
678 #if defined (_MSC_VER) && (_MSC_VER >= 1100)
680 #define SS_INC_COMDEF // signal that we #included MS comdef.h file
681 #define STDSTRING_INC_COMDEF
682 #define SS_NOTHROW __declspec(nothrow)
688 #define TRACE_DEFINED_HERE
692 // Microsoft defines PCSTR, PCWSTR, etc, but no PCTSTR. I hate to use the
693 // versions with the "L" in front of them because that's a leftover from Win 16
694 // days, even though it evaluates to the same thing. Therefore, Define a PCSTR
697 #if !defined(PCTSTR) && !defined(PCTSTR_DEFINED)
698 typedef const TCHAR
* PCTSTR
;
699 #define PCTSTR_DEFINED
702 #if !defined(PCOLESTR) && !defined(PCOLESTR_DEFINED)
703 typedef const OLECHAR
* PCOLESTR
;
704 #define PCOLESTR_DEFINED
707 #if !defined(POLESTR) && !defined(POLESTR_DEFINED)
708 typedef OLECHAR
* POLESTR
;
709 #define POLESTR_DEFINED
712 #if !defined(PCUSTR) && !defined(PCUSTR_DEFINED)
713 typedef const unsigned char* PCUSTR
;
714 typedef unsigned char* PUSTR
;
715 #define PCUSTR_DEFINED
719 // SGI compiler 7.3 doesnt know these types - oh and btw, remember to use
720 // -LANG:std in the CXX Flags
722 typedef unsigned long DWORD
;
723 typedef void * LPCVOID
;
727 // SS_USE_FACET macro and why we need it:
729 // Since I'm a good little Standard C++ programmer, I use locales. Thus, I
730 // need to make use of the use_facet<> template function here. Unfortunately,
731 // this need is complicated by the fact the MS' implementation of the Standard
732 // C++ Library has a non-standard version of use_facet that takes more
733 // arguments than the standard dictates. Since I'm trying to write CStdString
734 // to work with any version of the Standard library, this presents a problem.
736 // The upshot of this is that I can't do 'use_facet' directly. The MS' docs
737 // tell me that I have to use a macro, _USE() instead. Since _USE obviously
738 // won't be available in other implementations, this means that I have to write
739 // my OWN macro -- SS_USE_FACET -- that evaluates either to _USE or to the
740 // standard, use_facet.
742 // If you are having trouble with the SS_USE_FACET macro, in your implementation
743 // of the Standard C++ Library, you can define your own version of SS_USE_FACET.
747 #define schSTR2(x) schSTR(x)
748 #define schMSG(desc) message(__FILE__ "(" schSTR2(__LINE__) "):" #desc)
753 // STLPort #defines a macro (__STL_NO_EXPLICIT_FUNCTION_TMPL_ARGS) for
754 // all MSVC builds, erroneously in my opinion. It causes problems for
755 // my SS_ANSI builds. In my code, I always comment out that line. You'll
756 // find it in \stlport\config\stl_msvc.h
758 #if defined(__SGI_STL_PORT) && (__SGI_STL_PORT >= 0x400 )
760 #if defined(__STL_NO_EXPLICIT_FUNCTION_TMPL_ARGS) && defined(_MSC_VER)
762 #pragma schMSG(__STL_NO_EXPLICIT_FUNCTION_TMPL_ARGS defined!!)
765 #define SS_USE_FACET(loc, fac) std::use_facet<fac >(loc)
767 #elif defined(_MSC_VER )
769 #define SS_USE_FACET(loc, fac) std::_USE(loc, fac)
772 #elif defined(_RWSTD_NO_TEMPLATE_ON_RETURN_TYPE)
774 #define SS_USE_FACET(loc, fac) std::use_facet(loc, (fac*)0)
778 #define SS_USE_FACET(loc, fac) std::use_facet<fac >(loc)
784 // =============================================================================
785 // UNICODE/MBCS conversion macros. Made to work just like the MFC/ATL ones.
786 // =============================================================================
788 #include <wchar.h> // Added to Std Library with Amendment #1.
790 // First define the conversion helper functions. We define these regardless of
791 // any preprocessor macro settings since their names won't collide.
793 // Not sure if we need all these headers. I believe ANSI says we do.
807 #if defined(_WIN32) || defined (_WIN32_WCE)
809 inline PWSTR
StdCodeCvt(PWSTR pDstW
, int nDst
, PCSTR pSrcA
, int nSrc
,
815 MultiByteToWideChar(acp
, 0, pSrcA
, nSrc
, pDstW
, nDst
);
818 inline PWSTR
StdCodeCvt(PWSTR pDstW
, int nDst
, PCUSTR pSrcA
, int nSrc
,
821 return StdCodeCvt(pDstW
, nDst
, (PCSTR
)pSrcA
, nSrc
, acp
);
824 inline PSTR
StdCodeCvt(PSTR pDstA
, int nDst
, PCWSTR pSrcW
, int nSrc
,
830 WideCharToMultiByte(acp
, 0, pSrcW
, nSrc
, pDstA
, nDst
, 0, 0);
833 inline PUSTR
StdCodeCvt(PUSTR pDstA
, int nDst
, PCWSTR pSrcW
, int nSrc
,
836 return (PUSTR
)StdCodeCvt((PSTR
)pDstA
, nDst
, pSrcW
, nSrc
, acp
);
843 // StdCodeCvt - made to look like Win32 functions WideCharToMultiByte
844 // and MultiByteToWideChar but uses locales in SS_ANSI
845 // builds. There are a number of overloads.
846 // First argument is the destination buffer.
847 // Second argument is the source buffer
848 //#if defined (SS_ANSI) || !defined (SS_WIN32)
850 // 'SSCodeCvt' - shorthand name for the codecvt facet we use
852 typedef std::codecvt
<wchar_t, char, mbstate_t> SSCodeCvt
;
854 inline PWSTR
StdCodeCvt(PWSTR pDstW
, int nDst
, PCSTR pSrcA
, int nSrc
,
855 const std::locale
& loc
=std::locale())
864 PCSTR pNextSrcA
= pSrcA
;
865 PWSTR pNextDstW
= pDstW
;
866 SSCodeCvt::result res
= SSCodeCvt::ok
;
867 const SSCodeCvt
& conv
= SS_USE_FACET(loc
, SSCodeCvt
);
868 SSCodeCvt::state_type st
= { 0 };
870 pSrcA
, pSrcA
+ nSrc
, pNextSrcA
,
871 pDstW
, pDstW
+ nDst
, pNextDstW
);
873 #define ASSERT2(a) if (!(a)) {fprintf(stderr, "StdString: Assertion Failed on line %d\n", __LINE__);}
875 #define ASSERT2 ASSERT
877 ASSERT2(SSCodeCvt::ok
== res
);
878 ASSERT2(SSCodeCvt::error
!= res
);
879 ASSERT2(pNextDstW
>= pDstW
);
880 ASSERT2(pNextSrcA
>= pSrcA
);
882 // Null terminate the converted string
884 if ( pNextDstW
- pDstW
> nDst
)
885 *(pDstW
+ nDst
) = '\0';
891 inline PWSTR
StdCodeCvt(PWSTR pDstW
, int nDst
, PCUSTR pSrcA
, int nSrc
,
892 const std::locale
& loc
=std::locale())
894 return StdCodeCvt(pDstW
, nDst
, (PCSTR
)pSrcA
, nSrc
, loc
);
897 inline PSTR
StdCodeCvt(PSTR pDstA
, int nDst
, PCWSTR pSrcW
, int nSrc
,
898 const std::locale
& loc
=std::locale())
907 PSTR pNextDstA
= pDstA
;
908 PCWSTR pNextSrcW
= pSrcW
;
909 SSCodeCvt::result res
= SSCodeCvt::ok
;
910 const SSCodeCvt
& conv
= SS_USE_FACET(loc
, SSCodeCvt
);
911 SSCodeCvt::state_type st
= { 0 };
913 pSrcW
, pSrcW
+ nSrc
, pNextSrcW
,
914 pDstA
, pDstA
+ nDst
, pNextDstA
);
916 #define ASSERT2(a) if (!(a)) {fprintf(stderr, "StdString: Assertion Failed on line %d\n", __LINE__);}
918 #define ASSERT2 ASSERT
920 ASSERT2(SSCodeCvt::error
!= res
);
921 ASSERT2(SSCodeCvt::ok
== res
); // strict, comment out for sanity
922 ASSERT2(pNextDstA
>= pDstA
);
923 ASSERT2(pNextSrcW
>= pSrcW
);
926 // Null terminate the converted string
928 if ( pNextDstA
- pDstA
> nDst
)
929 *(pDstA
+ nDst
) = '\0';
936 inline PUSTR
StdCodeCvt(PUSTR pDstA
, int nDst
, PCWSTR pSrcW
, int nSrc
,
937 const std::locale
& loc
=std::locale())
939 return (PUSTR
)StdCodeCvt((PSTR
)pDstA
, nDst
, pSrcW
, nSrc
, loc
);
946 // Unicode/MBCS conversion macros are only available on implementations of
947 // the "C" library that have the non-standard _alloca function. As far as I
948 // know that's only Microsoft's though I've heard that the function exists
951 #if defined(SS_ALLOCA) && !defined SS_NO_CONVERSION
953 #include <malloc.h> // needed for _alloca
955 // Define our conversion macros to look exactly like Microsoft's to
956 // facilitate using this stuff both with and without MFC/ATL
958 #ifdef _CONVERSION_USES_THREAD_LOCALE
961 #define SSCVT int _cvt; _cvt; UINT _acp=GetACP(); \
962 _acp; PCWSTR _pw; _pw; PCSTR _pa; _pa
964 #define SSCVT int _cvt = 0; _cvt; UINT _acp=GetACP();\
965 _acp; PCWSTR _pw=0; _pw; PCSTR _pa=0; _pa
968 ((_pa = pa) == 0) ? 0 : (\
969 _cvt = (sslen(_pa)),\
970 StdCodeCvt((PWSTR) _alloca((_cvt+1)*2), (_cvt+1)*2, \
973 ((_pw = pw) == 0) ? 0 : (\
975 StdCodeCvt((LPSTR) _alloca((_cvt+1)*2), (_cvt+1)*2, \
980 #define SSCVT int _cvt; _cvt; UINT _acp=CP_ACP; _acp;\
981 PCWSTR _pw; _pw; PCSTR _pa; _pa
983 #define SSCVT int _cvt = 0; _cvt; UINT _acp=CP_ACP; \
984 _acp; PCWSTR _pw=0; _pw; PCSTR _pa=0; _pa
987 ((_pa = pa) == 0) ? 0 : (\
988 _cvt = (sslen(_pa)),\
989 StdCodeCvt((PWSTR) _alloca((_cvt+1)*2), (_cvt+1)*2, \
992 ((_pw = pw) == 0) ? 0 : (\
993 _cvt = (sslen(_pw)),\
994 StdCodeCvt((LPSTR) _alloca((_cvt+1)*2), (_cvt+1)*2, \
998 #define SSA2CW(pa) ((PCWSTR)SSA2W((pa)))
999 #define SSW2CA(pw) ((PCSTR)SSW2A((pw)))
1004 #define SST2CA SSW2CA
1005 #define SSA2CT SSA2CW
1006 // (Did you get a compiler error here about not being able to convert
1007 // PTSTR into PWSTR? Then your _UNICODE and UNICODE flags are messed
1008 // up. Best bet: #define BOTH macros before including any MS headers.)
1009 inline PWSTR
SST2W(PTSTR p
) { return p
; }
1010 inline PTSTR
SSW2T(PWSTR p
) { return p
; }
1011 inline PCWSTR
SST2CW(PCTSTR p
) { return p
; }
1012 inline PCTSTR
SSW2CT(PCWSTR p
) { return p
; }
1016 #define SST2CW SSA2CW
1017 #define SSW2CT SSW2CA
1018 inline PSTR
SST2A(PTSTR p
) { return p
; }
1019 inline PTSTR
SSA2T(PSTR p
) { return p
; }
1020 inline PCSTR
SST2CA(PCTSTR p
) { return p
; }
1021 inline PCTSTR
SSA2CT(PCSTR p
) { return p
; }
1022 #endif // #ifdef UNICODE
1024 #if defined(UNICODE)
1025 // in these cases the default (TCHAR) is the same as OLECHAR
1026 inline PCOLESTR
SST2COLE(PCTSTR p
) { return p
; }
1027 inline PCTSTR
SSOLE2CT(PCOLESTR p
) { return p
; }
1028 inline POLESTR
SST2OLE(PTSTR p
) { return p
; }
1029 inline PTSTR
SSOLE2T(POLESTR p
) { return p
; }
1030 #elif defined(OLE2ANSI)
1031 // in these cases the default (TCHAR) is the same as OLECHAR
1032 inline PCOLESTR
SST2COLE(PCTSTR p
) { return p
; }
1033 inline PCTSTR
SSOLE2CT(PCOLESTR p
) { return p
; }
1034 inline POLESTR
SST2OLE(PTSTR p
) { return p
; }
1035 inline PTSTR
SSOLE2T(POLESTR p
) { return p
; }
1037 //CharNextW doesn't work on Win95 so we use this
1038 #define SST2COLE(pa) SSA2CW((pa))
1039 #define SST2OLE(pa) SSA2W((pa))
1040 #define SSOLE2CT(po) SSW2CA((po))
1041 #define SSOLE2T(po) SSW2A((po))
1045 #define SSW2OLE SSW2A
1046 #define SSOLE2W SSA2W
1047 #define SSW2COLE SSW2CA
1048 #define SSOLE2CW SSA2CW
1049 inline POLESTR
SSA2OLE(PSTR p
) { return p
; }
1050 inline PSTR
SSOLE2A(POLESTR p
) { return p
; }
1051 inline PCOLESTR
SSA2COLE(PCSTR p
) { return p
; }
1052 inline PCSTR
SSOLE2CA(PCOLESTR p
){ return p
; }
1054 #define SSA2OLE SSA2W
1055 #define SSOLE2A SSW2A
1056 #define SSA2COLE SSA2CW
1057 #define SSOLE2CA SSW2CA
1058 inline POLESTR
SSW2OLE(PWSTR p
) { return p
; }
1059 inline PWSTR
SSOLE2W(POLESTR p
) { return p
; }
1060 inline PCOLESTR
SSW2COLE(PCWSTR p
) { return p
; }
1061 inline PCWSTR
SSOLE2CW(PCOLESTR p
){ return p
; }
1064 // Above we've defined macros that look like MS' but all have
1065 // an 'SS' prefix. Now we need the real macros. We'll either
1066 // get them from the macros above or from MFC/ATL.
1068 #if defined (USES_CONVERSION)
1070 #define _NO_STDCONVERSION // just to be consistent
1076 #include <afxconv.h>
1077 #define _NO_STDCONVERSION // just to be consistent
1081 #define USES_CONVERSION SSCVT
1092 #define ocslen sslen
1093 #define ocscpy sscpy
1094 #define T2COLE SST2COLE
1095 #define OLE2CT SSOLE2CT
1096 #define T2OLE SST2COLE
1097 #define OLE2T SSOLE2CT
1098 #define A2OLE SSA2OLE
1099 #define OLE2A SSOLE2A
1100 #define W2OLE SSW2OLE
1101 #define OLE2W SSOLE2W
1102 #define A2COLE SSA2COLE
1103 #define OLE2CA SSOLE2CA
1104 #define W2COLE SSW2COLE
1105 #define OLE2CW SSOLE2CW
1107 #endif // #ifdef _MFC_VER
1108 #endif // #ifndef USES_CONVERSION
1109 #endif // #ifndef SS_NO_CONVERSION
1111 // Define ostring - generic name for std::basic_string<OLECHAR>
1113 #if !defined(ostring) && !defined(OSTRING_DEFINED)
1114 typedef std::basic_string
<OLECHAR
> ostring
;
1115 #define OSTRING_DEFINED
1118 // StdCodeCvt when there's no conversion to be done
1119 template <typename T
>
1120 inline T
* StdCodeCvt(T
* pDst
, int nDst
, const T
* pSrc
, int nSrc
)
1122 int nChars
= SSMIN(nSrc
, nDst
);
1127 std::basic_string
<T
>::traits_type::copy(pDst
, pSrc
, nChars
);
1128 // std::char_traits<T>::copy(pDst, pSrc, nChars);
1129 pDst
[nChars
] = '\0';
1134 inline PSTR
StdCodeCvt(PSTR pDst
, int nDst
, PCUSTR pSrc
, int nSrc
)
1136 return StdCodeCvt(pDst
, nDst
, (PCSTR
)pSrc
, nSrc
);
1138 inline PUSTR
StdCodeCvt(PUSTR pDst
, int nDst
, PCSTR pSrc
, int nSrc
)
1140 return (PUSTR
)StdCodeCvt((PSTR
)pDst
, nDst
, pSrc
, nSrc
);
1143 // Define tstring -- generic name for std::basic_string<TCHAR>
1145 #if !defined(tstring) && !defined(TSTRING_DEFINED)
1146 typedef std::basic_string
<TCHAR
> tstring
;
1147 #define TSTRING_DEFINED
1150 // a very shorthand way of applying the fix for KB problem Q172398
1151 // (basic_string assignment bug)
1153 #if defined ( _MSC_VER ) && ( _MSC_VER < 1200 )
1154 #define Q172398(x) (x).erase()
1159 // =============================================================================
1160 // INLINE FUNCTIONS ON WHICH CSTDSTRING RELIES
1162 // Usually for generic text mapping, we rely on preprocessor macro definitions
1163 // to map to string functions. However the CStdStr<> template cannot use
1164 // macro-based generic text mappings because its character types do not get
1165 // resolved until template processing which comes AFTER macro processing. In
1166 // other words, the preprocessor macro UNICODE is of little help to us in the
1169 // Therefore, to keep the CStdStr declaration simple, we have these inline
1170 // functions. The template calls them often. Since they are inline (and NOT
1171 // exported when this is built as a DLL), they will probably be resolved away
1174 // Without these functions, the CStdStr<> template would probably have to broken
1175 // out into two, almost identical classes. Either that or it would be a huge,
1176 // convoluted mess, with tons of "if" statements all over the place checking the
1177 // size of template parameter CT.
1178 // =============================================================================
1182 // --------------------------------------------------------------------------
1183 // Win32 GetStringTypeEx wrappers
1184 // --------------------------------------------------------------------------
1185 inline bool wsGetStringType(LCID lc
, DWORD dwT
, PCSTR pS
, int nSize
,
1188 return FALSE
!= GetStringTypeExA(lc
, dwT
, pS
, nSize
, pWd
);
1190 inline bool wsGetStringType(LCID lc
, DWORD dwT
, PCWSTR pS
, int nSize
,
1193 return FALSE
!= GetStringTypeExW(lc
, dwT
, pS
, nSize
, pWd
);
1197 template<typename CT
>
1198 inline bool ssisspace (CT t
)
1201 return wsGetStringType(GetThreadLocale(), CT_CTYPE1
, &t
, 1, &toYourMother
)
1202 && 0 != (C1_BLANK
& toYourMother
);
1207 // If they defined SS_NO_REFCOUNT, then we must convert all assignments
1209 #if defined (_MSC_VER) && (_MSC_VER < 1300)
1210 #ifdef SS_NO_REFCOUNT
1211 #define SSREF(x) (x).c_str()
1213 #define SSREF(x) (x)
1216 #define SSREF(x) (x)
1219 // -----------------------------------------------------------------------------
1220 // sslen: strlen/wcslen wrappers
1221 // -----------------------------------------------------------------------------
1222 template<typename CT
> inline int sslen(const CT
* pT
)
1224 return 0 == pT
? 0 : (int)std::basic_string
<CT
>::traits_type::length(pT
);
1225 // return 0 == pT ? 0 : std::char_traits<CT>::length(pT);
1227 inline SS_NOTHROW
int sslen(const std::string
& s
)
1229 return static_cast<int>(s
.length());
1231 inline SS_NOTHROW
int sslen(const std::wstring
& s
)
1233 return static_cast<int>(s
.length());
1236 // -----------------------------------------------------------------------------
1237 // sstolower/sstoupper -- convert characters to upper/lower case
1238 // -----------------------------------------------------------------------------
1241 inline char sstoupper(char ch
) { return (char)::toupper(ch
); }
1242 inline wchar_t sstoupper(wchar_t ch
){ return (wchar_t)::towupper(ch
); }
1243 inline char sstolower(char ch
) { return (char)::tolower(ch
); }
1244 inline wchar_t sstolower(wchar_t ch
){ return (wchar_t)::tolower(ch
); }
1246 template<typename CT
>
1247 inline CT
sstolower(const CT
& t
, const std::locale
& loc
= std::locale())
1249 return std::tolower
<CT
>(t
, loc
);
1251 template<typename CT
>
1252 inline CT
sstoupper(const CT
& t
, const std::locale
& loc
= std::locale())
1254 return std::toupper
<CT
>(t
, loc
);
1258 // -----------------------------------------------------------------------------
1259 // ssasn: assignment functions -- assign "sSrc" to "sDst"
1260 // -----------------------------------------------------------------------------
1261 typedef std::string::size_type SS_SIZETYPE
; // just for shorthand, really
1262 typedef std::string::pointer SS_PTRTYPE
;
1263 typedef std::wstring::size_type SW_SIZETYPE
;
1264 typedef std::wstring::pointer SW_PTRTYPE
;
1267 template <typename T
>
1268 inline void ssasn(std::basic_string
<T
>& sDst
, const std::basic_string
<T
>& sSrc
)
1270 if ( sDst
.c_str() != sSrc
.c_str() )
1273 sDst
.assign(SSREF(sSrc
));
1276 template <typename T
>
1277 inline void ssasn(std::basic_string
<T
>& sDst
, const T
*pA
)
1279 // Watch out for NULLs, as always.
1286 // If pA actually points to part of sDst, we must NOT erase(), but
1287 // rather take a substring
1289 else if ( pA
>= sDst
.c_str() && pA
<= sDst
.c_str() + sDst
.size() )
1291 sDst
=sDst
.substr(static_cast<typename
std::basic_string
<T
>::size_type
>(pA
-sDst
.c_str()));
1294 // Otherwise (most cases) apply the assignment bug fix, if applicable
1295 // and do the assignment
1303 inline void ssasn(std::string
& sDst
, const std::wstring
& sSrc
)
1311 int nDst
= static_cast<int>(sSrc
.size());
1313 // In MBCS builds, pad the buffer to account for the possibility of
1314 // some 3 byte characters. Not perfect but should get most cases.
1317 // In MBCS builds, we don't know how long the destination string will be.
1318 nDst
= static_cast<int>(static_cast<double>(nDst
) * 1.3);
1319 sDst
.resize(nDst
+1);
1320 PCSTR szCvt
= StdCodeCvt(const_cast<SS_PTRTYPE
>(sDst
.data()), nDst
,
1321 sSrc
.c_str(), static_cast<int>(sSrc
.size()));
1322 sDst
.resize(sslen(szCvt
));
1324 sDst
.resize(nDst
+1);
1325 StdCodeCvt(const_cast<SS_PTRTYPE
>(sDst
.data()), nDst
,
1326 sSrc
.c_str(), static_cast<int>(sSrc
.size()));
1327 sDst
.resize(sSrc
.size());
1331 inline void ssasn(std::string
& sDst
, PCWSTR pW
)
1333 int nSrc
= sslen(pW
);
1336 int nSrc
= sslen(pW
);
1339 // In MBCS builds, pad the buffer to account for the possibility of
1340 // some 3 byte characters. Not perfect but should get most cases.
1343 nDst
= static_cast<int>(static_cast<double>(nDst
) * 1.3);
1344 // In MBCS builds, we don't know how long the destination string will be.
1345 sDst
.resize(nDst
+ 1);
1346 PCSTR szCvt
= StdCodeCvt(const_cast<SS_PTRTYPE
>(sDst
.data()), nDst
,
1348 sDst
.resize(sslen(szCvt
));
1350 sDst
.resize(nDst
+ 1);
1351 StdCodeCvt(const_cast<SS_PTRTYPE
>(sDst
.data()), nDst
, pW
, nSrc
);
1360 inline void ssasn(std::string
& sDst
, const int nNull
)
1367 inline void ssasn(std::wstring
& sDst
, const std::string
& sSrc
)
1375 int nSrc
= static_cast<int>(sSrc
.size());
1378 sDst
.resize(nSrc
+1);
1379 PCWSTR szCvt
= StdCodeCvt(const_cast<SW_PTRTYPE
>(sDst
.data()), nDst
,
1380 sSrc
.c_str(), nSrc
);
1382 sDst
.resize(sslen(szCvt
));
1385 inline void ssasn(std::wstring
& sDst
, PCSTR pA
)
1387 int nSrc
= sslen(pA
);
1396 sDst
.resize(nDst
+1);
1397 PCWSTR szCvt
= StdCodeCvt(const_cast<SW_PTRTYPE
>(sDst
.data()), nDst
, pA
,
1400 sDst
.resize(sslen(szCvt
));
1403 inline void ssasn(std::wstring
& sDst
, const int nNull
)
1410 // -----------------------------------------------------------------------------
1411 // ssadd: string object concatenation -- add second argument to first
1412 // -----------------------------------------------------------------------------
1413 inline void ssadd(std::string
& sDst
, const std::wstring
& sSrc
)
1415 int nSrc
= static_cast<int>(sSrc
.size());
1419 int nDst
= static_cast<int>(sDst
.size());
1422 // In MBCS builds, pad the buffer to account for the possibility of
1423 // some 3 byte characters. Not perfect but should get most cases.
1426 nAdd
= static_cast<int>(static_cast<double>(nAdd
) * 1.3);
1427 sDst
.resize(nDst
+nAdd
+1);
1428 PCSTR szCvt
= StdCodeCvt(const_cast<SS_PTRTYPE
>(sDst
.data()+nDst
),
1429 nAdd
, sSrc
.c_str(), nSrc
);
1430 sDst
.resize(nDst
+ sslen(szCvt
));
1432 sDst
.resize(nDst
+nAdd
+1);
1433 StdCodeCvt(const_cast<SS_PTRTYPE
>(sDst
.data()+nDst
), nAdd
, sSrc
.c_str(), nSrc
);
1434 sDst
.resize(nDst
+ nAdd
);
1438 template <typename T
>
1439 inline void ssadd(typename
std::basic_string
<T
>& sDst
, const typename
std::basic_string
<T
>& sSrc
)
1443 inline void ssadd(std::string
& sDst
, PCWSTR pW
)
1445 int nSrc
= sslen(pW
);
1448 int nDst
= static_cast<int>(sDst
.size());
1452 nAdd
= static_cast<int>(static_cast<double>(nAdd
) * 1.3);
1453 sDst
.resize(nDst
+ nAdd
+ 1);
1454 PCSTR szCvt
= StdCodeCvt(const_cast<SS_PTRTYPE
>(sDst
.data()+nDst
),
1456 sDst
.resize(nDst
+ sslen(szCvt
));
1458 sDst
.resize(nDst
+ nAdd
+ 1);
1459 StdCodeCvt(const_cast<SS_PTRTYPE
>(sDst
.data()+nDst
), nAdd
, pW
, nSrc
);
1460 sDst
.resize(nDst
+ nSrc
);
1464 template <typename T
>
1465 inline void ssadd(typename
std::basic_string
<T
>& sDst
, const T
*pA
)
1469 // If the string being added is our internal string or a part of our
1470 // internal string, then we must NOT do any reallocation without
1471 // first copying that string to another object (since we're using a
1474 if ( pA
>= sDst
.c_str() && pA
<= sDst
.c_str()+sDst
.length())
1476 if ( sDst
.capacity() <= sDst
.size()+sslen(pA
) )
1477 sDst
.append(std::basic_string
<T
>(pA
));
1487 inline void ssadd(std::wstring
& sDst
, const std::string
& sSrc
)
1489 if ( !sSrc
.empty() )
1491 int nSrc
= static_cast<int>(sSrc
.size());
1492 int nDst
= static_cast<int>(sDst
.size());
1494 sDst
.resize(nDst
+ nSrc
+ 1);
1496 PCWSTR szCvt
= StdCodeCvt(const_cast<SW_PTRTYPE
>(sDst
.data()+nDst
),
1497 nSrc
, sSrc
.c_str(), nSrc
+1);
1498 sDst
.resize(nDst
+ sslen(szCvt
));
1500 StdCodeCvt(const_cast<SW_PTRTYPE
>(sDst
.data()+nDst
), nSrc
, sSrc
.c_str(), nSrc
+1);
1501 sDst
.resize(nDst
+ nSrc
);
1505 inline void ssadd(std::wstring
& sDst
, PCSTR pA
)
1507 int nSrc
= sslen(pA
);
1511 int nDst
= static_cast<int>(sDst
.size());
1513 sDst
.resize(nDst
+ nSrc
+ 1);
1515 PCWSTR szCvt
= StdCodeCvt(const_cast<SW_PTRTYPE
>(sDst
.data()+nDst
),
1517 sDst
.resize(nDst
+ sslen(szCvt
));
1519 StdCodeCvt(const_cast<SW_PTRTYPE
>(sDst
.data()+nDst
), nSrc
, pA
, nSrc
+1);
1520 sDst
.resize(nDst
+ nSrc
);
1525 // -----------------------------------------------------------------------------
1526 // sscmp: comparison (case sensitive, not affected by locale)
1527 // -----------------------------------------------------------------------------
1528 template<typename CT
>
1529 inline int sscmp(const CT
* pA1
, const CT
* pA2
)
1538 } while ( (f
) && (f
== l
) );
1540 return (int)(f
- l
);
1543 // -----------------------------------------------------------------------------
1544 // ssicmp: comparison (case INsensitive, not affected by locale)
1545 // -----------------------------------------------------------------------------
1546 template<typename CT
>
1547 inline int ssicmp(const CT
* pA1
, const CT
* pA2
)
1549 // Using the "C" locale = "not affected by locale"
1551 std::locale loc
= std::locale::classic();
1552 const std::ctype
<CT
>& ct
= SS_USE_FACET(loc
, std::ctype
<CT
>);
1558 f
= ct
.tolower(*(pA1
++));
1559 l
= ct
.tolower(*(pA2
++));
1560 } while ( (f
) && (f
== l
) );
1562 return (int)(f
- l
);
1565 // -----------------------------------------------------------------------------
1566 // ssupr/sslwr: Uppercase/Lowercase conversion functions
1567 // -----------------------------------------------------------------------------
1569 template<typename CT
>
1570 inline void sslwr(CT
* pT
, size_t nLen
, const std::locale
& loc
=std::locale())
1572 SS_USE_FACET(loc
, std::ctype
<CT
>).tolower(pT
, pT
+nLen
);
1574 template<typename CT
>
1575 inline void ssupr(CT
* pT
, size_t nLen
, const std::locale
& loc
=std::locale())
1577 SS_USE_FACET(loc
, std::ctype
<CT
>).toupper(pT
, pT
+nLen
);
1580 // -----------------------------------------------------------------------------
1581 // vsprintf/vswprintf or _vsnprintf/_vsnwprintf equivalents. In standard
1582 // builds we can't use _vsnprintf/_vsnwsprintf because they're MS extensions.
1584 // -----------------------------------------------------------------------------
1585 // Borland's headers put some ANSI "C" functions in the 'std' namespace.
1586 // Promote them to the global namespace so we can use them here.
1588 #if defined(__BORLANDC__)
1589 using std::vsprintf
;
1590 using std::vswprintf
;
1593 // GNU is supposed to have vsnprintf and vsnwprintf. But only the newer
1594 // distributions do.
1596 #if defined(__GNUC__)
1598 inline int ssvsprintf(PSTR pA
, size_t nCount
, PCSTR pFmtA
, va_list vl
)
1600 return vsnprintf(pA
, nCount
, pFmtA
, vl
);
1602 inline int ssvsprintf(PWSTR pW
, size_t nCount
, PCWSTR pFmtW
, va_list vl
)
1604 return vswprintf(pW
, nCount
, pFmtW
, vl
);
1607 // Microsofties can use
1608 #elif defined(_MSC_VER) && !defined(SS_ANSI)
1610 inline int ssvsprintf(PSTR pA
, size_t nCount
, PCSTR pFmtA
, va_list vl
)
1612 return _vsnprintf(pA
, nCount
, pFmtA
, vl
);
1614 inline int ssvsprintf(PWSTR pW
, size_t nCount
, PCWSTR pFmtW
, va_list vl
)
1616 return _vsnwprintf(pW
, nCount
, pFmtW
, vl
);
1619 #elif defined (SS_DANGEROUS_FORMAT) // ignore buffer size parameter if needed?
1621 inline int ssvsprintf(PSTR pA
, size_t /*nCount*/, PCSTR pFmtA
, va_list vl
)
1623 return vsprintf(pA
, pFmtA
, vl
);
1626 inline int ssvsprintf(PWSTR pW
, size_t nCount
, PCWSTR pFmtW
, va_list vl
)
1628 // JMO: Some distributions of the "C" have a version of vswprintf that
1629 // takes 3 arguments (e.g. Microsoft, Borland, GNU). Others have a
1630 // version which takes 4 arguments (an extra "count" argument in the
1631 // second position. The best stab I can take at this so far is that if
1632 // you are NOT running with MS, Borland, or GNU, then I'll assume you
1633 // have the version that takes 4 arguments.
1635 // I'm sure that these checks don't catch every platform correctly so if
1636 // you get compiler errors on one of the lines immediately below, it's
1637 // probably because your implemntation takes a different number of
1638 // arguments. You can comment out the offending line (and use the
1639 // alternate version) or you can figure out what compiler flag to check
1640 // and add that preprocessor check in. Regardless, if you get an error
1641 // on these lines, I'd sure like to hear from you about it.
1643 // Thanks to Ronny Schulz for the SGI-specific checks here.
1645 // #if !defined(__MWERKS__) && !defined(__SUNPRO_CC_COMPAT) && !defined(__SUNPRO_CC)
1646 #if !defined(_MSC_VER) \
1647 && !defined (__BORLANDC__) \
1648 && !defined(__GNUC__) \
1651 return vswprintf(pW
, nCount
, pFmtW
, vl
);
1653 // suddenly with the current SGI 7.3 compiler there is no such function as
1654 // vswprintf and the substitute needs explicit casts to compile
1656 #elif defined(__sgi)
1659 return vsprintf( (char *)pW
, (char *)pFmtW
, vl
);
1664 return vswprintf(pW
, pFmtW
, vl
);
1672 // GOT COMPILER PROBLEMS HERE?
1673 // ---------------------------
1674 // Does your compiler choke on one or more of the following 2 functions? It
1675 // probably means that you don't have have either vsnprintf or vsnwprintf in
1676 // your version of the CRT. This is understandable since neither is an ANSI
1677 // "C" function. However it still leaves you in a dilemma. In order to make
1678 // this code build, you're going to have to to use some non-length-checked
1679 // formatting functions that every CRT has: vsprintf and vswprintf.
1681 // This is very dangerous. With the proper erroneous (or malicious) code, it
1682 // can lead to buffer overlows and crashing your PC. Use at your own risk
1683 // In order to use them, just #define SS_DANGEROUS_FORMAT at the top of
1686 // Even THEN you might not be all the way home due to some non-conforming
1687 // distributions. More on this in the comments below.
1689 inline int ssnprintf(PSTR pA
, size_t nCount
, PCSTR pFmtA
, va_list vl
)
1692 return _vsnprintf(pA
, nCount
, pFmtA
, vl
);
1694 return vsnprintf(pA
, nCount
, pFmtA
, vl
);
1697 inline int ssnprintf(PWSTR pW
, size_t nCount
, PCWSTR pFmtW
, va_list vl
)
1700 return _vsnwprintf(pW
, nCount
, pFmtW
, vl
);
1702 return vswprintf(pW
, nCount
, pFmtW
, vl
);
1709 // -----------------------------------------------------------------------------
1710 // ssload: Type safe, overloaded ::LoadString wrappers
1711 // There is no equivalent of these in non-Win32-specific builds. However, I'm
1712 // thinking that with the message facet, there might eventually be one
1713 // -----------------------------------------------------------------------------
1714 #if defined (SS_WIN32) && !defined(SS_ANSI)
1715 inline int ssload(HMODULE hInst
, UINT uId
, PSTR pBuf
, int nMax
)
1717 return ::LoadStringA(hInst
, uId
, pBuf
, nMax
);
1719 inline int ssload(HMODULE hInst
, UINT uId
, PWSTR pBuf
, int nMax
)
1721 return ::LoadStringW(hInst
, uId
, pBuf
, nMax
);
1723 #if defined ( _MSC_VER ) && ( _MSC_VER >= 1500 )
1724 inline int ssload(HMODULE hInst
, UINT uId
, uint16_t *pBuf
, int nMax
)
1728 inline int ssload(HMODULE hInst
, UINT uId
, uint32_t *pBuf
, int nMax
)
1736 // -----------------------------------------------------------------------------
1737 // sscoll/ssicoll: Collation wrappers
1738 // Note -- with MSVC I have reversed the arguments order here because the
1739 // functions appear to return the opposite of what they should
1740 // -----------------------------------------------------------------------------
1741 #ifndef SS_NO_LOCALE
1742 template <typename CT
>
1743 inline int sscoll(const CT
* sz1
, int nLen1
, const CT
* sz2
, int nLen2
)
1745 const std::collate
<CT
>& coll
=
1746 SS_USE_FACET(std::locale(), std::collate
<CT
>);
1748 return coll
.compare(sz2
, sz2
+nLen2
, sz1
, sz1
+nLen1
);
1750 template <typename CT
>
1751 inline int ssicoll(const CT
* sz1
, int nLen1
, const CT
* sz2
, int nLen2
)
1753 const std::locale loc
;
1754 const std::collate
<CT
>& coll
= SS_USE_FACET(loc
, std::collate
<CT
>);
1756 // Some implementations seem to have trouble using the collate<>
1757 // facet typedefs so we'll just default to basic_string and hope
1758 // that's what the collate facet uses (which it generally should)
1760 // std::collate<CT>::string_type s1(sz1);
1761 // std::collate<CT>::string_type s2(sz2);
1762 const std::basic_string
<CT
> sEmpty
;
1763 std::basic_string
<CT
> s1(sz1
? sz1
: sEmpty
.c_str());
1764 std::basic_string
<CT
> s2(sz2
? sz2
: sEmpty
.c_str());
1766 sslwr(const_cast<CT
*>(s1
.c_str()), nLen1
, loc
);
1767 sslwr(const_cast<CT
*>(s2
.c_str()), nLen2
, loc
);
1768 return coll
.compare(s2
.c_str(), s2
.c_str()+nLen2
,
1769 s1
.c_str(), s1
.c_str()+nLen1
);
1774 // -----------------------------------------------------------------------------
1775 // ssfmtmsg: FormatMessage equivalents. Needed because I added a CString facade
1776 // Again -- no equivalent of these on non-Win32 builds but their might one day
1777 // be one if the message facet gets implemented
1778 // -----------------------------------------------------------------------------
1779 #if defined (SS_WIN32) && !defined(SS_ANSI)
1780 inline DWORD
ssfmtmsg(DWORD dwFlags
, LPCVOID pSrc
, DWORD dwMsgId
,
1781 DWORD dwLangId
, PSTR pBuf
, DWORD nSize
,
1784 return FormatMessageA(dwFlags
, pSrc
, dwMsgId
, dwLangId
,
1785 pBuf
, nSize
,vlArgs
);
1787 inline DWORD
ssfmtmsg(DWORD dwFlags
, LPCVOID pSrc
, DWORD dwMsgId
,
1788 DWORD dwLangId
, PWSTR pBuf
, DWORD nSize
,
1791 return FormatMessageW(dwFlags
, pSrc
, dwMsgId
, dwLangId
,
1792 pBuf
, nSize
,vlArgs
);
1799 // FUNCTION: sscpy. Copies up to 'nMax' characters from pSrc to pDst.
1800 // -----------------------------------------------------------------------------
1802 // inline int sscpy(PSTR pDst, PCSTR pSrc, int nMax=-1);
1803 // inline int sscpy(PUSTR pDst, PCSTR pSrc, int nMax=-1)
1804 // inline int sscpy(PSTR pDst, PCWSTR pSrc, int nMax=-1);
1805 // inline int sscpy(PWSTR pDst, PCWSTR pSrc, int nMax=-1);
1806 // inline int sscpy(PWSTR pDst, PCSTR pSrc, int nMax=-1);
1809 // This function is very much (but not exactly) like strcpy. These
1810 // overloads simplify copying one C-style string into another by allowing
1811 // the caller to specify two different types of strings if necessary.
1813 // The strings must NOT overlap
1815 // "Character" is expressed in terms of the destination string, not
1816 // the source. If no 'nMax' argument is supplied, then the number of
1817 // characters copied will be sslen(pSrc). A NULL terminator will
1818 // also be added so pDst must actually be big enough to hold nMax+1
1819 // characters. The return value is the number of characters copied,
1820 // not including the NULL terminator.
1823 // pSrc - the string to be copied FROM. May be a char based string, an
1824 // MBCS string (in Win32 builds) or a wide string (wchar_t).
1825 // pSrc - the string to be copied TO. Also may be either MBCS or wide
1826 // nMax - the maximum number of characters to be copied into szDest. Note
1827 // that this is expressed in whatever a "character" means to pDst.
1828 // If pDst is a wchar_t type string than this will be the maximum
1829 // number of wchar_ts that my be copied. The pDst string must be
1830 // large enough to hold least nMaxChars+1 characters.
1831 // If the caller supplies no argument for nMax this is a signal to
1832 // the routine to copy all the characters in pSrc, regardless of
1835 // RETURN VALUE: none
1836 // -----------------------------------------------------------------------------
1838 template<typename CT1
, typename CT2
>
1839 inline int sscpycvt(CT1
* pDst
, const CT2
* pSrc
, int nMax
)
1841 // Note -- we assume pDst is big enough to hold pSrc. If not, we're in
1842 // big trouble. No bounds checking. Caveat emptor.
1844 int nSrc
= sslen(pSrc
);
1846 const CT1
* szCvt
= StdCodeCvt(pDst
, nMax
, pSrc
, nSrc
);
1848 // If we're copying the same size characters, then all the "code convert"
1849 // just did was basically memcpy so the #of characters copied is the same
1850 // as the number requested. I should probably specialize this function
1851 // template to achieve this purpose as it is silly to do a runtime check
1852 // of a fact known at compile time. I'll get around to it.
1854 return sslen(szCvt
);
1857 template<typename T
>
1858 inline int sscpycvt(T
* pDst
, const T
* pSrc
, int nMax
)
1861 for (; nCount
> 0 && *pSrc
; ++pSrc
, ++pDst
, --nCount
)
1862 std::basic_string
<T
>::traits_type::assign(*pDst
, *pSrc
);
1865 return nMax
- nCount
;
1868 inline int sscpycvt(PWSTR pDst
, PCSTR pSrc
, int nMax
)
1870 // Note -- we assume pDst is big enough to hold pSrc. If not, we're in
1871 // big trouble. No bounds checking. Caveat emptor.
1873 const PWSTR szCvt
= StdCodeCvt(pDst
, nMax
, pSrc
, nMax
);
1874 return sslen(szCvt
);
1877 template<typename CT1
, typename CT2
>
1878 inline int sscpy(CT1
* pDst
, const CT2
* pSrc
, int nMax
, int nLen
)
1880 return sscpycvt(pDst
, pSrc
, SSMIN(nMax
, nLen
));
1882 template<typename CT1
, typename CT2
>
1883 inline int sscpy(CT1
* pDst
, const CT2
* pSrc
, int nMax
)
1885 return sscpycvt(pDst
, pSrc
, SSMIN(nMax
, sslen(pSrc
)));
1887 template<typename CT1
, typename CT2
>
1888 inline int sscpy(CT1
* pDst
, const CT2
* pSrc
)
1890 return sscpycvt(pDst
, pSrc
, sslen(pSrc
));
1892 template<typename CT1
, typename CT2
>
1893 inline int sscpy(CT1
* pDst
, const std::basic_string
<CT2
>& sSrc
, int nMax
)
1895 return sscpycvt(pDst
, sSrc
.c_str(), SSMIN(nMax
, (int)sSrc
.length()));
1897 template<typename CT1
, typename CT2
>
1898 inline int sscpy(CT1
* pDst
, const std::basic_string
<CT2
>& sSrc
)
1900 return sscpycvt(pDst
, sSrc
.c_str(), (int)sSrc
.length());
1903 #ifdef SS_INC_COMDEF
1904 template<typename CT1
>
1905 inline int sscpy(CT1
* pDst
, const _bstr_t
& bs
, int nMax
)
1907 return sscpycvt(pDst
, static_cast<PCOLESTR
>(bs
),
1908 SSMIN(nMax
, static_cast<int>(bs
.length())));
1910 template<typename CT1
>
1911 inline int sscpy(CT1
* pDst
, const _bstr_t
& bs
)
1913 return sscpy(pDst
, bs
, static_cast<int>(bs
.length()));
1918 // -----------------------------------------------------------------------------
1919 // Functional objects for changing case. They also let you pass locales
1920 // -----------------------------------------------------------------------------
1923 template<typename CT
>
1924 struct SSToUpper
: public std::unary_function
<CT
, CT
>
1926 inline CT
operator()(const CT
& t
) const
1928 return sstoupper(t
);
1931 template<typename CT
>
1932 struct SSToLower
: public std::unary_function
<CT
, CT
>
1934 inline CT
operator()(const CT
& t
) const
1936 return sstolower(t
);
1940 template<typename CT
>
1941 struct SSToUpper
: public std::binary_function
<CT
, std::locale
, CT
>
1943 inline CT
operator()(const CT
& t
, const std::locale
& loc
) const
1945 return sstoupper
<CT
>(t
, loc
);
1948 template<typename CT
>
1949 struct SSToLower
: public std::binary_function
<CT
, std::locale
, CT
>
1951 inline CT
operator()(const CT
& t
, const std::locale
& loc
) const
1953 return sstolower
<CT
>(t
, loc
);
1958 // This struct is used for TrimRight() and TrimLeft() function implementations.
1959 //template<typename CT>
1960 //struct NotSpace : public std::unary_function<CT, bool>
1962 // const std::locale& loc;
1963 // inline NotSpace(const std::locale& locArg) : loc(locArg) {}
1964 // inline bool operator() (CT t) { return !std::isspace(t, loc); }
1966 template<typename CT
>
1967 struct NotSpace
: public std::unary_function
<CT
, bool>
1970 // Note -- using std::isspace in a COM DLL gives us access violations
1971 // because it causes the dynamic addition of a function to be called
1972 // when the library shuts down. Unfortunately the list is maintained
1973 // in DLL memory but the function is in static memory. So the COM DLL
1974 // goes away along with the function that was supposed to be called,
1975 // and then later when the DLL CRT shuts down it unloads the list and
1976 // tries to call the long-gone function.
1977 // This is DinkumWare's implementation problem. If you encounter this
1978 // problem, you may replace the calls here with good old isspace() and
1979 // iswspace() from the CRT unless they specify SS_ANSI
1983 bool operator() (CT t
) const { return !ssisspace(t
); }
1986 const std::locale loc
;
1987 NotSpace(const std::locale
& locArg
=std::locale()) : loc(locArg
) {}
1988 bool operator() (CT t
) const { return !std::isspace(t
, loc
); }
1995 // Now we can define the template (finally!)
1996 // =============================================================================
1997 // TEMPLATE: CStdStr
1998 // template<typename CT> class CStdStr : public std::basic_string<CT>
2001 // This template derives from basic_string<CT> and adds some MFC CString-
2002 // like functionality
2004 // Basically, this is my attempt to make Standard C++ library strings as
2005 // easy to use as the MFC CString class.
2007 // Note that although this is a template, it makes the assumption that the
2008 // template argument (CT, the character type) is either char or wchar_t.
2009 // =============================================================================
2011 //#define CStdStr _SS // avoid compiler warning 4786
2013 // template<typename ARG> ARG& FmtArg(ARG& arg) { return arg; }
2014 // PCSTR FmtArg(const std::string& arg) { return arg.c_str(); }
2015 // PCWSTR FmtArg(const std::wstring& arg) { return arg.c_str(); }
2017 template<typename ARG
>
2020 explicit FmtArg(const ARG
& arg
) : a_(arg
) {}
2021 const ARG
& operator()() const { return a_
; }
2024 FmtArg
& operator=(const FmtArg
&) { return *this; }
2027 template<typename CT
>
2028 class CStdStr
: public std::basic_string
<CT
>
2030 // Typedefs for shorter names. Using these names also appears to help
2031 // us avoid some ambiguities that otherwise arise on some platforms
2033 #define MYBASE std::basic_string<CT> // my base class
2034 //typedef typename std::basic_string<CT> MYBASE; // my base class
2035 typedef CStdStr
<CT
> MYTYPE
; // myself
2036 typedef typename
MYBASE::const_pointer PCMYSTR
; // PCSTR or PCWSTR
2037 typedef typename
MYBASE::pointer PMYSTR
; // PSTR or PWSTR
2038 typedef typename
MYBASE::iterator MYITER
; // my iterator type
2039 typedef typename
MYBASE::const_iterator MYCITER
; // you get the idea...
2040 typedef typename
MYBASE::reverse_iterator MYRITER
;
2041 typedef typename
MYBASE::size_type MYSIZE
;
2042 typedef typename
MYBASE::value_type MYVAL
;
2043 typedef typename
MYBASE::allocator_type MYALLOC
;
2046 // shorthand conversion from PCTSTR to string resource ID
2047 #define SSRES(pctstr) LOWORD(reinterpret_cast<unsigned long>(pctstr))
2049 bool TryLoad(const void* pT
)
2051 bool bLoaded
= false;
2053 #if defined(SS_WIN32) && !defined(SS_ANSI)
2054 if ( ( pT
!= NULL
) && SS_IS_INTRESOURCE(pT
) )
2056 UINT nId
= LOWORD(reinterpret_cast<unsigned long>(pT
));
2057 if ( !LoadString(nId
) )
2059 TRACE(_T("Can't load string %u\n"), SSRES(pT
));
2069 // CStdStr inline constructors
2074 CStdStr(const MYTYPE
& str
) : MYBASE(SSREF(str
))
2078 CStdStr(const std::string
& str
)
2080 ssasn(*this, SSREF(str
));
2083 CStdStr(const std::wstring
& str
)
2085 ssasn(*this, SSREF(str
));
2088 CStdStr(PCMYSTR pT
, MYSIZE n
) : MYBASE(pT
, n
)
2095 *this = reinterpret_cast<PCSTR
>(pU
);
2119 CStdStr(uint16_t* pW
)
2129 CStdStr(uint32_t* pW
)
2139 CStdStr(MYCITER first
, MYCITER last
)
2140 : MYBASE(first
, last
)
2144 CStdStr(MYSIZE nSize
, MYVAL ch
, const MYALLOC
& al
=MYALLOC())
2145 : MYBASE(nSize
, ch
, al
)
2149 #ifdef SS_INC_COMDEF
2150 CStdStr(const _bstr_t
& bstr
)
2152 if ( bstr
.length() > 0 )
2153 this->append(static_cast<PCMYSTR
>(bstr
), bstr
.length());
2157 // CStdStr inline assignment operators -- the ssasn function now takes care
2158 // of fixing the MSVC assignment bug (see knowledge base article Q172398).
2159 MYTYPE
& operator=(const MYTYPE
& str
)
2165 MYTYPE
& operator=(const std::string
& str
)
2171 MYTYPE
& operator=(const std::wstring
& str
)
2177 MYTYPE
& operator=(PCSTR pA
)
2183 MYTYPE
& operator=(PCWSTR pW
)
2190 MYTYPE
& operator=(PCUSTR pU
)
2192 ssasn(*this, reinterpret_cast<PCSTR
>(pU
));
2197 MYTYPE
& operator=(uint16_t* pA
)
2203 MYTYPE
& operator=(uint32_t* pA
)
2209 MYTYPE
& operator=(CT t
)
2216 #ifdef SS_INC_COMDEF
2217 MYTYPE
& operator=(const _bstr_t
& bstr
)
2219 if ( bstr
.length() > 0 )
2221 this->assign(static_cast<PCMYSTR
>(bstr
), bstr
.length());
2233 // Overloads also needed to fix the MSVC assignment bug (KB: Q172398)
2234 // *** Thanks to Pete The Plumber for catching this one ***
2235 // They also are compiled if you have explicitly turned off refcounting
2236 #if ( defined(_MSC_VER) && ( _MSC_VER < 1200 ) ) || defined(SS_NO_REFCOUNT)
2238 MYTYPE
& assign(const MYTYPE
& str
)
2241 sscpy(GetBuffer(str
.size()+1), SSREF(str
));
2242 this->ReleaseBuffer(str
.size());
2246 MYTYPE
& assign(const MYTYPE
& str
, MYSIZE nStart
, MYSIZE nChars
)
2248 // This overload of basic_string::assign is supposed to assign up to
2249 // <nChars> or the NULL terminator, whichever comes first. Since we
2250 // are about to call a less forgiving overload (in which <nChars>
2251 // must be a valid length), we must adjust the length here to a safe
2252 // value. Thanks to Ullrich Poll�hne for catching this bug
2254 nChars
= SSMIN(nChars
, str
.length() - nStart
);
2255 MYTYPE
strTemp(str
.c_str()+nStart
, nChars
);
2257 this->assign(strTemp
);
2261 MYTYPE
& assign(const MYBASE
& str
)
2267 MYTYPE
& assign(const MYBASE
& str
, MYSIZE nStart
, MYSIZE nChars
)
2269 // This overload of basic_string::assign is supposed to assign up to
2270 // <nChars> or the NULL terminator, whichever comes first. Since we
2271 // are about to call a less forgiving overload (in which <nChars>
2272 // must be a valid length), we must adjust the length here to a safe
2273 // value. Thanks to Ullrich Poll�hne for catching this bug
2275 nChars
= SSMIN(nChars
, str
.length() - nStart
);
2277 // Watch out for assignment to self
2281 MYTYPE
strTemp(str
.c_str() + nStart
, nChars
);
2282 static_cast<MYBASE
*>(this)->assign(strTemp
);
2287 static_cast<MYBASE
*>(this)->assign(str
.c_str()+nStart
, nChars
);
2292 MYTYPE
& assign(const CT
* pC
, MYSIZE nChars
)
2294 // Q172398 only fix -- erase before assigning, but not if we're
2295 // assigning from our own buffer
2297 #if defined ( _MSC_VER ) && ( _MSC_VER < 1200 )
2298 if ( !this->empty() &&
2299 ( pC
< this->data() || pC
> this->data() + this->capacity() ) )
2305 static_cast<MYBASE
*>(this)->assign(pC
, nChars
);
2309 MYTYPE
& assign(MYSIZE nChars
, MYVAL val
)
2312 static_cast<MYBASE
*>(this)->assign(nChars
, val
);
2316 MYTYPE
& assign(const CT
* pT
)
2318 return this->assign(pT
, MYBASE::traits_type::length(pT
));
2321 MYTYPE
& assign(MYCITER iterFirst
, MYCITER iterLast
)
2323 #if defined ( _MSC_VER ) && ( _MSC_VER < 1200 )
2324 // Q172398 fix. don't call erase() if we're assigning from ourself
2325 if ( iterFirst
< this->begin() ||
2326 iterFirst
> this->begin() + this->size() )
2331 this->replace(this->begin(), this->end(), iterFirst
, iterLast
);
2337 // -------------------------------------------------------------------------
2338 // CStdStr inline concatenation.
2339 // -------------------------------------------------------------------------
2340 MYTYPE
& operator+=(const MYTYPE
& str
)
2346 MYTYPE
& operator+=(const std::string
& str
)
2352 MYTYPE
& operator+=(const std::wstring
& str
)
2358 MYTYPE
& operator+=(PCSTR pA
)
2364 MYTYPE
& operator+=(PCWSTR pW
)
2370 MYTYPE
& operator+=(uint16_t* pW
)
2376 MYTYPE
& operator+=(uint32_t* pW
)
2382 MYTYPE
& operator+=(CT t
)
2387 #ifdef SS_INC_COMDEF // if we have _bstr_t, define a += for it too.
2388 MYTYPE
& operator+=(const _bstr_t
& bstr
)
2390 return this->operator+=(static_cast<PCMYSTR
>(bstr
));
2395 // -------------------------------------------------------------------------
2396 // Case changing functions
2397 // -------------------------------------------------------------------------
2399 MYTYPE
& ToUpper(const std::locale
& loc
=std::locale())
2401 // Note -- if there are any MBCS character sets in which the lowercase
2402 // form a character takes up a different number of bytes than the
2403 // uppercase form, this would probably not work...
2405 std::transform(this->begin(),
2411 std::bind2nd(SSToUpper
<CT
>(), loc
));
2414 // ...but if it were, this would probably work better. Also, this way
2415 // seems to be a bit faster when anything other then the "C" locale is
2420 // ssupr(this->GetBuf(), this->size(), loc);
2427 MYTYPE
& ToLower(const std::locale
& loc
=std::locale())
2429 // Note -- if there are any MBCS character sets in which the lowercase
2430 // form a character takes up a different number of bytes than the
2431 // uppercase form, this would probably not work...
2433 std::transform(this->begin(),
2439 std::bind2nd(SSToLower
<CT
>(), loc
));
2442 // ...but if it were, this would probably work better. Also, this way
2443 // seems to be a bit faster when anything other then the "C" locale is
2448 // sslwr(this->GetBuf(), this->size(), loc);
2457 return Trim().ToLower();
2461 // -------------------------------------------------------------------------
2462 // CStdStr -- Direct access to character buffer. In the MS' implementation,
2463 // the at() function that we use here also calls _Freeze() providing us some
2464 // protection from multithreading problems associated with ref-counting.
2465 // In VC 7 and later, of course, the ref-counting stuff is gone.
2466 // -------------------------------------------------------------------------
2468 CT
* GetBuf(int nMinLen
=-1)
2470 if ( static_cast<int>(this->size()) < nMinLen
)
2471 this->resize(static_cast<MYSIZE
>(nMinLen
));
2473 return this->empty() ? const_cast<CT
*>(this->data()) : &(this->at(0));
2476 CT
* SetBuf(int nLen
)
2478 nLen
= ( nLen
> 0 ? nLen
: 0 );
2479 if ( this->capacity() < 1 && nLen
== 0 )
2482 this->resize(static_cast<MYSIZE
>(nLen
));
2483 return const_cast<CT
*>(this->data());
2485 void RelBuf(int nNewLen
=-1)
2487 this->resize(static_cast<MYSIZE
>(nNewLen
> -1 ? nNewLen
:
2488 sslen(this->c_str())));
2491 void BufferRel() { RelBuf(); } // backwards compatability
2492 CT
* Buffer() { return GetBuf(); } // backwards compatability
2493 CT
* BufferSet(int nLen
) { return SetBuf(nLen
);}// backwards compatability
2495 bool Equals(const CT
* pT
, bool bUseCase
=false) const
2497 return 0 == (bUseCase
? this->compare(pT
) : ssicmp(this->c_str(), pT
));
2500 // -------------------------------------------------------------------------
2501 // FUNCTION: CStdStr::Load
2503 // Loads string from resource specified by nID
2506 // nID - resource Identifier. Purely a Win32 thing in this case
2509 // true if successful, false otherwise
2510 // -------------------------------------------------------------------------
2514 bool Load(UINT nId
, HMODULE hModule
=NULL
)
2516 bool bLoaded
= false; // set to true of we succeed.
2518 #ifdef _MFC_VER // When in Rome (or MFC land)...
2520 // If they gave a resource handle, use it. Note - this is archaic
2521 // and not really what I would recommend. But then again, in MFC
2522 // land, you ought to be using CString for resources anyway since
2523 // it walks the resource chain for you.
2525 HMODULE hModuleOld
= NULL
;
2527 if ( NULL
!= hModule
)
2529 hModuleOld
= AfxGetResourceHandle();
2530 AfxSetResourceHandle(hModule
);
2533 // ...load the string
2536 bLoaded
= FALSE
!= strRes
.LoadString(nId
);
2538 // ...and if we set the resource handle, restore it.
2540 if ( NULL
!= hModuleOld
)
2541 AfxSetResourceHandle(hModule
);
2546 #else // otherwise make our own hackneyed version of CString's Load
2548 // Get the resource name and module handle
2550 if ( NULL
== hModule
)
2551 hModule
= GetResourceHandle();
2553 PCTSTR szName
= MAKEINTRESOURCE((nId
>>4)+1); // lifted
2556 // No sense continuing if we can't find the resource
2558 HRSRC hrsrc
= ::FindResource(hModule
, szName
, RT_STRING
);
2560 if ( NULL
== hrsrc
)
2562 TRACE(_T("Cannot find resource %d: 0x%X"), nId
, ::GetLastError());
2564 else if ( 0 == (dwSize
= ::SizeofResource(hModule
, hrsrc
) / sizeof(CT
)))
2566 TRACE(_T("Cant get size of resource %d 0x%X\n"),nId
,GetLastError());
2570 bLoaded
= 0 != ssload(hModule
, nId
, GetBuf(dwSize
), dwSize
);
2574 #endif // #ifdef _MFC_VER
2577 TRACE(_T("String not loaded 0x%X\n"), ::GetLastError());
2582 #endif // #ifdef SS_ANSI
2584 // -------------------------------------------------------------------------
2585 // FUNCTION: CStdStr::Format
2586 // void _cdecl Formst(CStdStringA& PCSTR szFormat, ...)
2587 // void _cdecl Format(PCSTR szFormat);
2590 // This function does sprintf/wsprintf style formatting on CStdStringA
2591 // objects. It looks a lot like MFC's CString::Format. Some people
2592 // might even call this identical. Fortunately, these people are now
2596 // nId - ID of string resource holding the format string
2597 // szFormat - a PCSTR holding the format specifiers
2598 // argList - a va_list holding the arguments for the format specifiers.
2600 // RETURN VALUE: None.
2601 // -------------------------------------------------------------------------
2602 // formatting (using wsprintf style formatting)
2604 // If they want a Format() function that safely handles string objects
2607 #ifdef SS_SAFE_FORMAT
2609 // Question: Joe, you wacky coder you, why do you have so many overloads
2610 // of the Format() function
2611 // Answer: One reason only - CString compatability. In short, by making
2612 // the Format() function a template this way, I can do strong typing
2613 // and allow people to pass CStdString arguments as fillers for
2614 // "%s" format specifiers without crashing their program! The downside
2615 // is that I need to overload on the number of arguments. If you are
2616 // passing more arguments than I have listed below in any of my
2617 // overloads, just add another one.
2619 // Yes, yes, this is really ugly. In essence what I am doing here is
2620 // protecting people from a bad (and incorrect) programming practice
2621 // that they should not be doing anyway. I am protecting them from
2622 // themselves. Why am I doing this? Well, if you had any idea the
2623 // number of times I've been emailed by people about this
2624 // "incompatability" in my code, you wouldn't ask.
2626 void Fmt(const CT
* szFmt
, ...)
2629 va_start(argList
, szFmt
);
2630 FormatV(szFmt
, argList
);
2636 void Format(UINT nId
)
2639 if ( strFmt
.Load(nId
) )
2643 void Format(UINT nId
, const A1
& v
)
2646 if ( strFmt
.Load(nId
) )
2647 Fmt(strFmt
, FmtArg
<A1
>(v
)());
2649 template<class A1
, class A2
>
2650 void Format(UINT nId
, const A1
& v1
, const A2
& v2
)
2653 if ( strFmt
.Load(nId
) )
2654 Fmt(strFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)());
2656 template<class A1
, class A2
, class A3
>
2657 void Format(UINT nId
, const A1
& v1
, const A2
& v2
, const A3
& v3
)
2660 if ( strFmt
.Load(nId
) )
2662 Fmt(strFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2666 template<class A1
, class A2
, class A3
, class A4
>
2667 void Format(UINT nId
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
2671 if ( strFmt
.Load(nId
) )
2673 Fmt(strFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2674 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)());
2677 template<class A1
, class A2
, class A3
, class A4
, class A5
>
2678 void Format(UINT nId
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
2679 const A4
& v4
, const A5
& v5
)
2682 if ( strFmt
.Load(nId
) )
2684 Fmt(strFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2685 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(), FmtArg
<A5
>(v5
)());
2688 template<class A1
, class A2
, class A3
, class A4
, class A5
, class A6
>
2689 void Format(UINT nId
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
2690 const A4
& v4
, const A5
& v5
, const A6
& v6
)
2693 if ( strFmt
.Load(nId
) )
2695 Fmt(strFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2696 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(),FmtArg
<A5
>(v5
)(),
2700 template<class A1
, class A2
, class A3
, class A4
, class A5
, class A6
,
2702 void Format(UINT nId
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
2703 const A4
& v4
, const A5
& v5
, const A6
& v6
, const A7
& v7
)
2706 if ( strFmt
.Load(nId
) )
2708 Fmt(strFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2709 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(),FmtArg
<A5
>(v5
)(),
2710 FmtArg
<A6
>(v6
)(), FmtArg
<A7
>(v7
)());
2713 template<class A1
, class A2
, class A3
, class A4
, class A5
, class A6
,
2715 void Format(UINT nId
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
2716 const A4
& v4
, const A5
& v5
, const A6
& v6
, const A7
& v7
,
2720 if ( strFmt
.Load(nId
) )
2722 Fmt(strFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2723 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(), FmtArg
<A5
>(v5
)(),
2724 FmtArg
<A6
>(v6
)(), FmtArg
<A7
>(v7
)(), FmtArg
<A8
>(v8
)());
2727 template<class A1
, class A2
, class A3
, class A4
, class A5
, class A6
,
2728 class A7
, class A8
, class A9
>
2729 void Format(UINT nId
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
2730 const A4
& v4
, const A5
& v5
, const A6
& v6
, const A7
& v7
,
2731 const A8
& v8
, const A9
& v9
)
2734 if ( strFmt
.Load(nId
) )
2736 Fmt(strFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2737 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(), FmtArg
<A5
>(v5
)(),
2738 FmtArg
<A6
>(v6
)(), FmtArg
<A7
>(v7
)(), FmtArg
<A8
>(v8
)(),
2742 template<class A1
, class A2
, class A3
, class A4
, class A5
, class A6
,
2743 class A7
, class A8
, class A9
, class A10
>
2744 void Format(UINT nId
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
2745 const A4
& v4
, const A5
& v5
, const A6
& v6
, const A7
& v7
,
2746 const A8
& v8
, const A9
& v9
, const A10
& v10
)
2749 if ( strFmt
.Load(nId
) )
2751 Fmt(strFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2752 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(), FmtArg
<A5
>(v5
)(),
2753 FmtArg
<A6
>(v6
)(), FmtArg
<A7
>(v7
)(), FmtArg
<A8
>(v8
)(),
2754 FmtArg
<A9
>(v9
)(), FmtArg
<A10
>(v10
)());
2757 template<class A1
, class A2
, class A3
, class A4
, class A5
, class A6
,
2758 class A7
, class A8
, class A9
, class A10
, class A11
>
2759 void Format(UINT nId
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
2760 const A4
& v4
, const A5
& v5
, const A6
& v6
, const A7
& v7
,
2761 const A8
& v8
, const A9
& v9
, const A10
& v10
, const A11
& v11
)
2764 if ( strFmt
.Load(nId
) )
2766 Fmt(strFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2767 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(), FmtArg
<A5
>(v5
)(),
2768 FmtArg
<A6
>(v6
)(), FmtArg
<A7
>(v7
)(), FmtArg
<A8
>(v8
)(),
2769 FmtArg
<A9
>(v9
)(),FmtArg
<A10
>(v10
)(),FmtArg
<A11
>(v11
)());
2772 template<class A1
, class A2
, class A3
, class A4
, class A5
, class A6
,
2773 class A7
, class A8
, class A9
, class A10
, class A11
, class A12
>
2774 void Format(UINT nId
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
2775 const A4
& v4
, const A5
& v5
, const A6
& v6
, const A7
& v7
,
2776 const A8
& v8
, const A9
& v9
, const A10
& v10
, const A11
& v11
,
2780 if ( strFmt
.Load(nId
) )
2782 Fmt(strFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2783 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(), FmtArg
<A5
>(v5
)(),
2784 FmtArg
<A6
>(v6
)(), FmtArg
<A7
>(v7
)(), FmtArg
<A8
>(v8
)(),
2785 FmtArg
<A9
>(v9
)(), FmtArg
<A10
>(v10
)(),FmtArg
<A11
>(v11
)(),
2786 FmtArg
<A12
>(v12
)());
2789 template<class A1
, class A2
, class A3
, class A4
, class A5
, class A6
,
2790 class A7
, class A8
, class A9
, class A10
, class A11
, class A12
,
2792 void Format(UINT nId
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
2793 const A4
& v4
, const A5
& v5
, const A6
& v6
, const A7
& v7
,
2794 const A8
& v8
, const A9
& v9
, const A10
& v10
, const A11
& v11
,
2795 const A12
& v12
, const A13
& v13
)
2798 if ( strFmt
.Load(nId
) )
2800 Fmt(strFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2801 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(), FmtArg
<A5
>(v5
)(),
2802 FmtArg
<A6
>(v6
)(), FmtArg
<A7
>(v7
)(), FmtArg
<A8
>(v8
)(),
2803 FmtArg
<A9
>(v9
)(), FmtArg
<A10
>(v10
)(),FmtArg
<A11
>(v11
)(),
2804 FmtArg
<A12
>(v12
)(), FmtArg
<A13
>(v13
)());
2807 template<class A1
, class A2
, class A3
, class A4
, class A5
, class A6
,
2808 class A7
, class A8
, class A9
, class A10
, class A11
, class A12
,
2809 class A13
, class A14
>
2810 void Format(UINT nId
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
2811 const A4
& v4
, const A5
& v5
, const A6
& v6
, const A7
& v7
,
2812 const A8
& v8
, const A9
& v9
, const A10
& v10
, const A11
& v11
,
2813 const A12
& v12
, const A13
& v13
, const A14
& v14
)
2816 if ( strFmt
.Load(nId
) )
2818 Fmt(strFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2819 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(), FmtArg
<A5
>(v5
)(),
2820 FmtArg
<A6
>(v6
)(), FmtArg
<A7
>(v7
)(), FmtArg
<A8
>(v8
)(),
2821 FmtArg
<A9
>(v9
)(), FmtArg
<A10
>(v10
)(),FmtArg
<A11
>(v11
)(),
2822 FmtArg
<A12
>(v12
)(), FmtArg
<A13
>(v13
)(),FmtArg
<A14
>(v14
)());
2825 template<class A1
, class A2
, class A3
, class A4
, class A5
, class A6
,
2826 class A7
, class A8
, class A9
, class A10
, class A11
, class A12
,
2827 class A13
, class A14
, class A15
>
2828 void Format(UINT nId
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
2829 const A4
& v4
, const A5
& v5
, const A6
& v6
, const A7
& v7
,
2830 const A8
& v8
, const A9
& v9
, const A10
& v10
, const A11
& v11
,
2831 const A12
& v12
, const A13
& v13
, const A14
& v14
, const A15
& v15
)
2834 if ( strFmt
.Load(nId
) )
2836 Fmt(strFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2837 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(), FmtArg
<A5
>(v5
)(),
2838 FmtArg
<A6
>(v6
)(), FmtArg
<A7
>(v7
)(), FmtArg
<A8
>(v8
)(),
2839 FmtArg
<A9
>(v9
)(), FmtArg
<A10
>(v10
)(),FmtArg
<A11
>(v11
)(),
2840 FmtArg
<A12
>(v12
)(),FmtArg
<A13
>(v13
)(),FmtArg
<A14
>(v14
)(),
2841 FmtArg
<A15
>(v15
)());
2844 template<class A1
, class A2
, class A3
, class A4
, class A5
, class A6
,
2845 class A7
, class A8
, class A9
, class A10
, class A11
, class A12
,
2846 class A13
, class A14
, class A15
, class A16
>
2847 void Format(UINT nId
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
2848 const A4
& v4
, const A5
& v5
, const A6
& v6
, const A7
& v7
,
2849 const A8
& v8
, const A9
& v9
, const A10
& v10
, const A11
& v11
,
2850 const A12
& v12
, const A13
& v13
, const A14
& v14
, const A15
& v15
,
2854 if ( strFmt
.Load(nId
) )
2856 Fmt(strFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2857 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(), FmtArg
<A5
>(v5
)(),
2858 FmtArg
<A6
>(v6
)(), FmtArg
<A7
>(v7
)(), FmtArg
<A8
>(v8
)(),
2859 FmtArg
<A9
>(v9
)(), FmtArg
<A10
>(v10
)(),FmtArg
<A11
>(v11
)(),
2860 FmtArg
<A12
>(v12
)(),FmtArg
<A13
>(v13
)(),FmtArg
<A14
>(v14
)(),
2861 FmtArg
<A15
>(v15
)(), FmtArg
<A16
>(v16
)());
2864 template<class A1
, class A2
, class A3
, class A4
, class A5
, class A6
,
2865 class A7
, class A8
, class A9
, class A10
, class A11
, class A12
,
2866 class A13
, class A14
, class A15
, class A16
, class A17
>
2867 void Format(UINT nId
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
2868 const A4
& v4
, const A5
& v5
, const A6
& v6
, const A7
& v7
,
2869 const A8
& v8
, const A9
& v9
, const A10
& v10
, const A11
& v11
,
2870 const A12
& v12
, const A13
& v13
, const A14
& v14
, const A15
& v15
,
2871 const A16
& v16
, const A17
& v17
)
2874 if ( strFmt
.Load(nId
) )
2876 Fmt(strFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2877 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(), FmtArg
<A5
>(v5
)(),
2878 FmtArg
<A6
>(v6
)(), FmtArg
<A7
>(v7
)(), FmtArg
<A8
>(v8
)(),
2879 FmtArg
<A9
>(v9
)(), FmtArg
<A10
>(v10
)(),FmtArg
<A11
>(v11
)(),
2880 FmtArg
<A12
>(v12
)(),FmtArg
<A13
>(v13
)(),FmtArg
<A14
>(v14
)(),
2881 FmtArg
<A15
>(v15
)(),FmtArg
<A16
>(v16
)(),FmtArg
<A17
>(v17
)());
2885 #endif // #ifndef SS_ANSI
2887 // ...now the other overload of Format: the one that takes a string literal
2889 void Format(const CT
* szFmt
)
2894 void Format(const CT
* szFmt
, const A1
& v
)
2896 Fmt(szFmt
, FmtArg
<A1
>(v
)());
2898 template<class A1
, class A2
>
2899 void Format(const CT
* szFmt
, const A1
& v1
, const A2
& v2
)
2901 Fmt(szFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)());
2903 template<class A1
, class A2
, class A3
>
2904 void Format(const CT
* szFmt
, const A1
& v1
, const A2
& v2
, const A3
& v3
)
2906 Fmt(szFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2909 template<class A1
, class A2
, class A3
, class A4
>
2910 void Format(const CT
* szFmt
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
2913 Fmt(szFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2914 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)());
2916 template<class A1
, class A2
, class A3
, class A4
, class A5
>
2917 void Format(const CT
* szFmt
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
2918 const A4
& v4
, const A5
& v5
)
2920 Fmt(szFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2921 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(), FmtArg
<A5
>(v5
)());
2923 template<class A1
, class A2
, class A3
, class A4
, class A5
, class A6
>
2924 void Format(const CT
* szFmt
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
2925 const A4
& v4
, const A5
& v5
, const A6
& v6
)
2927 Fmt(szFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2928 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(), FmtArg
<A5
>(v5
)(),
2931 template<class A1
, class A2
, class A3
, class A4
, class A5
, class A6
,
2933 void Format(const CT
* szFmt
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
2934 const A4
& v4
, const A5
& v5
, const A6
& v6
, const A7
& v7
)
2936 Fmt(szFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2937 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(), FmtArg
<A5
>(v5
)(),
2938 FmtArg
<A6
>(v6
)(), FmtArg
<A7
>(v7
)());
2940 template<class A1
, class A2
, class A3
, class A4
, class A5
, class A6
,
2942 void Format(const CT
* szFmt
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
2943 const A4
& v4
, const A5
& v5
, const A6
& v6
, const A7
& v7
,
2946 Fmt(szFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2947 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(), FmtArg
<A5
>(v5
)(),
2948 FmtArg
<A6
>(v6
)(), FmtArg
<A7
>(v7
)(), FmtArg
<A8
>(v8
)());
2950 template<class A1
, class A2
, class A3
, class A4
, class A5
, class A6
,
2951 class A7
, class A8
, class A9
>
2952 void Format(const CT
* szFmt
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
2953 const A4
& v4
, const A5
& v5
, const A6
& v6
, const A7
& v7
,
2954 const A8
& v8
, const A9
& v9
)
2956 Fmt(szFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2957 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(), FmtArg
<A5
>(v5
)(),
2958 FmtArg
<A6
>(v6
)(), FmtArg
<A7
>(v7
)(), FmtArg
<A8
>(v8
)(),
2961 template<class A1
, class A2
, class A3
, class A4
, class A5
, class A6
,
2962 class A7
, class A8
, class A9
, class A10
>
2963 void Format(const CT
* szFmt
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
2964 const A4
& v4
, const A5
& v5
, const A6
& v6
, const A7
& v7
,
2965 const A8
& v8
, const A9
& v9
, const A10
& v10
)
2967 Fmt(szFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2968 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(), FmtArg
<A5
>(v5
)(),
2969 FmtArg
<A6
>(v6
)(), FmtArg
<A7
>(v7
)(), FmtArg
<A8
>(v8
)(),
2970 FmtArg
<A9
>(v9
)(), FmtArg
<A10
>(v10
)());
2972 template<class A1
, class A2
, class A3
, class A4
, class A5
, class A6
,
2973 class A7
, class A8
, class A9
, class A10
, class A11
>
2974 void Format(const CT
* szFmt
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
2975 const A4
& v4
, const A5
& v5
, const A6
& v6
, const A7
& v7
,
2976 const A8
& v8
, const A9
& v9
, const A10
& v10
, const A11
& v11
)
2978 Fmt(szFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2979 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(), FmtArg
<A5
>(v5
)(),
2980 FmtArg
<A6
>(v6
)(), FmtArg
<A7
>(v7
)(), FmtArg
<A8
>(v8
)(),
2981 FmtArg
<A9
>(v9
)(),FmtArg
<A10
>(v10
)(),FmtArg
<A11
>(v11
)());
2983 template<class A1
, class A2
, class A3
, class A4
, class A5
, class A6
,
2984 class A7
, class A8
, class A9
, class A10
, class A11
, class A12
>
2985 void Format(const CT
* szFmt
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
2986 const A4
& v4
, const A5
& v5
, const A6
& v6
, const A7
& v7
,
2987 const A8
& v8
, const A9
& v9
, const A10
& v10
, const A11
& v11
,
2990 Fmt(szFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2991 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(), FmtArg
<A5
>(v5
)(),
2992 FmtArg
<A6
>(v6
)(), FmtArg
<A7
>(v7
)(), FmtArg
<A8
>(v8
)(),
2993 FmtArg
<A9
>(v9
)(), FmtArg
<A10
>(v10
)(),FmtArg
<A11
>(v11
)(),
2994 FmtArg
<A12
>(v12
)());
2996 template<class A1
, class A2
, class A3
, class A4
, class A5
, class A6
,
2997 class A7
, class A8
, class A9
, class A10
, class A11
, class A12
,
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 const A12
& v12
, const A13
& v13
)
3004 Fmt(szFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
3005 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(), FmtArg
<A5
>(v5
)(),
3006 FmtArg
<A6
>(v6
)(), FmtArg
<A7
>(v7
)(), FmtArg
<A8
>(v8
)(),
3007 FmtArg
<A9
>(v9
)(), FmtArg
<A10
>(v10
)(),FmtArg
<A11
>(v11
)(),
3008 FmtArg
<A12
>(v12
)(), FmtArg
<A13
>(v13
)());
3010 template<class A1
, class A2
, class A3
, class A4
, class A5
, class A6
,
3011 class A7
, class A8
, class A9
, class A10
, class A11
, class A12
,
3012 class A13
, class A14
>
3013 void Format(const CT
* szFmt
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
3014 const A4
& v4
, const A5
& v5
, const A6
& v6
, const A7
& v7
,
3015 const A8
& v8
, const A9
& v9
, const A10
& v10
, const A11
& v11
,
3016 const A12
& v12
, const A13
& v13
, const A14
& v14
)
3018 Fmt(szFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
3019 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(), FmtArg
<A5
>(v5
)(),
3020 FmtArg
<A6
>(v6
)(), FmtArg
<A7
>(v7
)(), FmtArg
<A8
>(v8
)(),
3021 FmtArg
<A9
>(v9
)(), FmtArg
<A10
>(v10
)(),FmtArg
<A11
>(v11
)(),
3022 FmtArg
<A12
>(v12
)(), FmtArg
<A13
>(v13
)(),FmtArg
<A14
>(v14
)());
3024 template<class A1
, class A2
, class A3
, class A4
, class A5
, class A6
,
3025 class A7
, class A8
, class A9
, class A10
, class A11
, class A12
,
3026 class A13
, class A14
, class A15
>
3027 void Format(const CT
* szFmt
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
3028 const A4
& v4
, const A5
& v5
, const A6
& v6
, const A7
& v7
,
3029 const A8
& v8
, const A9
& v9
, const A10
& v10
, const A11
& v11
,
3030 const A12
& v12
, const A13
& v13
, const A14
& v14
, const A15
& v15
)
3032 Fmt(szFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
3033 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(), FmtArg
<A5
>(v5
)(),
3034 FmtArg
<A6
>(v6
)(), FmtArg
<A7
>(v7
)(), FmtArg
<A8
>(v8
)(),
3035 FmtArg
<A9
>(v9
)(), FmtArg
<A10
>(v10
)(),FmtArg
<A11
>(v11
)(),
3036 FmtArg
<A12
>(v12
)(),FmtArg
<A13
>(v13
)(),FmtArg
<A14
>(v14
)(),
3037 FmtArg
<A15
>(v15
)());
3039 template<class A1
, class A2
, class A3
, class A4
, class A5
, class A6
,
3040 class A7
, class A8
, class A9
, class A10
, class A11
, class A12
,
3041 class A13
, class A14
, class A15
, class A16
>
3042 void Format(const CT
* szFmt
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
3043 const A4
& v4
, const A5
& v5
, const A6
& v6
, const A7
& v7
,
3044 const A8
& v8
, const A9
& v9
, const A10
& v10
, const A11
& v11
,
3045 const A12
& v12
, const A13
& v13
, const A14
& v14
, const A15
& v15
,
3048 Fmt(szFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
3049 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(), FmtArg
<A5
>(v5
)(),
3050 FmtArg
<A6
>(v6
)(), FmtArg
<A7
>(v7
)(), FmtArg
<A8
>(v8
)(),
3051 FmtArg
<A9
>(v9
)(), FmtArg
<A10
>(v10
)(),FmtArg
<A11
>(v11
)(),
3052 FmtArg
<A12
>(v12
)(),FmtArg
<A13
>(v13
)(),FmtArg
<A14
>(v14
)(),
3053 FmtArg
<A15
>(v15
)(), FmtArg
<A16
>(v16
)());
3055 template<class A1
, class A2
, class A3
, class A4
, class A5
, class A6
,
3056 class A7
, class A8
, class A9
, class A10
, class A11
, class A12
,
3057 class A13
, class A14
, class A15
, class A16
, class A17
>
3058 void Format(const CT
* szFmt
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
3059 const A4
& v4
, const A5
& v5
, const A6
& v6
, const A7
& v7
,
3060 const A8
& v8
, const A9
& v9
, const A10
& v10
, const A11
& v11
,
3061 const A12
& v12
, const A13
& v13
, const A14
& v14
, const A15
& v15
,
3062 const A16
& v16
, const A17
& v17
)
3064 Fmt(szFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
3065 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(), FmtArg
<A5
>(v5
)(),
3066 FmtArg
<A6
>(v6
)(), FmtArg
<A7
>(v7
)(), FmtArg
<A8
>(v8
)(),
3067 FmtArg
<A9
>(v9
)(), FmtArg
<A10
>(v10
)(),FmtArg
<A11
>(v11
)(),
3068 FmtArg
<A12
>(v12
)(),FmtArg
<A13
>(v13
)(),FmtArg
<A14
>(v14
)(),
3069 FmtArg
<A15
>(v15
)(),FmtArg
<A16
>(v16
)(),FmtArg
<A17
>(v17
)());
3072 #else // #ifdef SS_SAFE_FORMAT
3077 void Format(UINT nId
, ...)
3080 va_start(argList
, nId
);
3083 if ( strFmt
.Load(nId
) )
3084 FormatV(strFmt
, argList
);
3089 #endif // #ifdef SS_ANSI
3091 void Format(const CT
* szFmt
, ...)
3094 va_start(argList
, szFmt
);
3095 FormatV(szFmt
, argList
);
3099 #endif // #ifdef SS_SAFE_FORMAT
3101 void AppendFormat(const CT
* szFmt
, ...)
3104 va_start(argList
, szFmt
);
3105 AppendFormatV(szFmt
, argList
);
3109 #define MAX_FMT_TRIES 5 // #of times we try
3110 #define FMT_BLOCK_SIZE 2048 // # of bytes to increment per try
3111 #define BUFSIZE_1ST 256
3112 #define BUFSIZE_2ND 512
3113 #define STD_BUF_SIZE 1024
3115 // an efficient way to add formatted characters to the string. You may only
3116 // add up to STD_BUF_SIZE characters at a time, though
3117 void AppendFormatV(const CT
* szFmt
, va_list argList
)
3119 CT szBuf
[STD_BUF_SIZE
];
3120 int nLen
= ssnprintf(szBuf
, STD_BUF_SIZE
-1, szFmt
, argList
);
3123 this->append(szBuf
, nLen
);
3126 // -------------------------------------------------------------------------
3127 // FUNCTION: FormatV
3128 // void FormatV(PCSTR szFormat, va_list, argList);
3131 // This function formats the string with sprintf style format-specs.
3132 // It makes a general guess at required buffer size and then tries
3133 // successively larger buffers until it finds one big enough or a
3134 // threshold (MAX_FMT_TRIES) is exceeded.
3137 // szFormat - a PCSTR holding the format of the output
3138 // argList - a Microsoft specific va_list for variable argument lists
3141 // -------------------------------------------------------------------------
3143 // NOTE: Changed by JM to actually function under non-win32,
3144 // and to remove the upper limit on size.
3145 void FormatV(const CT
* szFormat
, va_list argList
)
3147 // try and grab a sufficient buffersize
3148 int nChars
= FMT_BLOCK_SIZE
;
3151 CT
*p
= reinterpret_cast<CT
*>(malloc(sizeof(CT
)*nChars
));
3156 va_copy(argCopy
, argList
);
3158 int nActual
= ssvsprintf(p
, nChars
, szFormat
, argCopy
);
3159 /* If that worked, return the string. */
3160 if (nActual
> -1 && nActual
< nChars
)
3161 { /* make sure it's NULL terminated */
3163 this->assign(p
, nActual
);
3168 /* Else try again with more space. */
3169 if (nActual
> -1) /* glibc 2.1 */
3170 nChars
= nActual
+ 1; /* precisely what is needed */
3171 else /* glibc 2.0 */
3172 nChars
*= 2; /* twice the old size */
3174 CT
*np
= reinterpret_cast<CT
*>(realloc(p
, sizeof(CT
)*nChars
));
3179 return; // failed :(
3186 // -------------------------------------------------------------------------
3187 // CString Facade Functions:
3189 // The following methods are intended to allow you to use this class as a
3190 // near drop-in replacement for CString.
3191 // -------------------------------------------------------------------------
3193 BSTR
AllocSysString() const
3197 return ::SysAllocString(os
.c_str());
3201 #ifndef SS_NO_LOCALE
3202 int Collate(PCMYSTR szThat
) const
3204 return sscoll(this->c_str(), this->length(), szThat
, sslen(szThat
));
3207 int CollateNoCase(PCMYSTR szThat
) const
3209 return ssicoll(this->c_str(), this->length(), szThat
, sslen(szThat
));
3212 int Compare(PCMYSTR szThat
) const
3214 return this->compare(szThat
);
3217 int CompareNoCase(PCMYSTR szThat
) const
3219 return ssicmp(this->c_str(), szThat
);
3222 int Delete(int nIdx
, int nCount
=1)
3227 if ( nIdx
< this->GetLength() )
3228 this->erase(static_cast<MYSIZE
>(nIdx
), static_cast<MYSIZE
>(nCount
));
3238 int Find(CT ch
) const
3240 MYSIZE nIdx
= this->find_first_of(ch
);
3241 return static_cast<int>(MYBASE::npos
== nIdx
? -1 : nIdx
);
3244 int Find(PCMYSTR szSub
) const
3246 MYSIZE nIdx
= this->find(szSub
);
3247 return static_cast<int>(MYBASE::npos
== nIdx
? -1 : nIdx
);
3250 int Find(CT ch
, int nStart
) const
3252 // CString::Find docs say add 1 to nStart when it's not zero
3253 // CString::Find code doesn't do that however. We'll stick
3254 // with what the code does
3256 MYSIZE nIdx
= this->find_first_of(ch
, static_cast<MYSIZE
>(nStart
));
3257 return static_cast<int>(MYBASE::npos
== nIdx
? -1 : nIdx
);
3260 int Find(PCMYSTR szSub
, int nStart
) const
3262 // CString::Find docs say add 1 to nStart when it's not zero
3263 // CString::Find code doesn't do that however. We'll stick
3264 // with what the code does
3266 MYSIZE nIdx
= this->find(szSub
, static_cast<MYSIZE
>(nStart
));
3267 return static_cast<int>(MYBASE::npos
== nIdx
? -1 : nIdx
);
3270 int FindOneOf(PCMYSTR szCharSet
) const
3272 MYSIZE nIdx
= this->find_first_of(szCharSet
);
3273 return static_cast<int>(MYBASE::npos
== nIdx
? -1 : nIdx
);
3277 void FormatMessage(PCMYSTR szFormat
, ...) throw(std::exception
)
3280 va_start(argList
, szFormat
);
3282 if ( ssfmtmsg(FORMAT_MESSAGE_FROM_STRING
|FORMAT_MESSAGE_ALLOCATE_BUFFER
,
3284 reinterpret_cast<PMYSTR
>(&szTemp
), 0, &argList
) == 0 ||
3287 throw std::runtime_error("out of memory");
3294 void FormatMessage(UINT nFormatId
, ...) throw(std::exception
)
3297 VERIFY(sFormat
.LoadString(nFormatId
));
3299 va_start(argList
, nFormatId
);
3301 if ( ssfmtmsg(FORMAT_MESSAGE_FROM_STRING
|FORMAT_MESSAGE_ALLOCATE_BUFFER
,
3303 reinterpret_cast<PMYSTR
>(&szTemp
), 0, &argList
) == 0 ||
3306 throw std::runtime_error("out of memory");
3314 // GetAllocLength -- an MSVC7 function but it costs us nothing to add it.
3316 int GetAllocLength()
3318 return static_cast<int>(this->capacity());
3321 // -------------------------------------------------------------------------
3322 // GetXXXX -- Direct access to character buffer
3323 // -------------------------------------------------------------------------
3324 CT
GetAt(int nIdx
) const
3326 return this->at(static_cast<MYSIZE
>(nIdx
));
3329 CT
* GetBuffer(int nMinLen
=-1)
3331 return GetBuf(nMinLen
);
3334 CT
* GetBufferSetLength(int nLen
)
3336 return BufferSet(nLen
);
3339 // GetLength() -- MFC docs say this is the # of BYTES but
3340 // in truth it is the number of CHARACTERs (chars or wchar_ts)
3341 int GetLength() const
3343 return static_cast<int>(this->length());
3346 int Insert(int nIdx
, CT ch
)
3348 if ( static_cast<MYSIZE
>(nIdx
) > this->size()-1 )
3349 this->append(1, ch
);
3351 this->insert(static_cast<MYSIZE
>(nIdx
), 1, ch
);
3355 int Insert(int nIdx
, PCMYSTR sz
)
3357 if ( static_cast<MYSIZE
>(nIdx
) >= this->size() )
3358 this->append(sz
, static_cast<MYSIZE
>(sslen(sz
)));
3360 this->insert(static_cast<MYSIZE
>(nIdx
), sz
);
3365 bool IsEmpty() const
3367 return this->empty();
3370 MYTYPE
Left(int nCount
) const
3372 // Range check the count.
3374 nCount
= SSMAX(0, SSMIN(nCount
, static_cast<int>(this->size())));
3375 return this->substr(0, static_cast<MYSIZE
>(nCount
));
3379 bool LoadString(UINT nId
)
3381 return this->Load(nId
);
3392 std::reverse(this->begin(), this->end());
3400 MYTYPE
Mid(int nFirst
) const
3402 return Mid(nFirst
, this->GetLength()-nFirst
);
3405 MYTYPE
Mid(int nFirst
, int nCount
) const
3407 // CString does range checking here. Since we're trying to emulate it,
3408 // we must check too.
3415 int nSize
= static_cast<int>(this->size());
3417 if ( nFirst
+ nCount
> nSize
)
3418 nCount
= nSize
- nFirst
;
3420 if ( nFirst
> nSize
)
3423 ASSERT(nFirst
>= 0);
3424 ASSERT(nFirst
+ nCount
<= nSize
);
3426 return this->substr(static_cast<MYSIZE
>(nFirst
),
3427 static_cast<MYSIZE
>(nCount
));
3430 void ReleaseBuffer(int nNewLen
=-1)
3439 while ( (nIdx
=this->find_first_of(ch
)) != MYBASE::npos
)
3441 this->erase(nIdx
, 1);
3447 int Replace(CT chOld
, CT chNew
)
3451 for ( MYITER iter
=this->begin(); iter
!= this->end(); iter
++ )
3453 if ( *iter
== chOld
)
3463 int Replace(PCMYSTR szOld
, PCMYSTR szNew
)
3467 MYSIZE nOldLen
= sslen(szOld
);
3471 // If the replacement string is longer than the one it replaces, this
3472 // string is going to have to grow in size, Figure out how much
3473 // and grow it all the way now, rather than incrementally
3475 MYSIZE nNewLen
= sslen(szNew
);
3476 if ( nNewLen
> nOldLen
)
3479 while ( nIdx
< this->length() &&
3480 (nIdx
=this->find(szOld
, nIdx
)) != MYBASE::npos
)
3485 this->reserve(this->size() + nFound
* (nNewLen
- nOldLen
));
3489 static const CT ch
= CT(0);
3490 PCMYSTR szRealNew
= szNew
== 0 ? &ch
: szNew
;
3493 while ( nIdx
< this->length() &&
3494 (nIdx
=this->find(szOld
, nIdx
)) != MYBASE::npos
)
3496 this->replace(this->begin()+nIdx
, this->begin()+nIdx
+nOldLen
,
3507 int ReverseFind(CT ch
) const
3509 MYSIZE nIdx
= this->find_last_of(ch
);
3510 return static_cast<int>(MYBASE::npos
== nIdx
? -1 : nIdx
);
3513 // ReverseFind overload that's not in CString but might be useful
3514 int ReverseFind(PCMYSTR szFind
, MYSIZE pos
=MYBASE::npos
) const
3516 //yuvalt - this does not compile with g++ since MYTTYPE() is different type
3517 //MYSIZE nIdx = this->rfind(0 == szFind ? MYTYPE() : szFind, pos);
3518 MYSIZE nIdx
= this->rfind(0 == szFind
? "" : szFind
, pos
);
3519 return static_cast<int>(MYBASE::npos
== nIdx
? -1 : nIdx
);
3522 MYTYPE
Right(int nCount
) const
3524 // Range check the count.
3526 nCount
= SSMAX(0, SSMIN(nCount
, static_cast<int>(this->size())));
3527 return this->substr(this->size()-static_cast<MYSIZE
>(nCount
));
3530 void SetAt(int nIndex
, CT ch
)
3532 ASSERT(this->size() > static_cast<MYSIZE
>(nIndex
));
3533 this->at(static_cast<MYSIZE
>(nIndex
)) = ch
;
3537 BSTR
SetSysString(BSTR
* pbstr
) const
3541 if ( !::SysReAllocStringLen(pbstr
, os
.c_str(), os
.length()) )
3542 throw std::runtime_error("out of memory");
3544 ASSERT(*pbstr
!= 0);
3549 MYTYPE
SpanExcluding(PCMYSTR szCharSet
) const
3551 MYSIZE pos
= this->find_first_of(szCharSet
);
3552 return pos
== MYBASE::npos
? *this : Left(pos
);
3555 MYTYPE
SpanIncluding(PCMYSTR szCharSet
) const
3557 MYSIZE pos
= this->find_first_not_of(szCharSet
);
3558 return pos
== MYBASE::npos
? *this : Left(pos
);
3561 #if defined SS_WIN32 && !defined(UNICODE) && !defined(SS_ANSI)
3563 // CString's OemToAnsi and AnsiToOem functions are available only in
3564 // Unicode builds. However since we're a template we also need a
3565 // runtime check of CT and a reinterpret_cast to account for the fact
3566 // that CStdStringW gets instantiated even in non-Unicode builds.
3570 if ( sizeof(CT
) == sizeof(char) && !empty() )
3572 ::CharToOem(reinterpret_cast<PCSTR
>(this->c_str()),
3573 reinterpret_cast<PSTR
>(GetBuf()));
3583 if ( sizeof(CT
) == sizeof(char) && !empty() )
3585 ::OemToChar(reinterpret_cast<PCSTR
>(this->c_str()),
3586 reinterpret_cast<PSTR
>(GetBuf()));
3597 // -------------------------------------------------------------------------
3598 // Trim and its variants
3599 // -------------------------------------------------------------------------
3602 return TrimLeft().TrimRight();
3607 this->erase(this->begin(),
3608 std::find_if(this->begin(), this->end(), NotSpace
<CT
>()));
3613 MYTYPE
& TrimLeft(CT tTrim
)
3615 this->erase(0, this->find_first_not_of(tTrim
));
3619 MYTYPE
& TrimLeft(PCMYSTR szTrimChars
)
3621 this->erase(0, this->find_first_not_of(szTrimChars
));
3627 // NOTE: When comparing reverse_iterators here (MYRITER), I avoid using
3628 // operator!=. This is because namespace rel_ops also has a template
3629 // operator!= which conflicts with the global operator!= already defined
3630 // for reverse_iterator in the header <utility>.
3631 // Thanks to John James for alerting me to this.
3633 MYRITER it
= std::find_if(this->rbegin(), this->rend(), NotSpace
<CT
>());
3634 if ( !(this->rend() == it
) )
3635 this->erase(this->rend() - it
);
3637 this->erase(!(it
== this->rend()) ? this->find_last_of(*it
) + 1 : 0);
3641 MYTYPE
& TrimRight(CT tTrim
)
3643 MYSIZE nIdx
= this->find_last_not_of(tTrim
);
3644 this->erase(MYBASE::npos
== nIdx
? 0 : ++nIdx
);
3648 MYTYPE
& TrimRight(PCMYSTR szTrimChars
)
3650 MYSIZE nIdx
= this->find_last_not_of(szTrimChars
);
3651 this->erase(MYBASE::npos
== nIdx
? 0 : ++nIdx
);
3660 this->assign(mt
.c_str(), mt
.size());
3663 // I have intentionally not implemented the following CString
3664 // functions. You cannot make them work without taking advantage
3665 // of implementation specific behavior. However if you absolutely
3666 // MUST have them, uncomment out these lines for "sort-of-like"
3667 // their behavior. You're on your own.
3669 // CT* LockBuffer() { return GetBuf(); }// won't really lock
3670 // void UnlockBuffer(); { } // why have UnlockBuffer w/o LockBuffer?
3672 // Array-indexing operators. Required because we defined an implicit cast
3673 // to operator const CT* (Thanks to Julian Selman for pointing this out)
3675 CT
& operator[](int nIdx
)
3677 return static_cast<MYBASE
*>(this)->operator[](static_cast<MYSIZE
>(nIdx
));
3680 const CT
& operator[](int nIdx
) const
3682 return static_cast<const MYBASE
*>(this)->operator[](static_cast<MYSIZE
>(nIdx
));
3685 CT
& operator[](unsigned int nIdx
)
3687 return static_cast<MYBASE
*>(this)->operator[](static_cast<MYSIZE
>(nIdx
));
3690 const CT
& operator[](unsigned int nIdx
) const
3692 return static_cast<const MYBASE
*>(this)->operator[](static_cast<MYSIZE
>(nIdx
));
3695 CT
& operator[](unsigned long nIdx
)
3697 return static_cast<MYBASE
*>(this)->operator[](static_cast<MYSIZE
>(nIdx
));
3700 const CT
& operator[](unsigned long nIdx
) const
3702 return static_cast<const MYBASE
*>(this)->operator[](static_cast<MYSIZE
>(nIdx
));
3705 #ifndef SS_NO_IMPLICIT_CAST
3706 operator const CT
*() const
3708 return this->c_str();
3712 // IStream related functions. Useful in IPersistStream implementations
3714 #ifdef SS_INC_COMDEF
3716 // struct SSSHDR - useful for non Std C++ persistence schemes.
3717 typedef struct SSSHDR
3721 } SSSHDR
; // as in "Standard String Stream Header"
3723 #define SSSO_UNICODE 0x01 // the string is a wide string
3724 #define SSSO_COMPRESS 0x02 // the string is compressed
3726 // -------------------------------------------------------------------------
3727 // FUNCTION: StreamSize
3729 // Returns how many bytes it will take to StreamSave() this CStdString
3730 // object to an IStream.
3731 // -------------------------------------------------------------------------
3732 ULONG
StreamSize() const
3734 // Control header plus string
3735 ASSERT(this->size()*sizeof(CT
) < 0xffffffffUL
- sizeof(SSSHDR
));
3736 return (this->size() * sizeof(CT
)) + sizeof(SSSHDR
);
3739 // -------------------------------------------------------------------------
3740 // FUNCTION: StreamSave
3742 // Saves this CStdString object to a COM IStream.
3743 // -------------------------------------------------------------------------
3744 HRESULT
StreamSave(IStream
* pStream
) const
3746 ASSERT(this->size()*sizeof(CT
) < 0xffffffffUL
- sizeof(SSSHDR
));
3747 HRESULT hr
= E_FAIL
;
3748 ASSERT(pStream
!= 0);
3750 hdr
.byCtrl
= sizeof(CT
) == 2 ? SSSO_UNICODE
: 0;
3751 hdr
.nChars
= this->size();
3754 if ( FAILED(hr
=pStream
->Write(&hdr
, sizeof(SSSHDR
), 0)) )
3756 TRACE(_T("StreamSave: Cannot write control header, ERR=0x%X\n"),hr
);
3760 ; // nothing to write
3762 else if ( FAILED(hr
=pStream
->Write(this->c_str(),
3763 this->size()*sizeof(CT
), 0)) )
3765 TRACE(_T("StreamSave: Cannot write string to stream 0x%X\n"), hr
);
3772 // -------------------------------------------------------------------------
3773 // FUNCTION: StreamLoad
3775 // This method loads the object from an IStream.
3776 // -------------------------------------------------------------------------
3777 HRESULT
StreamLoad(IStream
* pStream
)
3779 ASSERT(pStream
!= 0);
3781 HRESULT hr
= E_FAIL
;
3783 if ( FAILED(hr
=pStream
->Read(&hdr
, sizeof(SSSHDR
), 0)) )
3785 TRACE(_T("StreamLoad: Cant read control header, ERR=0x%X\n"), hr
);
3787 else if ( hdr
.nChars
> 0 )
3790 PMYSTR pMyBuf
= BufferSet(hdr
.nChars
);
3792 // If our character size matches the character size of the string
3793 // we're trying to read, then we can read it directly into our
3794 // buffer. Otherwise, we have to read into an intermediate buffer
3797 if ( (hdr
.byCtrl
& SSSO_UNICODE
) != 0 )
3799 ULONG nBytes
= hdr
.nChars
* sizeof(wchar_t);
3800 if ( sizeof(CT
) == sizeof(wchar_t) )
3802 if ( FAILED(hr
=pStream
->Read(pMyBuf
, nBytes
, &nRead
)) )
3803 TRACE(_T("StreamLoad: Cannot read string: 0x%X\n"), hr
);
3807 PWSTR pBufW
= reinterpret_cast<PWSTR
>(_alloca((nBytes
)+1));
3808 if ( FAILED(hr
=pStream
->Read(pBufW
, nBytes
, &nRead
)) )
3809 TRACE(_T("StreamLoad: Cannot read string: 0x%X\n"), hr
);
3811 sscpy(pMyBuf
, pBufW
, hdr
.nChars
);
3816 ULONG nBytes
= hdr
.nChars
* sizeof(char);
3817 if ( sizeof(CT
) == sizeof(char) )
3819 if ( FAILED(hr
=pStream
->Read(pMyBuf
, nBytes
, &nRead
)) )
3820 TRACE(_T("StreamLoad: Cannot read string: 0x%X\n"), hr
);
3824 PSTR pBufA
= reinterpret_cast<PSTR
>(_alloca(nBytes
));
3825 if ( FAILED(hr
=pStream
->Read(pBufA
, hdr
.nChars
, &nRead
)) )
3826 TRACE(_T("StreamLoad: Cannot read string: 0x%X\n"), hr
);
3828 sscpy(pMyBuf
, pBufA
, hdr
.nChars
);
3838 #endif // #ifdef SS_INC_COMDEF
3842 // SetResourceHandle/GetResourceHandle. In MFC builds, these map directly
3843 // to AfxSetResourceHandle and AfxGetResourceHandle. In non-MFC builds they
3844 // point to a single static HINST so that those who call the member
3845 // functions that take resource IDs can provide an alternate HINST of a DLL
3846 // to search. This is not exactly the list of HMODULES that MFC provides
3847 // but it's better than nothing.
3850 static void SetResourceHandle(HMODULE hNew
)
3852 AfxSetResourceHandle(hNew
);
3854 static HMODULE
GetResourceHandle()
3856 return AfxGetResourceHandle();
3859 static void SetResourceHandle(HMODULE hNew
)
3861 SSResourceHandle() = hNew
;
3863 static HMODULE
GetResourceHandle()
3865 return SSResourceHandle();
3872 // -----------------------------------------------------------------------------
3873 // MSVC USERS: HOW TO EXPORT CSTDSTRING FROM A DLL
3875 // If you are using MS Visual C++ and you want to export CStdStringA and
3876 // CStdStringW from a DLL, then all you need to
3878 // 1. make sure that all components link to the same DLL version
3879 // of the CRT (not the static one).
3880 // 2. Uncomment the 3 lines of code below
3881 // 3. #define 2 macros per the instructions in MS KnowledgeBase
3882 // article Q168958. The macros are:
3884 // MACRO DEFINTION WHEN EXPORTING DEFINITION WHEN IMPORTING
3885 // ----- ------------------------ -------------------------
3886 // SSDLLEXP (nothing, just #define it) extern
3887 // SSDLLSPEC __declspec(dllexport) __declspec(dllimport)
3889 // Note that these macros must be available to ALL clients who want to
3890 // link to the DLL and use the class. If they
3892 // A word of advice: Don't bother.
3894 // Really, it is not necessary to export CStdString functions from a DLL. I
3895 // never do. In my projects, I do generally link to the DLL version of the
3896 // Standard C++ Library, but I do NOT attempt to export CStdString functions.
3897 // I simply include the header where it is needed and allow for the code
3900 // That redundancy is a lot less than you think. This class does most of its
3901 // work via the Standard C++ Library, particularly the base_class basic_string<>
3902 // member functions. Most of the functions here are small enough to be inlined
3903 // anyway. Besides, you'll find that in actual practice you use less than 1/2
3904 // of the code here, even in big projects and different modules will use as
3905 // little as 10% of it. That means a lot less functions actually get linked
3906 // your binaries. If you export this code from a DLL, it ALL gets linked in.
3908 // I've compared the size of the binaries from exporting vs NOT exporting. Take
3909 // my word for it -- exporting this code is not worth the hassle.
3911 // -----------------------------------------------------------------------------
3912 //#pragma warning(disable:4231) // non-standard extension ("extern template")
3913 // SSDLLEXP template class SSDLLSPEC CStdStr<char>;
3914 // SSDLLEXP template class SSDLLSPEC CStdStr<wchar_t>;
3917 // =============================================================================
3918 // END OF CStdStr INLINE FUNCTION DEFINITIONS
3919 // =============================================================================
3921 // Now typedef our class names based upon this humongous template
3923 typedef CStdStr
<char> CStdStringA
; // a better std::string
3924 typedef CStdStr
<wchar_t> CStdStringW
; // a better std::wstring
3925 typedef CStdStr
<uint16_t> CStdString16
; // a 16bit char string
3926 typedef CStdStr
<uint32_t> CStdString32
; // a 32bit char string
3927 typedef CStdStr
<OLECHAR
> CStdStringO
; // almost always CStdStringW
3929 // -----------------------------------------------------------------------------
3930 // CStdStr addition functions defined as inline
3931 // -----------------------------------------------------------------------------
3934 inline CStdStringA
operator+(const CStdStringA
& s1
, const CStdStringA
& s2
)
3936 CStdStringA
sRet(SSREF(s1
));
3940 inline CStdStringA
operator+(const CStdStringA
& s1
, CStdStringA::value_type t
)
3942 CStdStringA
sRet(SSREF(s1
));
3946 inline CStdStringA
operator+(const CStdStringA
& s1
, PCSTR pA
)
3948 CStdStringA
sRet(SSREF(s1
));
3952 inline CStdStringA
operator+(PCSTR pA
, const CStdStringA
& sA
)
3955 CStdStringA::size_type nObjSize
= sA
.size();
3956 CStdStringA::size_type nLitSize
=
3957 static_cast<CStdStringA::size_type
>(sslen(pA
));
3959 sRet
.reserve(nLitSize
+ nObjSize
);
3966 inline CStdStringA
operator+(const CStdStringA
& s1
, const CStdStringW
& s2
)
3968 return s1
+ CStdStringA(s2
);
3970 inline CStdStringW
operator+(const CStdStringW
& s1
, const CStdStringW
& s2
)
3972 CStdStringW
sRet(SSREF(s1
));
3976 inline CStdStringA
operator+(const CStdStringA
& s1
, PCWSTR pW
)
3978 return s1
+ CStdStringA(pW
);
3982 inline CStdStringW
operator+(PCWSTR pW
, const CStdStringA
& sA
)
3984 return CStdStringW(pW
) + CStdStringW(SSREF(sA
));
3986 inline CStdStringW
operator+(PCSTR pA
, const CStdStringW
& sW
)
3988 return CStdStringW(pA
) + sW
;
3991 inline CStdStringA
operator+(PCWSTR pW
, const CStdStringA
& sA
)
3993 return CStdStringA(pW
) + sA
;
3995 inline CStdStringA
operator+(PCSTR pA
, const CStdStringW
& sW
)
3997 return pA
+ CStdStringA(sW
);
4001 // ...Now the wide string versions.
4002 inline CStdStringW
operator+(const CStdStringW
& s1
, CStdStringW::value_type t
)
4004 CStdStringW
sRet(SSREF(s1
));
4008 inline CStdStringW
operator+(const CStdStringW
& s1
, PCWSTR pW
)
4010 CStdStringW
sRet(SSREF(s1
));
4014 inline CStdStringW
operator+(PCWSTR pW
, const CStdStringW
& sW
)
4017 CStdStringW::size_type nObjSize
= sW
.size();
4018 CStdStringA::size_type nLitSize
=
4019 static_cast<CStdStringW::size_type
>(sslen(pW
));
4021 sRet
.reserve(nLitSize
+ nObjSize
);
4027 inline CStdStringW
operator+(const CStdStringW
& s1
, const CStdStringA
& s2
)
4029 return s1
+ CStdStringW(s2
);
4031 inline CStdStringW
operator+(const CStdStringW
& s1
, PCSTR pA
)
4033 return s1
+ CStdStringW(pA
);
4037 // New-style format function is a template
4039 #ifdef SS_SAFE_FORMAT
4042 struct FmtArg
<CStdStringA
>
4044 explicit FmtArg(const CStdStringA
& arg
) : a_(arg
) {}
4045 PCSTR
operator()() const { return a_
.c_str(); }
4046 const CStdStringA
& a_
;
4048 FmtArg
<CStdStringA
>& operator=(const FmtArg
<CStdStringA
>&) { return *this; }
4051 struct FmtArg
<CStdStringW
>
4053 explicit FmtArg(const CStdStringW
& arg
) : a_(arg
) {}
4054 PCWSTR
operator()() const { return a_
.c_str(); }
4055 const CStdStringW
& a_
;
4057 FmtArg
<CStdStringW
>& operator=(const FmtArg
<CStdStringW
>&) { return *this; }
4061 struct FmtArg
<std::string
>
4063 explicit FmtArg(const std::string
& arg
) : a_(arg
) {}
4064 PCSTR
operator()() const { return a_
.c_str(); }
4065 const std::string
& a_
;
4067 FmtArg
<std::string
>& operator=(const FmtArg
<std::string
>&) { return *this; }
4070 struct FmtArg
<std::wstring
>
4072 explicit FmtArg(const std::wstring
& arg
) : a_(arg
) {}
4073 PCWSTR
operator()() const { return a_
.c_str(); }
4074 const std::wstring
& a_
;
4076 FmtArg
<std::wstring
>& operator=(const FmtArg
<std::wstring
>&) {return *this;}
4078 #endif // #ifdef SS_SAFEFORMAT
4081 // SSResourceHandle: our MFC-like resource handle
4082 inline HMODULE
& SSResourceHandle()
4084 static HMODULE hModuleSS
= GetModuleHandle(0);
4090 // In MFC builds, define some global serialization operators
4091 // Special operators that allow us to serialize CStdStrings to CArchives.
4092 // Note that we use an intermediate CString object in order to ensure that
4093 // we use the exact same format.
4096 inline CArchive
& AFXAPI
operator<<(CArchive
& ar
, const CStdStringA
& strA
)
4098 CString strTemp
= strA
;
4099 return ar
<< strTemp
;
4101 inline CArchive
& AFXAPI
operator<<(CArchive
& ar
, const CStdStringW
& strW
)
4103 CString strTemp
= strW
;
4104 return ar
<< strTemp
;
4107 inline CArchive
& AFXAPI
operator>>(CArchive
& ar
, CStdStringA
& strA
)
4114 inline CArchive
& AFXAPI
operator>>(CArchive
& ar
, CStdStringW
& strW
)
4121 #endif // #ifdef _MFC_VER -- (i.e. is this MFC?)
4125 // -----------------------------------------------------------------------------
4126 // GLOBAL FUNCTION: WUFormat
4127 // CStdStringA WUFormat(UINT nId, ...);
4128 // CStdStringA WUFormat(PCSTR szFormat, ...);
4131 // This function allows the caller for format and return a CStdStringA
4132 // object with a single line of code.
4133 // -----------------------------------------------------------------------------
4136 inline CStdStringA
WUFormatA(UINT nId
, ...)
4139 va_start(argList
, nId
);
4143 if ( strFmt
.Load(nId
) )
4144 strOut
.FormatV(strFmt
, argList
);
4149 inline CStdStringA
WUFormatA(PCSTR szFormat
, ...)
4152 va_start(argList
, szFormat
);
4154 strOut
.FormatV(szFormat
, argList
);
4158 inline CStdStringW
WUFormatW(UINT nId
, ...)
4161 va_start(argList
, nId
);
4165 if ( strFmt
.Load(nId
) )
4166 strOut
.FormatV(strFmt
, argList
);
4171 inline CStdStringW
WUFormatW(PCWSTR szwFormat
, ...)
4174 va_start(argList
, szwFormat
);
4176 strOut
.FormatV(szwFormat
, argList
);
4180 #endif // #ifdef SS_ANSI
4184 #if defined(SS_WIN32) && !defined (SS_ANSI)
4185 // -------------------------------------------------------------------------
4186 // FUNCTION: WUSysMessage
4187 // CStdStringA WUSysMessageA(DWORD dwError, DWORD dwLangId=SS_DEFLANGID);
4188 // CStdStringW WUSysMessageW(DWORD dwError, DWORD dwLangId=SS_DEFLANGID);
4191 // This function simplifies the process of obtaining a string equivalent
4192 // of a system error code returned from GetLastError(). You simply
4193 // supply the value returned by GetLastError() to this function and the
4194 // corresponding system string is returned in the form of a CStdStringA.
4197 // dwError - a DWORD value representing the error code to be translated
4198 // dwLangId - the language id to use. defaults to english.
4201 // a CStdStringA equivalent of the error code. Currently, this function
4202 // only returns either English of the system default language strings.
4203 // -------------------------------------------------------------------------
4204 #define SS_DEFLANGID MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT)
4205 inline CStdStringA
WUSysMessageA(DWORD dwError
, DWORD dwLangId
=SS_DEFLANGID
)
4209 if ( 0 != ::FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM
, NULL
, dwError
,
4210 dwLangId
, szBuf
, 511, NULL
) )
4211 return WUFormatA("%s (0x%X)", szBuf
, dwError
);
4213 return WUFormatA("Unknown error (0x%X)", dwError
);
4215 inline CStdStringW
WUSysMessageW(DWORD dwError
, DWORD dwLangId
=SS_DEFLANGID
)
4219 if ( 0 != ::FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM
, NULL
, dwError
,
4220 dwLangId
, szBuf
, 511, NULL
) )
4221 return WUFormatW(L
"%s (0x%X)", szBuf
, dwError
);
4223 return WUFormatW(L
"Unknown error (0x%X)", dwError
);
4227 // Define TCHAR based friendly names for some of these functions
4230 //#define CStdString CStdStringW
4231 typedef CStdStringW CStdString
;
4232 #define WUSysMessage WUSysMessageW
4233 #define WUFormat WUFormatW
4235 //#define CStdString CStdStringA
4236 typedef CStdStringA CStdString
;
4237 #define WUSysMessage WUSysMessageA
4238 #define WUFormat WUFormatA
4241 // ...and some shorter names for the space-efficient
4243 #define WUSysMsg WUSysMessage
4244 #define WUSysMsgA WUSysMessageA
4245 #define WUSysMsgW WUSysMessageW
4246 #define WUFmtA WUFormatA
4247 #define WUFmtW WUFormatW
4248 #define WUFmt WUFormat
4249 #define WULastErrMsg() WUSysMessage(::GetLastError())
4250 #define WULastErrMsgA() WUSysMessageA(::GetLastError())
4251 #define WULastErrMsgW() WUSysMessageW(::GetLastError())
4254 // -----------------------------------------------------------------------------
4255 // FUNCTIONAL COMPARATORS:
4257 // These structs are derived from the std::binary_function template. They
4258 // give us functional classes (which may be used in Standard C++ Library
4259 // collections and algorithms) that perform case-insensitive comparisons of
4260 // CStdString objects. This is useful for maps in which the key may be the
4261 // proper string but in the wrong case.
4262 // -----------------------------------------------------------------------------
4263 #define StdStringLessNoCaseW SSLNCW // avoid VC compiler warning 4786
4264 #define StdStringEqualsNoCaseW SSENCW
4265 #define StdStringLessNoCaseA SSLNCA
4266 #define StdStringEqualsNoCaseA SSENCA
4269 #define StdStringLessNoCase SSLNCW
4270 #define StdStringEqualsNoCase SSENCW
4272 #define StdStringLessNoCase SSLNCA
4273 #define StdStringEqualsNoCase SSENCA
4276 struct StdStringLessNoCaseW
4277 : std::binary_function
<CStdStringW
, CStdStringW
, bool>
4280 bool operator()(const CStdStringW
& sLeft
, const CStdStringW
& sRight
) const
4281 { return ssicmp(sLeft
.c_str(), sRight
.c_str()) < 0; }
4283 struct StdStringEqualsNoCaseW
4284 : std::binary_function
<CStdStringW
, CStdStringW
, bool>
4287 bool operator()(const CStdStringW
& sLeft
, const CStdStringW
& sRight
) const
4288 { return ssicmp(sLeft
.c_str(), sRight
.c_str()) == 0; }
4290 struct StdStringLessNoCaseA
4291 : std::binary_function
<CStdStringA
, CStdStringA
, bool>
4294 bool operator()(const CStdStringA
& sLeft
, const CStdStringA
& sRight
) const
4295 { return ssicmp(sLeft
.c_str(), sRight
.c_str()) < 0; }
4297 struct StdStringEqualsNoCaseA
4298 : std::binary_function
<CStdStringA
, CStdStringA
, bool>
4301 bool operator()(const CStdStringA
& sLeft
, const CStdStringA
& sRight
) const
4302 { return ssicmp(sLeft
.c_str(), sRight
.c_str()) == 0; }
4305 // If we had to define our own version of TRACE above, get rid of it now
4307 #ifdef TRACE_DEFINED_HERE
4309 #undef TRACE_DEFINED_HERE
4313 // These std::swap specializations come courtesy of Mike Crusader.
4317 // inline void swap(CStdStringA& s1, CStdStringA& s2) throw()
4322 // inline void swap(CStdStringW& s1, CStdStringW& s2) throw()
4328 // Turn back on any Borland warnings we turned off.
4331 #pragma option pop // Turn back on inline function warnings
4332 // #pragma warn +inl // Turn back on inline function warnings
4335 typedef std::vector
<CStdString
> CStdStringArray
;
4337 #endif // #ifndef STDSTRING_H