6 #if defined(_WIN32) && !defined(va_copy)
7 #define va_copy(dst, src) ((dst) = (src))
10 // =============================================================================
12 // AUTHOR: Joe O'Leary (with outside help noted in comments)
14 // If you find any bugs in this code, please let me know:
16 // jmoleary@earthlink.net
17 // http://www.joeo.net/stdstring.htm (a bit outdated)
19 // The latest version of this code should always be available at the
22 // http://www.joeo.net/code/StdString.zip (Dec 6, 2003)
26 // This header file declares the CStdStr template. This template derives
27 // the Standard C++ Library basic_string<> template and add to it the
28 // the following conveniences:
29 // - The full MFC CString set of functions (including implicit cast)
30 // - writing to/reading from COM IStream interfaces
31 // - Functional objects for use in STL algorithms
33 // From this template, we intstantiate two classes: CStdStringA and
34 // CStdStringW. The name "CStdString" is just a #define of one of these,
35 // based upone the UNICODE macro setting
37 // This header also declares our own version of the MFC/ATL UNICODE-MBCS
38 // conversion macros. Our version looks exactly like the Microsoft's to
39 // facilitate portability.
42 // If you you use this in an MFC or ATL build, you should include either
43 // afx.h or atlbase.h first, as appropriate.
45 // PEOPLE WHO HAVE CONTRIBUTED TO THIS CLASS:
47 // Several people have helped me iron out problems and othewise improve
48 // this class. OK, this is a long list but in my own defense, this code
49 // has undergone two major rewrites. Many of the improvements became
50 // necessary after I rewrote the code as a template. Others helped me
51 // improve the CString facade.
53 // Anyway, these people are (in chronological order):
55 // - Pete the Plumber (???)
57 // - Chris (of Melbsys)
70 // - Baptiste Lepilleur
78 // - Aaron (no last name)
79 // - Joldakowski (???)
83 // - Farrokh Nejadlotfi
93 // - Bagira (full name?)
106 // 2005-JAN-10 - Thanks to Don Beusee for pointing out the danger in mapping
107 // length-checked formatting functions to non-length-checked
108 // CRT equivalents. Also thanks to him for motivating me to
109 // optimize my implementation of Replace()
111 // 2004-APR-22 - A big, big thank you to "MKingman" (whoever you are) for
112 // finally spotting a silly little error in StdCodeCvt that
113 // has been causing me (and users of CStdString) problems for
114 // years in some relatively rare conversions. I had reversed
115 // two length arguments.
117 // 2003-NOV-24 - Thanks to a bunch of people for helping me clean up many
118 // compiler warnings (and yes, even a couple of actual compiler
119 // errors). These include Henk Demper for figuring out how
120 // to make the Intellisense work on with CStdString on VC6,
121 // something I was never able to do. Greg Marr pointed out
122 // a compiler warning about an unreferenced symbol and a
123 // problem with my version of Load in MFC builds. Bill
124 // Carducci took a lot of time with me to help me figure out
125 // why some implementations of the Standard C++ Library were
126 // returning error codes for apparently successful conversions
127 // between ASCII and UNICODE. Finally thanks to Brian Groose
128 // for helping me fix compiler signed unsigned warnings in
129 // several functions.
131 // 2003-JUL-10 - Thanks to Charles Godwin for making me realize my 'FmtArg'
132 // fixes had inadvertently broken the DLL-export code (which is
133 // normally commented out. I had to move it up higher. Also
134 // this helped me catch a bug in ssicoll that would prevent
135 // compilation, otherwise.
137 // 2003-MAR-14 - Thanks to Jakko Van Hunen for pointing out a copy-and-paste
138 // bug in one of the overloads of FmtArg.
140 // 2003-MAR-10 - Thanks to Ronny Schulz for (twice!) sending me some changes
141 // to help CStdString build on SGI and for pointing out an
142 // error in placement of my preprocessor macros for ssfmtmsg.
144 // 2002-NOV-26 - Thanks to Bagira for pointing out that my implementation of
145 // SpanExcluding was not properly handling the case in which
146 // the string did NOT contain any of the given characters
148 // 2002-OCT-21 - Many thanks to Paul DeMarco who was invaluable in helping me
149 // get this code working with Borland's free compiler as well
150 // as the Dev-C++ compiler (available free at SourceForge).
152 // 2002-SEP-13 - Thanks to Glen Maynard who helped me get rid of some loud
153 // but harmless warnings that were showing up on g++. Glen
154 // also pointed out that some pre-declarations of FmtArg<>
155 // specializations were unnecessary (and no good on G++)
157 // 2002-JUN-26 - Thanks to Arnt Witteveen for pointing out that I was using
158 // static_cast<> in a place in which I should have been using
159 // reinterpret_cast<> (the ctor for unsigned char strings).
160 // That's what happens when I don't unit-test properly!
161 // Arnt also noticed that CString was silently correcting the
162 // 'nCount' argument to Left() and Right() where CStdString was
163 // not (and crashing if it was bad). That is also now fixed!
165 // 2002-FEB-25 - Thanks to Tim Dowty for pointing out (and giving me the fix
166 // for) a conversion problem with non-ASCII MBCS characters.
167 // CStdString is now used in my favorite commercial MP3 player!
169 // 2001-DEC-06 - Thanks to Wang Haifeng for spotting a problem in one of the
170 // assignment operators (for _bstr_t) that would cause compiler
171 // errors when refcounting protection was turned off.
173 // 2001-NOV-27 - Remove calls to operator!= which involve reverse_iterators
174 // due to a conflict with the rel_ops operator!=. Thanks to
175 // John James for pointing this out.
177 // 2001-OCT-29 - Added a minor range checking fix for the Mid function to
178 // make it as forgiving as CString's version is. Thanks to
179 // Igor Kholodov for noticing this.
180 // - Added a specialization of std::swap for CStdString. Thanks
181 // to Mike Crusader for suggesting this! It's commented out
182 // because you're not supposed to inject your own code into the
183 // 'std' namespace. But if you don't care about that, it's
184 // there if you want it
185 // - Thanks to Jason Mills for catching a case where CString was
186 // more forgiving in the Delete() function than I was.
188 // 2001-JUN-06 - I was violating the Standard name lookup rules stated
189 // in [14.6.2(3)]. None of the compilers I've tried so
190 // far apparently caught this but HP-UX aCC 3.30 did. The
191 // fix was to add 'this->' prefixes in many places.
192 // Thanks to Farrokh Nejadlotfi for this!
194 // 2001-APR-27 - StreamLoad was calculating the number of BYTES in one
195 // case, not characters. Thanks to Pablo Presedo for this.
197 // 2001-FEB-23 - Replace() had a bug which caused infinite loops if the
198 // source string was empty. Fixed thanks to Eric Nitzsche.
200 // 2001-FEB-23 - Scott Hathaway was a huge help in providing me with the
201 // ability to build CStdString on Sun Unix systems. He
202 // sent me detailed build reports about what works and what
203 // does not. If CStdString compiles on your Unix box, you
204 // can thank Scott for it.
206 // 2000-DEC-29 - Joldakowski noticed one overload of Insert failed to do a
207 // range check as CString's does. Now fixed -- thanks!
209 // 2000-NOV-07 - Aaron pointed out that I was calling static member
210 // functions of char_traits via a temporary. This was not
211 // technically wrong, but it was unnecessary and caused
212 // problems for poor old buggy VC5. Thanks Aaron!
214 // 2000-JUL-11 - Joe Woodbury noted that the CString::Find docs don't match
215 // what the CString::Find code really ends up doing. I was
216 // trying to match the docs. Now I match the CString code
217 // - Joe also caught me truncating strings for GetBuffer() calls
218 // when the supplied length was less than the current length.
220 // 2000-MAY-25 - Better support for STLPORT's Standard library distribution
221 // - Got rid of the NSP macro - it interfered with Koenig lookup
222 // - Thanks to Joe Woodbury for catching a TrimLeft() bug that
223 // I introduced in January. Empty strings were not getting
226 // 2000-APR-17 - Thanks to Joe Vitaterna for pointing out that ReverseFind
227 // is supposed to be a const function.
229 // 2000-MAR-07 - Thanks to Ullrich Poll�hne for catching a range bug in one
230 // of the overloads of assign.
232 // 2000-FEB-01 - You can now use CStdString on the Mac with CodeWarrior!
233 // Thanks to Todd Heckel for helping out with this.
235 // 2000-JAN-23 - Thanks to Jim Cline for pointing out how I could make the
236 // Trim() function more efficient.
237 // - Thanks to Jeff Kohn for prompting me to find and fix a typo
238 // in one of the addition operators that takes _bstr_t.
239 // - Got rid of the .CPP file - you only need StdString.h now!
241 // 1999-DEC-22 - Thanks to Greg Pickles for helping me identify a problem
242 // with my implementation of CStdString::FormatV in which
243 // resulting string might not be properly NULL terminated.
245 // 1999-DEC-06 - Chris Conti pointed yet another basic_string<> assignment
246 // bug that MS has not fixed. CStdString did nothing to fix
247 // it either but it does now! The bug was: create a string
248 // longer than 31 characters, get a pointer to it (via c_str())
249 // and then assign that pointer to the original string object.
250 // The resulting string would be empty. Not with CStdString!
252 // 1999-OCT-06 - BufferSet was erasing the string even when it was merely
253 // supposed to shrink it. Fixed. Thanks to Chris Conti.
254 // - Some of the Q172398 fixes were not checking for assignment-
255 // to-self. Fixed. Thanks to Baptiste Lepilleur.
257 // 1999-AUG-20 - Improved Load() function to be more efficient by using
258 // SizeOfResource(). Thanks to Rich Zuris for this.
259 // - Corrected resource ID constructor, again thanks to Rich.
260 // - Fixed a bug that occurred with UNICODE characters above
261 // the first 255 ANSI ones. Thanks to Craig Watson.
262 // - Added missing overloads of TrimLeft() and TrimRight().
263 // Thanks to Karim Ratib for pointing them out
265 // 1999-JUL-21 - Made all calls to GetBuf() with no args check length first.
267 // 1999-JUL-10 - Improved MFC/ATL independence of conversion macros
268 // - Added SS_NO_REFCOUNT macro to allow you to disable any
269 // reference-counting your basic_string<> impl. may do.
270 // - Improved ReleaseBuffer() to be as forgiving as CString.
271 // Thanks for Fan Xia for helping me find this and to
272 // Matthew Williams for pointing it out directly.
274 // 1999-JUL-06 - Thanks to Nigel Nunn for catching a very sneaky bug in
275 // ToLower/ToUpper. They should call GetBuf() instead of
276 // data() in order to ensure the changed string buffer is not
277 // reference-counted (in those implementations that refcount).
279 // 1999-JUL-01 - Added a true CString facade. Now you can use CStdString as
280 // a drop-in replacement for CString. If you find this useful,
281 // you can thank Chris Sells for finally convincing me to give
282 // in and implement it.
283 // - Changed operators << and >> (for MFC CArchive) to serialize
284 // EXACTLY as CString's do. So now you can send a CString out
285 // to a CArchive and later read it in as a CStdString. I have
286 // no idea why you would want to do this but you can.
288 // 1999-JUN-21 - Changed the CStdString class into the CStdStr template.
289 // - Fixed FormatV() to correctly decrement the loop counter.
290 // This was harmless bug but a bug nevertheless. Thanks to
291 // Chris (of Melbsys) for pointing it out
292 // - Changed Format() to try a normal stack-based array before
293 // using to _alloca().
294 // - Updated the text conversion macros to properly use code
295 // pages and to fit in better in MFC/ATL builds. In other
296 // words, I copied Microsoft's conversion stuff again.
297 // - Added equivalents of CString::GetBuffer, GetBufferSetLength
298 // - new sscpy() replacement of CStdString::CopyString()
299 // - a Trim() function that combines TrimRight() and TrimLeft().
301 // 1999-MAR-13 - Corrected the "NotSpace" functional object to use _istpace()
302 // instead of _isspace() Thanks to Dave Plummer for this.
304 // 1999-FEB-26 - Removed errant line (left over from testing) that #defined
305 // _MFC_VER. Thanks to John C Sipos for noticing this.
307 // 1999-FEB-03 - Fixed a bug in a rarely-used overload of operator+() that
308 // caused infinite recursion and stack overflow
309 // - Added member functions to simplify the process of
310 // persisting CStdStrings to/from DCOM IStream interfaces
311 // - Added functional objects (e.g. StdStringLessNoCase) that
312 // allow CStdStrings to be used as keys STL map objects with
313 // case-insensitive comparison
314 // - Added array indexing operators (i.e. operator[]). I
315 // originally assumed that these were unnecessary and would be
316 // inherited from basic_string. However, without them, Visual
317 // C++ complains about ambiguous overloads when you try to use
318 // them. Thanks to Julian Selman to pointing this out.
320 // 1998-FEB-?? - Added overloads of assign() function to completely account
321 // for Q172398 bug. Thanks to "Pete the Plumber" for this
323 // 1998-FEB-?? - Initial submission
326 // 2002 Joseph M. O'Leary. This code is 100% free. Use it anywhere you
327 // want. Rewrite it, restructure it, whatever. If you can write software
328 // that makes money off of it, good for you. I kinda like capitalism.
329 // Please don't blame me if it causes your $30 billion dollar satellite
330 // explode in orbit. If you redistribute it in any form, I'd appreciate it
331 // if you would leave this notice here.
332 // =============================================================================
334 // Avoid multiple inclusion
339 // When using VC, turn off browser references
340 // Turn off unavoidable compiler warnings
342 #if defined(_MSC_VER) && (_MSC_VER > 1100)
343 #pragma component(browser, off, references, "CStdString")
344 #pragma warning (disable : 4290) // C++ Exception Specification ignored
345 #pragma warning (disable : 4127) // Conditional expression is constant
346 #pragma warning (disable : 4097) // typedef name used as synonym for class name
349 // Borland warnings to turn off
352 #pragma option push -w-inl
353 // #pragma warn -inl // Turn off inline function warnings
358 // A copy of IS_INTRESOURCE from VC7. Because old VC6 version of winuser.h
359 // doesn't have this.
361 #define SS_IS_INTRESOURCE(_r) (false)
363 #if !defined (SS_ANSI) && defined(_MSC_VER)
364 #undef SS_IS_INTRESOURCE
366 #define SS_IS_INTRESOURCE(_r) (((unsigned __int64)(_r) >> 16) == 0)
368 #define SS_IS_INTRESOURCE(_r) (((unsigned long)(_r) >> 16) == 0)
373 // MACRO: SS_UNSIGNED
374 // ------------------
375 // This macro causes the addition of a constructor and assignment operator
376 // which take unsigned characters. CString has such functions and in order
377 // to provide maximum CString-compatability, this code needs them as well.
378 // In practice you will likely never need these functions...
380 //#define SS_UNSIGNED
382 #ifdef SS_ALLOW_UNSIGNED_CHARS
386 // MACRO: SS_SAFE_FORMAT
387 // ---------------------
388 // This macro provides limited compatability with a questionable CString
389 // "feature". You can define it in order to avoid a common problem that
390 // people encounter when switching from CString to CStdString.
392 // To illustrate the problem -- With CString, you can do this:
394 // CString sName("Joe");
396 // sTmp.Format("My name is %s", sName); // WORKS!
398 // However if you were to try this with CStdString, your program would
401 // CStdString sName("Joe");
403 // sTmp.Format("My name is %s", sName); // CRASHES!
405 // You must explicitly call c_str() or cast the object to the proper type
407 // sTmp.Format("My name is %s", sName.c_str()); // WORKS!
408 // sTmp.Format("My name is %s", static_cast<PCSTR>(sName));// WORKS!
409 // sTmp.Format("My name is %s", (PCSTR)sName); // WORKS!
411 // This is because it is illegal to pass anything but a POD type as a
412 // variadic argument to a variadic function (i.e. as one of the "..."
413 // arguments). The type const char* is a POD type. The type CStdString
414 // is not. Of course, neither is the type CString, but CString lets you do
415 // it anyway due to the way they laid out the class in binary. I have no
416 // control over this in CStdString since I derive from whatever
417 // implementation of basic_string is available.
419 // However if you have legacy code (which does this) that you want to take
420 // out of the MFC world and you don't want to rewrite all your calls to
421 // Format(), then you can define this flag and it will no longer crash.
423 // Note however that this ONLY works for Format(), not sprintf, fprintf,
424 // etc. If you pass a CStdString object to one of those functions, your
425 // program will crash. Not much I can do to get around this, short of
426 // writing substitutes for those functions as well.
428 #define SS_SAFE_FORMAT // use new template style Format() function
431 // MACRO: SS_NO_IMPLICIT_CAST
432 // --------------------------
433 // Some people don't like the implicit cast to const char* (or rather to
434 // const CT*) that CStdString (and MFC's CString) provide. That was the
435 // whole reason I created this class in the first place, but hey, whatever
436 // bakes your cake. Just #define this macro to get rid of the the implicit
439 //#define SS_NO_IMPLICIT_CAST // gets rid of operator const CT*()
442 // MACRO: SS_NO_REFCOUNT
443 // ---------------------
444 // turns off reference counting at the assignment level. Only needed
445 // for the version of basic_string<> that comes with Visual C++ versions
446 // 6.0 or earlier, and only then in some heavily multithreaded scenarios.
447 // Uncomment it if you feel you need it.
449 //#define SS_NO_REFCOUNT
453 // When this flag is set, we are building code for the Win32 platform and
454 // may use Win32 specific functions (such as LoadString). This gives us
455 // a couple of nice extras for the code.
457 // Obviously, Microsoft's is not the only compiler available for Win32 out
458 // there. So I can't just check to see if _MSC_VER is defined to detect
459 // if I'm building on Win32. So for now, if you use MS Visual C++ or
460 // Borland's compiler, I turn this on. Otherwise you may turn it on
461 // yourself, if you prefer
463 #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(_WIN32)
469 // When this macro is defined, the code attempts only to use ANSI/ISO
470 // standard library functions to do it's work. It will NOT attempt to use
471 // any Win32 of Visual C++ specific functions -- even if they are
472 // available. You may define this flag yourself to prevent any Win32
473 // of VC++ specific functions from being called.
475 // If we're not on Win32, we MUST use an ANSI build
478 #if !defined(SS_NO_ANSI)
485 // Some implementations of the Standard C Library have a non-standard
486 // function known as alloca(). This functions allows one to allocate a
487 // variable amount of memory on the stack. It is needed to implement
488 // the ASCII/MBCS conversion macros.
490 // I wanted to find some way to determine automatically if alloca() is
491 // available on this platform via compiler flags but that is asking for
492 // trouble. The crude test presented here will likely need fixing on
493 // other platforms. Therefore I'll leave it up to you to fiddle with
494 // this test to determine if it exists. Just make sure SS_ALLOCA is or
495 // is not defined as appropriate and you control this feature.
497 #if defined(_MSC_VER) && !defined(SS_ANSI)
504 // Setting this macro means you are using MBCS characters. In MSVC builds,
505 // this macro gets set automatically by detection of the preprocessor flag
506 // _MBCS. For other platforms you may set it manually if you wish. The
507 // only effect it currently has is to cause the allocation of more space
508 // for wchar_t --> char conversions.
509 // Note that MBCS does not mean UNICODE.
519 // MACRO SS_NO_LOCALE
520 // ------------------
521 // If your implementation of the Standard C++ Library lacks the <locale> header,
522 // you can #define this macro to make your code build properly. Note that this
523 // is some of my newest code and frankly I'm not very sure of it, though it does
524 // pass my unit tests.
526 // #define SS_NO_LOCALE
529 // Compiler Error regarding _UNICODE and UNICODE
530 // -----------------------------------------------
531 // Microsoft header files are screwy. Sometimes they depend on a preprocessor
532 // flag named "_UNICODE". Other times they check "UNICODE" (note the lack of
533 // leading underscore in the second version". In several places, they silently
534 // "synchronize" these two flags this by defining one of the other was defined.
535 // In older version of this header, I used to try to do the same thing.
537 // However experience has taught me that this is a bad idea. You get weird
538 // compiler errors that seem to indicate things like LPWSTR and LPTSTR not being
539 // equivalent in UNICODE builds, stuff like that (when they MUST be in a proper
540 // UNICODE build). You end up scratching your head and saying, "But that HAS
543 // So what should you do if you get this error?
545 // Make sure that both macros (_UNICODE and UNICODE) are defined before this
546 // file is included. You can do that by either
548 // a) defining both yourself before any files get included
549 // b) including the proper MS headers in the proper order
550 // c) including this file before any other file, uncommenting
551 // the #defines below, and commenting out the #errors
553 // Personally I recommend solution a) but it's your call.
556 #if defined (_UNICODE) && !defined (UNICODE)
557 #error UNICODE defined but not UNICODE
558 // #define UNICODE // no longer silently fix this
560 #if defined (UNICODE) && !defined (_UNICODE)
561 #error Warning, UNICODE defined but not _UNICODE
562 // #define _UNICODE // no longer silently fix this
567 // -----------------------------------------------------------------------------
568 // MIN and MAX. The Standard C++ template versions go by so many names (at
569 // at least in the MS implementation) that you never know what's available
570 // -----------------------------------------------------------------------------
572 inline const Type
& SSMIN(const Type
& arg1
, const Type
& arg2
)
574 return arg2
< arg1
? arg2
: arg1
;
577 inline const Type
& SSMAX(const Type
& arg1
, const Type
& arg2
)
579 return arg2
> arg1
? arg2
: arg1
;
582 // If they have not #included W32Base.h (part of my W32 utility library) then
583 // we need to define some stuff. Otherwise, this is all defined there.
585 #if !defined(W32BASE_H)
587 // If they want us to use only standard C++ stuff (no Win32 stuff)
591 // On Win32 we have TCHAR.H so just include it. This is NOT violating
592 // the spirit of SS_ANSI as we are not calling any Win32 functions here.
602 // ... but on non-Win32 platforms, we must #define the types we need.
606 typedef const char* PCSTR
;
608 typedef const wchar_t* PCWSTR
;
609 typedef wchar_t* PWSTR
;
611 typedef wchar_t TCHAR
;
615 typedef wchar_t OLECHAR
;
617 #endif // #ifndef _WIN32
620 // Make sure ASSERT and verify are defined using only ANSI stuff
624 #define ASSERT(f) assert((f))
628 #define VERIFY(x) ASSERT((x))
634 #else // ...else SS_ANSI is NOT defined
642 // Make sure ASSERT and verify are defined
646 #define ASSERT(f) _ASSERTE((f))
650 #define VERIFY(x) ASSERT((x))
656 #endif // #ifdef SS_ANSI
662 #endif // #ifndef W32BASE_H
664 // Standard headers needed
666 #include <string> // basic_string
667 #include <algorithm> // for_each, etc.
668 #include <functional> // for StdStringLessNoCase, et al
670 #include <locale> // for various facets
673 // If this is a recent enough version of VC include comdef.h, so we can write
674 // member functions to deal with COM types & compiler support classes e.g.
677 #if defined (_MSC_VER) && (_MSC_VER >= 1100)
679 #define SS_INC_COMDEF // signal that we #included MS comdef.h file
680 #define STDSTRING_INC_COMDEF
681 #define SS_NOTHROW __declspec(nothrow)
687 #define TRACE_DEFINED_HERE
691 // Microsoft defines PCSTR, PCWSTR, etc, but no PCTSTR. I hate to use the
692 // versions with the "L" in front of them because that's a leftover from Win 16
693 // days, even though it evaluates to the same thing. Therefore, Define a PCSTR
696 #if !defined(PCTSTR) && !defined(PCTSTR_DEFINED)
697 typedef const TCHAR
* PCTSTR
;
698 #define PCTSTR_DEFINED
701 #if !defined(PCOLESTR) && !defined(PCOLESTR_DEFINED)
702 typedef const OLECHAR
* PCOLESTR
;
703 #define PCOLESTR_DEFINED
706 #if !defined(POLESTR) && !defined(POLESTR_DEFINED)
707 typedef OLECHAR
* POLESTR
;
708 #define POLESTR_DEFINED
711 #if !defined(PCUSTR) && !defined(PCUSTR_DEFINED)
712 typedef const unsigned char* PCUSTR
;
713 typedef unsigned char* PUSTR
;
714 #define PCUSTR_DEFINED
718 // SGI compiler 7.3 doesnt know these types - oh and btw, remember to use
719 // -LANG:std in the CXX Flags
721 typedef unsigned long DWORD
;
722 typedef void * LPCVOID
;
726 // SS_USE_FACET macro and why we need it:
728 // Since I'm a good little Standard C++ programmer, I use locales. Thus, I
729 // need to make use of the use_facet<> template function here. Unfortunately,
730 // this need is complicated by the fact the MS' implementation of the Standard
731 // C++ Library has a non-standard version of use_facet that takes more
732 // arguments than the standard dictates. Since I'm trying to write CStdString
733 // to work with any version of the Standard library, this presents a problem.
735 // The upshot of this is that I can't do 'use_facet' directly. The MS' docs
736 // tell me that I have to use a macro, _USE() instead. Since _USE obviously
737 // won't be available in other implementations, this means that I have to write
738 // my OWN macro -- SS_USE_FACET -- that evaluates either to _USE or to the
739 // standard, use_facet.
741 // If you are having trouble with the SS_USE_FACET macro, in your implementation
742 // of the Standard C++ Library, you can define your own version of SS_USE_FACET.
746 #define schSTR2(x) schSTR(x)
747 #define schMSG(desc) message(__FILE__ "(" schSTR2(__LINE__) "):" #desc)
752 // STLPort #defines a macro (__STL_NO_EXPLICIT_FUNCTION_TMPL_ARGS) for
753 // all MSVC builds, erroneously in my opinion. It causes problems for
754 // my SS_ANSI builds. In my code, I always comment out that line. You'll
755 // find it in \stlport\config\stl_msvc.h
757 #if defined(__SGI_STL_PORT) && (__SGI_STL_PORT >= 0x400 )
759 #if defined(__STL_NO_EXPLICIT_FUNCTION_TMPL_ARGS) && defined(_MSC_VER)
761 #pragma schMSG(__STL_NO_EXPLICIT_FUNCTION_TMPL_ARGS defined!!)
764 #define SS_USE_FACET(loc, fac) std::use_facet<fac >(loc)
766 #elif defined(_MSC_VER )
768 #define SS_USE_FACET(loc, fac) std::_USE(loc, fac)
771 #elif defined(_RWSTD_NO_TEMPLATE_ON_RETURN_TYPE)
773 #define SS_USE_FACET(loc, fac) std::use_facet(loc, (fac*)0)
777 #define SS_USE_FACET(loc, fac) std::use_facet<fac >(loc)
783 // =============================================================================
784 // UNICODE/MBCS conversion macros. Made to work just like the MFC/ATL ones.
785 // =============================================================================
787 #include <wchar.h> // Added to Std Library with Amendment #1.
789 // First define the conversion helper functions. We define these regardless of
790 // any preprocessor macro settings since their names won't collide.
792 // Not sure if we need all these headers. I believe ANSI says we do.
806 #if defined(_WIN32) || defined (_WIN32_WCE)
808 inline PWSTR
StdCodeCvt(PWSTR pDstW
, int nDst
, PCSTR pSrcA
, int nSrc
,
814 MultiByteToWideChar(acp
, 0, pSrcA
, nSrc
, pDstW
, nDst
);
817 inline PWSTR
StdCodeCvt(PWSTR pDstW
, int nDst
, PCUSTR pSrcA
, int nSrc
,
820 return StdCodeCvt(pDstW
, nDst
, (PCSTR
)pSrcA
, nSrc
, acp
);
823 inline PSTR
StdCodeCvt(PSTR pDstA
, int nDst
, PCWSTR pSrcW
, int nSrc
,
829 WideCharToMultiByte(acp
, 0, pSrcW
, nSrc
, pDstA
, nDst
, 0, 0);
832 inline PUSTR
StdCodeCvt(PUSTR pDstA
, int nDst
, PCWSTR pSrcW
, int nSrc
,
835 return (PUSTR
)StdCodeCvt((PSTR
)pDstA
, nDst
, pSrcW
, nSrc
, acp
);
842 // StdCodeCvt - made to look like Win32 functions WideCharToMultiByte
843 // and MultiByteToWideChar but uses locales in SS_ANSI
844 // builds. There are a number of overloads.
845 // First argument is the destination buffer.
846 // Second argument is the source buffer
847 //#if defined (SS_ANSI) || !defined (SS_WIN32)
849 // 'SSCodeCvt' - shorthand name for the codecvt facet we use
851 typedef std::codecvt
<wchar_t, char, mbstate_t> SSCodeCvt
;
853 inline PWSTR
StdCodeCvt(PWSTR pDstW
, int nDst
, PCSTR pSrcA
, int nSrc
,
854 const std::locale
& loc
=std::locale())
863 PCSTR pNextSrcA
= pSrcA
;
864 PWSTR pNextDstW
= pDstW
;
865 SSCodeCvt::result res
= SSCodeCvt::ok
;
866 const SSCodeCvt
& conv
= SS_USE_FACET(loc
, SSCodeCvt
);
867 SSCodeCvt::state_type st
= { 0 };
869 pSrcA
, pSrcA
+ nSrc
, pNextSrcA
,
870 pDstW
, pDstW
+ nDst
, pNextDstW
);
872 #define ASSERT2(a) if (!(a)) {fprintf(stderr, "StdString: Assertion Failed on line %d\n", __LINE__);}
874 #define ASSERT2 ASSERT
876 ASSERT2(SSCodeCvt::ok
== res
);
877 ASSERT2(SSCodeCvt::error
!= res
);
878 ASSERT2(pNextDstW
>= pDstW
);
879 ASSERT2(pNextSrcA
>= pSrcA
);
881 // Null terminate the converted string
883 if ( pNextDstW
- pDstW
> nDst
)
884 *(pDstW
+ nDst
) = '\0';
890 inline PWSTR
StdCodeCvt(PWSTR pDstW
, int nDst
, PCUSTR pSrcA
, int nSrc
,
891 const std::locale
& loc
=std::locale())
893 return StdCodeCvt(pDstW
, nDst
, (PCSTR
)pSrcA
, nSrc
, loc
);
896 inline PSTR
StdCodeCvt(PSTR pDstA
, int nDst
, PCWSTR pSrcW
, int nSrc
,
897 const std::locale
& loc
=std::locale())
906 PSTR pNextDstA
= pDstA
;
907 PCWSTR pNextSrcW
= pSrcW
;
908 SSCodeCvt::result res
= SSCodeCvt::ok
;
909 const SSCodeCvt
& conv
= SS_USE_FACET(loc
, SSCodeCvt
);
910 SSCodeCvt::state_type st
= { 0 };
912 pSrcW
, pSrcW
+ nSrc
, pNextSrcW
,
913 pDstA
, pDstA
+ nDst
, pNextDstA
);
915 #define ASSERT2(a) if (!(a)) {fprintf(stderr, "StdString: Assertion Failed on line %d\n", __LINE__);}
917 #define ASSERT2 ASSERT
919 ASSERT2(SSCodeCvt::error
!= res
);
920 ASSERT2(SSCodeCvt::ok
== res
); // strict, comment out for sanity
921 ASSERT2(pNextDstA
>= pDstA
);
922 ASSERT2(pNextSrcW
>= pSrcW
);
925 // Null terminate the converted string
927 if ( pNextDstA
- pDstA
> nDst
)
928 *(pDstA
+ nDst
) = '\0';
935 inline PUSTR
StdCodeCvt(PUSTR pDstA
, int nDst
, PCWSTR pSrcW
, int nSrc
,
936 const std::locale
& loc
=std::locale())
938 return (PUSTR
)StdCodeCvt((PSTR
)pDstA
, nDst
, pSrcW
, nSrc
, loc
);
945 // Unicode/MBCS conversion macros are only available on implementations of
946 // the "C" library that have the non-standard _alloca function. As far as I
947 // know that's only Microsoft's though I've heard that the function exists
950 #if defined(SS_ALLOCA) && !defined SS_NO_CONVERSION
952 #include <malloc.h> // needed for _alloca
954 // Define our conversion macros to look exactly like Microsoft's to
955 // facilitate using this stuff both with and without MFC/ATL
957 #ifdef _CONVERSION_USES_THREAD_LOCALE
960 #define SSCVT int _cvt; _cvt; UINT _acp=GetACP(); \
961 _acp; PCWSTR _pw; _pw; PCSTR _pa; _pa
963 #define SSCVT int _cvt = 0; _cvt; UINT _acp=GetACP();\
964 _acp; PCWSTR _pw=0; _pw; PCSTR _pa=0; _pa
967 ((_pa = pa) == 0) ? 0 : (\
968 _cvt = (sslen(_pa)),\
969 StdCodeCvt((PWSTR) _alloca((_cvt+1)*2), (_cvt+1)*2, \
972 ((_pw = pw) == 0) ? 0 : (\
974 StdCodeCvt((LPSTR) _alloca((_cvt+1)*2), (_cvt+1)*2, \
979 #define SSCVT int _cvt; _cvt; UINT _acp=CP_ACP; _acp;\
980 PCWSTR _pw; _pw; PCSTR _pa; _pa
982 #define SSCVT int _cvt = 0; _cvt; UINT _acp=CP_ACP; \
983 _acp; PCWSTR _pw=0; _pw; PCSTR _pa=0; _pa
986 ((_pa = pa) == 0) ? 0 : (\
987 _cvt = (sslen(_pa)),\
988 StdCodeCvt((PWSTR) _alloca((_cvt+1)*2), (_cvt+1)*2, \
991 ((_pw = pw) == 0) ? 0 : (\
992 _cvt = (sslen(_pw)),\
993 StdCodeCvt((LPSTR) _alloca((_cvt+1)*2), (_cvt+1)*2, \
997 #define SSA2CW(pa) ((PCWSTR)SSA2W((pa)))
998 #define SSW2CA(pw) ((PCSTR)SSW2A((pw)))
1003 #define SST2CA SSW2CA
1004 #define SSA2CT SSA2CW
1005 // (Did you get a compiler error here about not being able to convert
1006 // PTSTR into PWSTR? Then your _UNICODE and UNICODE flags are messed
1007 // up. Best bet: #define BOTH macros before including any MS headers.)
1008 inline PWSTR
SST2W(PTSTR p
) { return p
; }
1009 inline PTSTR
SSW2T(PWSTR p
) { return p
; }
1010 inline PCWSTR
SST2CW(PCTSTR p
) { return p
; }
1011 inline PCTSTR
SSW2CT(PCWSTR p
) { return p
; }
1015 #define SST2CW SSA2CW
1016 #define SSW2CT SSW2CA
1017 inline PSTR
SST2A(PTSTR p
) { return p
; }
1018 inline PTSTR
SSA2T(PSTR p
) { return p
; }
1019 inline PCSTR
SST2CA(PCTSTR p
) { return p
; }
1020 inline PCTSTR
SSA2CT(PCSTR p
) { return p
; }
1021 #endif // #ifdef UNICODE
1023 #if defined(UNICODE)
1024 // in these cases the default (TCHAR) is the same as OLECHAR
1025 inline PCOLESTR
SST2COLE(PCTSTR p
) { return p
; }
1026 inline PCTSTR
SSOLE2CT(PCOLESTR p
) { return p
; }
1027 inline POLESTR
SST2OLE(PTSTR p
) { return p
; }
1028 inline PTSTR
SSOLE2T(POLESTR p
) { return p
; }
1029 #elif defined(OLE2ANSI)
1030 // in these cases the default (TCHAR) is the same as OLECHAR
1031 inline PCOLESTR
SST2COLE(PCTSTR p
) { return p
; }
1032 inline PCTSTR
SSOLE2CT(PCOLESTR p
) { return p
; }
1033 inline POLESTR
SST2OLE(PTSTR p
) { return p
; }
1034 inline PTSTR
SSOLE2T(POLESTR p
) { return p
; }
1036 //CharNextW doesn't work on Win95 so we use this
1037 #define SST2COLE(pa) SSA2CW((pa))
1038 #define SST2OLE(pa) SSA2W((pa))
1039 #define SSOLE2CT(po) SSW2CA((po))
1040 #define SSOLE2T(po) SSW2A((po))
1044 #define SSW2OLE SSW2A
1045 #define SSOLE2W SSA2W
1046 #define SSW2COLE SSW2CA
1047 #define SSOLE2CW SSA2CW
1048 inline POLESTR
SSA2OLE(PSTR p
) { return p
; }
1049 inline PSTR
SSOLE2A(POLESTR p
) { return p
; }
1050 inline PCOLESTR
SSA2COLE(PCSTR p
) { return p
; }
1051 inline PCSTR
SSOLE2CA(PCOLESTR p
){ return p
; }
1053 #define SSA2OLE SSA2W
1054 #define SSOLE2A SSW2A
1055 #define SSA2COLE SSA2CW
1056 #define SSOLE2CA SSW2CA
1057 inline POLESTR
SSW2OLE(PWSTR p
) { return p
; }
1058 inline PWSTR
SSOLE2W(POLESTR p
) { return p
; }
1059 inline PCOLESTR
SSW2COLE(PCWSTR p
) { return p
; }
1060 inline PCWSTR
SSOLE2CW(PCOLESTR p
){ return p
; }
1063 // Above we've defined macros that look like MS' but all have
1064 // an 'SS' prefix. Now we need the real macros. We'll either
1065 // get them from the macros above or from MFC/ATL.
1067 #if defined (USES_CONVERSION)
1069 #define _NO_STDCONVERSION // just to be consistent
1075 #include <afxconv.h>
1076 #define _NO_STDCONVERSION // just to be consistent
1080 #define USES_CONVERSION SSCVT
1091 #define ocslen sslen
1092 #define ocscpy sscpy
1093 #define T2COLE SST2COLE
1094 #define OLE2CT SSOLE2CT
1095 #define T2OLE SST2COLE
1096 #define OLE2T SSOLE2CT
1097 #define A2OLE SSA2OLE
1098 #define OLE2A SSOLE2A
1099 #define W2OLE SSW2OLE
1100 #define OLE2W SSOLE2W
1101 #define A2COLE SSA2COLE
1102 #define OLE2CA SSOLE2CA
1103 #define W2COLE SSW2COLE
1104 #define OLE2CW SSOLE2CW
1106 #endif // #ifdef _MFC_VER
1107 #endif // #ifndef USES_CONVERSION
1108 #endif // #ifndef SS_NO_CONVERSION
1110 // Define ostring - generic name for std::basic_string<OLECHAR>
1112 #if !defined(ostring) && !defined(OSTRING_DEFINED)
1113 typedef std::basic_string
<OLECHAR
> ostring
;
1114 #define OSTRING_DEFINED
1117 // StdCodeCvt when there's no conversion to be done
1118 template <typename T
>
1119 inline T
* StdCodeCvt(T
* pDst
, int nDst
, const T
* pSrc
, int nSrc
)
1121 int nChars
= SSMIN(nSrc
, nDst
);
1126 std::basic_string
<T
>::traits_type::copy(pDst
, pSrc
, nChars
);
1127 // std::char_traits<T>::copy(pDst, pSrc, nChars);
1128 pDst
[nChars
] = '\0';
1133 inline PSTR
StdCodeCvt(PSTR pDst
, int nDst
, PCUSTR pSrc
, int nSrc
)
1135 return StdCodeCvt(pDst
, nDst
, (PCSTR
)pSrc
, nSrc
);
1137 inline PUSTR
StdCodeCvt(PUSTR pDst
, int nDst
, PCSTR pSrc
, int nSrc
)
1139 return (PUSTR
)StdCodeCvt((PSTR
)pDst
, nDst
, pSrc
, nSrc
);
1142 // Define tstring -- generic name for std::basic_string<TCHAR>
1144 #if !defined(tstring) && !defined(TSTRING_DEFINED)
1145 typedef std::basic_string
<TCHAR
> tstring
;
1146 #define TSTRING_DEFINED
1149 // a very shorthand way of applying the fix for KB problem Q172398
1150 // (basic_string assignment bug)
1152 #if defined ( _MSC_VER ) && ( _MSC_VER < 1200 )
1153 #define Q172398(x) (x).erase()
1158 // =============================================================================
1159 // INLINE FUNCTIONS ON WHICH CSTDSTRING RELIES
1161 // Usually for generic text mapping, we rely on preprocessor macro definitions
1162 // to map to string functions. However the CStdStr<> template cannot use
1163 // macro-based generic text mappings because its character types do not get
1164 // resolved until template processing which comes AFTER macro processing. In
1165 // other words, the preprocessor macro UNICODE is of little help to us in the
1168 // Therefore, to keep the CStdStr declaration simple, we have these inline
1169 // functions. The template calls them often. Since they are inline (and NOT
1170 // exported when this is built as a DLL), they will probably be resolved away
1173 // Without these functions, the CStdStr<> template would probably have to broken
1174 // out into two, almost identical classes. Either that or it would be a huge,
1175 // convoluted mess, with tons of "if" statements all over the place checking the
1176 // size of template parameter CT.
1177 // =============================================================================
1181 // --------------------------------------------------------------------------
1182 // Win32 GetStringTypeEx wrappers
1183 // --------------------------------------------------------------------------
1184 inline bool wsGetStringType(LCID lc
, DWORD dwT
, PCSTR pS
, int nSize
,
1187 return FALSE
!= GetStringTypeExA(lc
, dwT
, pS
, nSize
, pWd
);
1189 inline bool wsGetStringType(LCID lc
, DWORD dwT
, PCWSTR pS
, int nSize
,
1192 return FALSE
!= GetStringTypeExW(lc
, dwT
, pS
, nSize
, pWd
);
1196 template<typename CT
>
1197 inline bool ssisspace (CT t
)
1200 return wsGetStringType(GetThreadLocale(), CT_CTYPE1
, &t
, 1, &toYourMother
)
1201 && 0 != (C1_BLANK
& toYourMother
);
1206 // If they defined SS_NO_REFCOUNT, then we must convert all assignments
1208 #if defined (_MSC_VER) && (_MSC_VER < 1300)
1209 #ifdef SS_NO_REFCOUNT
1210 #define SSREF(x) (x).c_str()
1212 #define SSREF(x) (x)
1215 #define SSREF(x) (x)
1218 // -----------------------------------------------------------------------------
1219 // sslen: strlen/wcslen wrappers
1220 // -----------------------------------------------------------------------------
1221 template<typename CT
> inline int sslen(const CT
* pT
)
1223 return 0 == pT
? 0 : (int)std::basic_string
<CT
>::traits_type::length(pT
);
1224 // return 0 == pT ? 0 : std::char_traits<CT>::length(pT);
1226 inline SS_NOTHROW
int sslen(const std::string
& s
)
1228 return static_cast<int>(s
.length());
1230 inline SS_NOTHROW
int sslen(const std::wstring
& s
)
1232 return static_cast<int>(s
.length());
1235 // -----------------------------------------------------------------------------
1236 // sstolower/sstoupper -- convert characters to upper/lower case
1237 // -----------------------------------------------------------------------------
1240 inline char sstoupper(char ch
) { return (char)::toupper(ch
); }
1241 inline wchar_t sstoupper(wchar_t ch
){ return (wchar_t)::towupper(ch
); }
1242 inline char sstolower(char ch
) { return (char)::tolower(ch
); }
1243 inline wchar_t sstolower(wchar_t ch
){ return (wchar_t)::tolower(ch
); }
1245 template<typename CT
>
1246 inline CT
sstolower(const CT
& t
, const std::locale
& loc
= std::locale())
1248 return std::tolower
<CT
>(t
, loc
);
1250 template<typename CT
>
1251 inline CT
sstoupper(const CT
& t
, const std::locale
& loc
= std::locale())
1253 return std::toupper
<CT
>(t
, loc
);
1257 // -----------------------------------------------------------------------------
1258 // ssasn: assignment functions -- assign "sSrc" to "sDst"
1259 // -----------------------------------------------------------------------------
1260 typedef std::string::size_type SS_SIZETYPE
; // just for shorthand, really
1261 typedef std::string::pointer SS_PTRTYPE
;
1262 typedef std::wstring::size_type SW_SIZETYPE
;
1263 typedef std::wstring::pointer SW_PTRTYPE
;
1266 template <typename T
>
1267 inline void ssasn(std::basic_string
<T
>& sDst
, const std::basic_string
<T
>& sSrc
)
1269 if ( sDst
.c_str() != sSrc
.c_str() )
1272 sDst
.assign(SSREF(sSrc
));
1275 template <typename T
>
1276 inline void ssasn(std::basic_string
<T
>& sDst
, const T
*pA
)
1278 // Watch out for NULLs, as always.
1285 // If pA actually points to part of sDst, we must NOT erase(), but
1286 // rather take a substring
1288 else if ( pA
>= sDst
.c_str() && pA
<= sDst
.c_str() + sDst
.size() )
1290 sDst
=sDst
.substr(static_cast<typename
std::basic_string
<T
>::size_type
>(pA
-sDst
.c_str()));
1293 // Otherwise (most cases) apply the assignment bug fix, if applicable
1294 // and do the assignment
1302 inline void ssasn(std::string
& sDst
, const std::wstring
& sSrc
)
1310 int nDst
= static_cast<int>(sSrc
.size());
1312 // In MBCS builds, pad the buffer to account for the possibility of
1313 // some 3 byte characters. Not perfect but should get most cases.
1316 // In MBCS builds, we don't know how long the destination string will be.
1317 nDst
= static_cast<int>(static_cast<double>(nDst
) * 1.3);
1318 sDst
.resize(nDst
+1);
1319 PCSTR szCvt
= StdCodeCvt(const_cast<SS_PTRTYPE
>(sDst
.data()), nDst
,
1320 sSrc
.c_str(), static_cast<int>(sSrc
.size()));
1321 sDst
.resize(sslen(szCvt
));
1323 sDst
.resize(nDst
+1);
1324 StdCodeCvt(const_cast<SS_PTRTYPE
>(sDst
.data()), nDst
,
1325 sSrc
.c_str(), static_cast<int>(sSrc
.size()));
1326 sDst
.resize(sSrc
.size());
1330 inline void ssasn(std::string
& sDst
, PCWSTR pW
)
1332 int nSrc
= sslen(pW
);
1335 int nSrc
= sslen(pW
);
1338 // In MBCS builds, pad the buffer to account for the possibility of
1339 // some 3 byte characters. Not perfect but should get most cases.
1342 nDst
= static_cast<int>(static_cast<double>(nDst
) * 1.3);
1343 // In MBCS builds, we don't know how long the destination string will be.
1344 sDst
.resize(nDst
+ 1);
1345 PCSTR szCvt
= StdCodeCvt(const_cast<SS_PTRTYPE
>(sDst
.data()), nDst
,
1347 sDst
.resize(sslen(szCvt
));
1349 sDst
.resize(nDst
+ 1);
1350 StdCodeCvt(const_cast<SS_PTRTYPE
>(sDst
.data()), nDst
, pW
, nSrc
);
1359 inline void ssasn(std::string
& sDst
, const int nNull
)
1366 inline void ssasn(std::wstring
& sDst
, const std::string
& sSrc
)
1374 int nSrc
= static_cast<int>(sSrc
.size());
1377 sDst
.resize(nSrc
+1);
1378 PCWSTR szCvt
= StdCodeCvt(const_cast<SW_PTRTYPE
>(sDst
.data()), nDst
,
1379 sSrc
.c_str(), nSrc
);
1381 sDst
.resize(sslen(szCvt
));
1384 inline void ssasn(std::wstring
& sDst
, PCSTR pA
)
1386 int nSrc
= sslen(pA
);
1395 sDst
.resize(nDst
+1);
1396 PCWSTR szCvt
= StdCodeCvt(const_cast<SW_PTRTYPE
>(sDst
.data()), nDst
, pA
,
1399 sDst
.resize(sslen(szCvt
));
1402 inline void ssasn(std::wstring
& sDst
, const int nNull
)
1409 // -----------------------------------------------------------------------------
1410 // ssadd: string object concatenation -- add second argument to first
1411 // -----------------------------------------------------------------------------
1412 inline void ssadd(std::string
& sDst
, const std::wstring
& sSrc
)
1414 int nSrc
= static_cast<int>(sSrc
.size());
1418 int nDst
= static_cast<int>(sDst
.size());
1421 // In MBCS builds, pad the buffer to account for the possibility of
1422 // some 3 byte characters. Not perfect but should get most cases.
1425 nAdd
= static_cast<int>(static_cast<double>(nAdd
) * 1.3);
1426 sDst
.resize(nDst
+nAdd
+1);
1427 PCSTR szCvt
= StdCodeCvt(const_cast<SS_PTRTYPE
>(sDst
.data()+nDst
),
1428 nAdd
, sSrc
.c_str(), nSrc
);
1429 sDst
.resize(nDst
+ sslen(szCvt
));
1431 sDst
.resize(nDst
+nAdd
+1);
1432 StdCodeCvt(const_cast<SS_PTRTYPE
>(sDst
.data()+nDst
), nAdd
, sSrc
.c_str(), nSrc
);
1433 sDst
.resize(nDst
+ nAdd
);
1437 template <typename T
>
1438 inline void ssadd(typename
std::basic_string
<T
>& sDst
, const typename
std::basic_string
<T
>& sSrc
)
1442 inline void ssadd(std::string
& sDst
, PCWSTR pW
)
1444 int nSrc
= sslen(pW
);
1447 int nDst
= static_cast<int>(sDst
.size());
1451 nAdd
= static_cast<int>(static_cast<double>(nAdd
) * 1.3);
1452 sDst
.resize(nDst
+ nAdd
+ 1);
1453 PCSTR szCvt
= StdCodeCvt(const_cast<SS_PTRTYPE
>(sDst
.data()+nDst
),
1455 sDst
.resize(nDst
+ sslen(szCvt
));
1457 sDst
.resize(nDst
+ nAdd
+ 1);
1458 StdCodeCvt(const_cast<SS_PTRTYPE
>(sDst
.data()+nDst
), nAdd
, pW
, nSrc
);
1459 sDst
.resize(nDst
+ nSrc
);
1463 template <typename T
>
1464 inline void ssadd(typename
std::basic_string
<T
>& sDst
, const T
*pA
)
1468 // If the string being added is our internal string or a part of our
1469 // internal string, then we must NOT do any reallocation without
1470 // first copying that string to another object (since we're using a
1473 if ( pA
>= sDst
.c_str() && pA
<= sDst
.c_str()+sDst
.length())
1475 if ( sDst
.capacity() <= sDst
.size()+sslen(pA
) )
1476 sDst
.append(std::basic_string
<T
>(pA
));
1486 inline void ssadd(std::wstring
& sDst
, const std::string
& sSrc
)
1488 if ( !sSrc
.empty() )
1490 int nSrc
= static_cast<int>(sSrc
.size());
1491 int nDst
= static_cast<int>(sDst
.size());
1493 sDst
.resize(nDst
+ nSrc
+ 1);
1495 PCWSTR szCvt
= StdCodeCvt(const_cast<SW_PTRTYPE
>(sDst
.data()+nDst
),
1496 nSrc
, sSrc
.c_str(), nSrc
+1);
1497 sDst
.resize(nDst
+ sslen(szCvt
));
1499 StdCodeCvt(const_cast<SW_PTRTYPE
>(sDst
.data()+nDst
), nSrc
, sSrc
.c_str(), nSrc
+1);
1500 sDst
.resize(nDst
+ nSrc
);
1504 inline void ssadd(std::wstring
& sDst
, PCSTR pA
)
1506 int nSrc
= sslen(pA
);
1510 int nDst
= static_cast<int>(sDst
.size());
1512 sDst
.resize(nDst
+ nSrc
+ 1);
1514 PCWSTR szCvt
= StdCodeCvt(const_cast<SW_PTRTYPE
>(sDst
.data()+nDst
),
1516 sDst
.resize(nDst
+ sslen(szCvt
));
1518 StdCodeCvt(const_cast<SW_PTRTYPE
>(sDst
.data()+nDst
), nSrc
, pA
, nSrc
+1);
1519 sDst
.resize(nDst
+ nSrc
);
1524 // -----------------------------------------------------------------------------
1525 // sscmp: comparison (case sensitive, not affected by locale)
1526 // -----------------------------------------------------------------------------
1527 template<typename CT
>
1528 inline int sscmp(const CT
* pA1
, const CT
* pA2
)
1537 } while ( (f
) && (f
== l
) );
1539 return (int)(f
- l
);
1542 // -----------------------------------------------------------------------------
1543 // ssicmp: comparison (case INsensitive, not affected by locale)
1544 // -----------------------------------------------------------------------------
1545 template<typename CT
>
1546 inline int ssicmp(const CT
* pA1
, const CT
* pA2
)
1548 // Using the "C" locale = "not affected by locale"
1550 std::locale loc
= std::locale::classic();
1551 const std::ctype
<CT
>& ct
= SS_USE_FACET(loc
, std::ctype
<CT
>);
1557 f
= ct
.tolower(*(pA1
++));
1558 l
= ct
.tolower(*(pA2
++));
1559 } while ( (f
) && (f
== l
) );
1561 return (int)(f
- l
);
1564 // -----------------------------------------------------------------------------
1565 // ssupr/sslwr: Uppercase/Lowercase conversion functions
1566 // -----------------------------------------------------------------------------
1568 template<typename CT
>
1569 inline void sslwr(CT
* pT
, size_t nLen
, const std::locale
& loc
=std::locale())
1571 SS_USE_FACET(loc
, std::ctype
<CT
>).tolower(pT
, pT
+nLen
);
1573 template<typename CT
>
1574 inline void ssupr(CT
* pT
, size_t nLen
, const std::locale
& loc
=std::locale())
1576 SS_USE_FACET(loc
, std::ctype
<CT
>).toupper(pT
, pT
+nLen
);
1579 // -----------------------------------------------------------------------------
1580 // vsprintf/vswprintf or _vsnprintf/_vsnwprintf equivalents. In standard
1581 // builds we can't use _vsnprintf/_vsnwsprintf because they're MS extensions.
1583 // -----------------------------------------------------------------------------
1584 // Borland's headers put some ANSI "C" functions in the 'std' namespace.
1585 // Promote them to the global namespace so we can use them here.
1587 #if defined(__BORLANDC__)
1588 using std::vsprintf
;
1589 using std::vswprintf
;
1592 // GNU is supposed to have vsnprintf and vsnwprintf. But only the newer
1593 // distributions do.
1595 #if defined(__GNUC__)
1597 inline int ssvsprintf(PSTR pA
, size_t nCount
, PCSTR pFmtA
, va_list vl
)
1599 return vsnprintf(pA
, nCount
, pFmtA
, vl
);
1601 inline int ssvsprintf(PWSTR pW
, size_t nCount
, PCWSTR pFmtW
, va_list vl
)
1603 return vswprintf(pW
, nCount
, pFmtW
, vl
);
1606 // Microsofties can use
1607 #elif defined(_MSC_VER) && !defined(SS_ANSI)
1609 inline int ssvsprintf(PSTR pA
, size_t nCount
, PCSTR pFmtA
, va_list vl
)
1611 return _vsnprintf(pA
, nCount
, pFmtA
, vl
);
1613 inline int ssvsprintf(PWSTR pW
, size_t nCount
, PCWSTR pFmtW
, va_list vl
)
1615 return _vsnwprintf(pW
, nCount
, pFmtW
, vl
);
1618 #elif defined (SS_DANGEROUS_FORMAT) // ignore buffer size parameter if needed?
1620 inline int ssvsprintf(PSTR pA
, size_t /*nCount*/, PCSTR pFmtA
, va_list vl
)
1622 return vsprintf(pA
, pFmtA
, vl
);
1625 inline int ssvsprintf(PWSTR pW
, size_t nCount
, PCWSTR pFmtW
, va_list vl
)
1627 // JMO: Some distributions of the "C" have a version of vswprintf that
1628 // takes 3 arguments (e.g. Microsoft, Borland, GNU). Others have a
1629 // version which takes 4 arguments (an extra "count" argument in the
1630 // second position. The best stab I can take at this so far is that if
1631 // you are NOT running with MS, Borland, or GNU, then I'll assume you
1632 // have the version that takes 4 arguments.
1634 // I'm sure that these checks don't catch every platform correctly so if
1635 // you get compiler errors on one of the lines immediately below, it's
1636 // probably because your implemntation takes a different number of
1637 // arguments. You can comment out the offending line (and use the
1638 // alternate version) or you can figure out what compiler flag to check
1639 // and add that preprocessor check in. Regardless, if you get an error
1640 // on these lines, I'd sure like to hear from you about it.
1642 // Thanks to Ronny Schulz for the SGI-specific checks here.
1644 // #if !defined(__MWERKS__) && !defined(__SUNPRO_CC_COMPAT) && !defined(__SUNPRO_CC)
1645 #if !defined(_MSC_VER) \
1646 && !defined (__BORLANDC__) \
1647 && !defined(__GNUC__) \
1650 return vswprintf(pW
, nCount
, pFmtW
, vl
);
1652 // suddenly with the current SGI 7.3 compiler there is no such function as
1653 // vswprintf and the substitute needs explicit casts to compile
1655 #elif defined(__sgi)
1658 return vsprintf( (char *)pW
, (char *)pFmtW
, vl
);
1663 return vswprintf(pW
, pFmtW
, vl
);
1671 // GOT COMPILER PROBLEMS HERE?
1672 // ---------------------------
1673 // Does your compiler choke on one or more of the following 2 functions? It
1674 // probably means that you don't have have either vsnprintf or vsnwprintf in
1675 // your version of the CRT. This is understandable since neither is an ANSI
1676 // "C" function. However it still leaves you in a dilemma. In order to make
1677 // this code build, you're going to have to to use some non-length-checked
1678 // formatting functions that every CRT has: vsprintf and vswprintf.
1680 // This is very dangerous. With the proper erroneous (or malicious) code, it
1681 // can lead to buffer overlows and crashing your PC. Use at your own risk
1682 // In order to use them, just #define SS_DANGEROUS_FORMAT at the top of
1685 // Even THEN you might not be all the way home due to some non-conforming
1686 // distributions. More on this in the comments below.
1688 inline int ssnprintf(PSTR pA
, size_t nCount
, PCSTR pFmtA
, va_list vl
)
1691 return _vsnprintf(pA
, nCount
, pFmtA
, vl
);
1693 return vsnprintf(pA
, nCount
, pFmtA
, vl
);
1696 inline int ssnprintf(PWSTR pW
, size_t nCount
, PCWSTR pFmtW
, va_list vl
)
1699 return _vsnwprintf(pW
, nCount
, pFmtW
, vl
);
1701 return vswprintf(pW
, nCount
, pFmtW
, vl
);
1708 // -----------------------------------------------------------------------------
1709 // ssload: Type safe, overloaded ::LoadString wrappers
1710 // There is no equivalent of these in non-Win32-specific builds. However, I'm
1711 // thinking that with the message facet, there might eventually be one
1712 // -----------------------------------------------------------------------------
1713 #if defined (SS_WIN32) && !defined(SS_ANSI)
1714 inline int ssload(HMODULE hInst
, UINT uId
, PSTR pBuf
, int nMax
)
1716 return ::LoadStringA(hInst
, uId
, pBuf
, nMax
);
1718 inline int ssload(HMODULE hInst
, UINT uId
, PWSTR pBuf
, int nMax
)
1720 return ::LoadStringW(hInst
, uId
, pBuf
, nMax
);
1722 #if defined ( _MSC_VER ) && ( _MSC_VER >= 1500 )
1723 inline int ssload(HMODULE hInst
, UINT uId
, uint16_t *pBuf
, int nMax
)
1727 inline int ssload(HMODULE hInst
, UINT uId
, uint32_t *pBuf
, int nMax
)
1735 // -----------------------------------------------------------------------------
1736 // sscoll/ssicoll: Collation wrappers
1737 // Note -- with MSVC I have reversed the arguments order here because the
1738 // functions appear to return the opposite of what they should
1739 // -----------------------------------------------------------------------------
1740 #ifndef SS_NO_LOCALE
1741 template <typename CT
>
1742 inline int sscoll(const CT
* sz1
, int nLen1
, const CT
* sz2
, int nLen2
)
1744 const std::collate
<CT
>& coll
=
1745 SS_USE_FACET(std::locale(), std::collate
<CT
>);
1747 return coll
.compare(sz2
, sz2
+nLen2
, sz1
, sz1
+nLen1
);
1749 template <typename CT
>
1750 inline int ssicoll(const CT
* sz1
, int nLen1
, const CT
* sz2
, int nLen2
)
1752 const std::locale loc
;
1753 const std::collate
<CT
>& coll
= SS_USE_FACET(loc
, std::collate
<CT
>);
1755 // Some implementations seem to have trouble using the collate<>
1756 // facet typedefs so we'll just default to basic_string and hope
1757 // that's what the collate facet uses (which it generally should)
1759 // std::collate<CT>::string_type s1(sz1);
1760 // std::collate<CT>::string_type s2(sz2);
1761 const std::basic_string
<CT
> sEmpty
;
1762 std::basic_string
<CT
> s1(sz1
? sz1
: sEmpty
.c_str());
1763 std::basic_string
<CT
> s2(sz2
? sz2
: sEmpty
.c_str());
1765 sslwr(const_cast<CT
*>(s1
.c_str()), nLen1
, loc
);
1766 sslwr(const_cast<CT
*>(s2
.c_str()), nLen2
, loc
);
1767 return coll
.compare(s2
.c_str(), s2
.c_str()+nLen2
,
1768 s1
.c_str(), s1
.c_str()+nLen1
);
1773 // -----------------------------------------------------------------------------
1774 // ssfmtmsg: FormatMessage equivalents. Needed because I added a CString facade
1775 // Again -- no equivalent of these on non-Win32 builds but their might one day
1776 // be one if the message facet gets implemented
1777 // -----------------------------------------------------------------------------
1778 #if defined (SS_WIN32) && !defined(SS_ANSI)
1779 inline DWORD
ssfmtmsg(DWORD dwFlags
, LPCVOID pSrc
, DWORD dwMsgId
,
1780 DWORD dwLangId
, PSTR pBuf
, DWORD nSize
,
1783 return FormatMessageA(dwFlags
, pSrc
, dwMsgId
, dwLangId
,
1784 pBuf
, nSize
,vlArgs
);
1786 inline DWORD
ssfmtmsg(DWORD dwFlags
, LPCVOID pSrc
, DWORD dwMsgId
,
1787 DWORD dwLangId
, PWSTR pBuf
, DWORD nSize
,
1790 return FormatMessageW(dwFlags
, pSrc
, dwMsgId
, dwLangId
,
1791 pBuf
, nSize
,vlArgs
);
1798 // FUNCTION: sscpy. Copies up to 'nMax' characters from pSrc to pDst.
1799 // -----------------------------------------------------------------------------
1801 // inline int sscpy(PSTR pDst, PCSTR pSrc, int nMax=-1);
1802 // inline int sscpy(PUSTR pDst, PCSTR pSrc, int nMax=-1)
1803 // inline int sscpy(PSTR pDst, PCWSTR pSrc, int nMax=-1);
1804 // inline int sscpy(PWSTR pDst, PCWSTR pSrc, int nMax=-1);
1805 // inline int sscpy(PWSTR pDst, PCSTR pSrc, int nMax=-1);
1808 // This function is very much (but not exactly) like strcpy. These
1809 // overloads simplify copying one C-style string into another by allowing
1810 // the caller to specify two different types of strings if necessary.
1812 // The strings must NOT overlap
1814 // "Character" is expressed in terms of the destination string, not
1815 // the source. If no 'nMax' argument is supplied, then the number of
1816 // characters copied will be sslen(pSrc). A NULL terminator will
1817 // also be added so pDst must actually be big enough to hold nMax+1
1818 // characters. The return value is the number of characters copied,
1819 // not including the NULL terminator.
1822 // pSrc - the string to be copied FROM. May be a char based string, an
1823 // MBCS string (in Win32 builds) or a wide string (wchar_t).
1824 // pSrc - the string to be copied TO. Also may be either MBCS or wide
1825 // nMax - the maximum number of characters to be copied into szDest. Note
1826 // that this is expressed in whatever a "character" means to pDst.
1827 // If pDst is a wchar_t type string than this will be the maximum
1828 // number of wchar_ts that my be copied. The pDst string must be
1829 // large enough to hold least nMaxChars+1 characters.
1830 // If the caller supplies no argument for nMax this is a signal to
1831 // the routine to copy all the characters in pSrc, regardless of
1834 // RETURN VALUE: none
1835 // -----------------------------------------------------------------------------
1837 template<typename CT1
, typename CT2
>
1838 inline int sscpycvt(CT1
* pDst
, const CT2
* pSrc
, int nMax
)
1840 // Note -- we assume pDst is big enough to hold pSrc. If not, we're in
1841 // big trouble. No bounds checking. Caveat emptor.
1843 int nSrc
= sslen(pSrc
);
1845 const CT1
* szCvt
= StdCodeCvt(pDst
, nMax
, pSrc
, nSrc
);
1847 // If we're copying the same size characters, then all the "code convert"
1848 // just did was basically memcpy so the #of characters copied is the same
1849 // as the number requested. I should probably specialize this function
1850 // template to achieve this purpose as it is silly to do a runtime check
1851 // of a fact known at compile time. I'll get around to it.
1853 return sslen(szCvt
);
1856 template<typename T
>
1857 inline int sscpycvt(T
* pDst
, const T
* pSrc
, int nMax
)
1860 for (; nCount
> 0 && *pSrc
; ++pSrc
, ++pDst
, --nCount
)
1861 std::basic_string
<T
>::traits_type::assign(*pDst
, *pSrc
);
1864 return nMax
- nCount
;
1867 inline int sscpycvt(PWSTR pDst
, PCSTR pSrc
, int nMax
)
1869 // Note -- we assume pDst is big enough to hold pSrc. If not, we're in
1870 // big trouble. No bounds checking. Caveat emptor.
1872 const PWSTR szCvt
= StdCodeCvt(pDst
, nMax
, pSrc
, nMax
);
1873 return sslen(szCvt
);
1876 template<typename CT1
, typename CT2
>
1877 inline int sscpy(CT1
* pDst
, const CT2
* pSrc
, int nMax
, int nLen
)
1879 return sscpycvt(pDst
, pSrc
, SSMIN(nMax
, nLen
));
1881 template<typename CT1
, typename CT2
>
1882 inline int sscpy(CT1
* pDst
, const CT2
* pSrc
, int nMax
)
1884 return sscpycvt(pDst
, pSrc
, SSMIN(nMax
, sslen(pSrc
)));
1886 template<typename CT1
, typename CT2
>
1887 inline int sscpy(CT1
* pDst
, const CT2
* pSrc
)
1889 return sscpycvt(pDst
, pSrc
, sslen(pSrc
));
1891 template<typename CT1
, typename CT2
>
1892 inline int sscpy(CT1
* pDst
, const std::basic_string
<CT2
>& sSrc
, int nMax
)
1894 return sscpycvt(pDst
, sSrc
.c_str(), SSMIN(nMax
, (int)sSrc
.length()));
1896 template<typename CT1
, typename CT2
>
1897 inline int sscpy(CT1
* pDst
, const std::basic_string
<CT2
>& sSrc
)
1899 return sscpycvt(pDst
, sSrc
.c_str(), (int)sSrc
.length());
1902 #ifdef SS_INC_COMDEF
1903 template<typename CT1
>
1904 inline int sscpy(CT1
* pDst
, const _bstr_t
& bs
, int nMax
)
1906 return sscpycvt(pDst
, static_cast<PCOLESTR
>(bs
),
1907 SSMIN(nMax
, static_cast<int>(bs
.length())));
1909 template<typename CT1
>
1910 inline int sscpy(CT1
* pDst
, const _bstr_t
& bs
)
1912 return sscpy(pDst
, bs
, static_cast<int>(bs
.length()));
1917 // -----------------------------------------------------------------------------
1918 // Functional objects for changing case. They also let you pass locales
1919 // -----------------------------------------------------------------------------
1922 template<typename CT
>
1923 struct SSToUpper
: public std::unary_function
<CT
, CT
>
1925 inline CT
operator()(const CT
& t
) const
1927 return sstoupper(t
);
1930 template<typename CT
>
1931 struct SSToLower
: public std::unary_function
<CT
, CT
>
1933 inline CT
operator()(const CT
& t
) const
1935 return sstolower(t
);
1939 template<typename CT
>
1940 struct SSToUpper
: public std::binary_function
<CT
, std::locale
, CT
>
1942 inline CT
operator()(const CT
& t
, const std::locale
& loc
) const
1944 return sstoupper
<CT
>(t
, loc
);
1947 template<typename CT
>
1948 struct SSToLower
: public std::binary_function
<CT
, std::locale
, CT
>
1950 inline CT
operator()(const CT
& t
, const std::locale
& loc
) const
1952 return sstolower
<CT
>(t
, loc
);
1957 // This struct is used for TrimRight() and TrimLeft() function implementations.
1958 //template<typename CT>
1959 //struct NotSpace : public std::unary_function<CT, bool>
1961 // const std::locale& loc;
1962 // inline NotSpace(const std::locale& locArg) : loc(locArg) {}
1963 // inline bool operator() (CT t) { return !std::isspace(t, loc); }
1965 template<typename CT
>
1966 struct NotSpace
: public std::unary_function
<CT
, bool>
1969 // Note -- using std::isspace in a COM DLL gives us access violations
1970 // because it causes the dynamic addition of a function to be called
1971 // when the library shuts down. Unfortunately the list is maintained
1972 // in DLL memory but the function is in static memory. So the COM DLL
1973 // goes away along with the function that was supposed to be called,
1974 // and then later when the DLL CRT shuts down it unloads the list and
1975 // tries to call the long-gone function.
1976 // This is DinkumWare's implementation problem. If you encounter this
1977 // problem, you may replace the calls here with good old isspace() and
1978 // iswspace() from the CRT unless they specify SS_ANSI
1982 bool operator() (CT t
) const { return !ssisspace(t
); }
1985 const std::locale loc
;
1986 NotSpace(const std::locale
& locArg
=std::locale()) : loc(locArg
) {}
1987 bool operator() (CT t
) const { return !std::isspace(t
, loc
); }
1994 // Now we can define the template (finally!)
1995 // =============================================================================
1996 // TEMPLATE: CStdStr
1997 // template<typename CT> class CStdStr : public std::basic_string<CT>
2000 // This template derives from basic_string<CT> and adds some MFC CString-
2001 // like functionality
2003 // Basically, this is my attempt to make Standard C++ library strings as
2004 // easy to use as the MFC CString class.
2006 // Note that although this is a template, it makes the assumption that the
2007 // template argument (CT, the character type) is either char or wchar_t.
2008 // =============================================================================
2010 //#define CStdStr _SS // avoid compiler warning 4786
2012 // template<typename ARG> ARG& FmtArg(ARG& arg) { return arg; }
2013 // PCSTR FmtArg(const std::string& arg) { return arg.c_str(); }
2014 // PCWSTR FmtArg(const std::wstring& arg) { return arg.c_str(); }
2016 template<typename ARG
>
2019 explicit FmtArg(const ARG
& arg
) : a_(arg
) {}
2020 const ARG
& operator()() const { return a_
; }
2023 FmtArg
& operator=(const FmtArg
&) { return *this; }
2026 template<typename CT
>
2027 class CStdStr
: public std::basic_string
<CT
>
2029 // Typedefs for shorter names. Using these names also appears to help
2030 // us avoid some ambiguities that otherwise arise on some platforms
2032 #define MYBASE std::basic_string<CT> // my base class
2033 //typedef typename std::basic_string<CT> MYBASE; // my base class
2034 typedef CStdStr
<CT
> MYTYPE
; // myself
2035 typedef typename
MYBASE::const_pointer PCMYSTR
; // PCSTR or PCWSTR
2036 typedef typename
MYBASE::pointer PMYSTR
; // PSTR or PWSTR
2037 typedef typename
MYBASE::iterator MYITER
; // my iterator type
2038 typedef typename
MYBASE::const_iterator MYCITER
; // you get the idea...
2039 typedef typename
MYBASE::reverse_iterator MYRITER
;
2040 typedef typename
MYBASE::size_type MYSIZE
;
2041 typedef typename
MYBASE::value_type MYVAL
;
2042 typedef typename
MYBASE::allocator_type MYALLOC
;
2045 // shorthand conversion from PCTSTR to string resource ID
2046 #define SSRES(pctstr) LOWORD(reinterpret_cast<unsigned long>(pctstr))
2048 bool TryLoad(const void* pT
)
2050 bool bLoaded
= false;
2052 #if defined(SS_WIN32) && !defined(SS_ANSI)
2053 if ( ( pT
!= NULL
) && SS_IS_INTRESOURCE(pT
) )
2055 UINT nId
= LOWORD(reinterpret_cast<unsigned long>(pT
));
2056 if ( !LoadString(nId
) )
2058 TRACE(_T("Can't load string %u\n"), SSRES(pT
));
2068 // CStdStr inline constructors
2073 CStdStr(const MYTYPE
& str
) : MYBASE(SSREF(str
))
2077 CStdStr(const std::string
& str
)
2079 ssasn(*this, SSREF(str
));
2082 CStdStr(const std::wstring
& str
)
2084 ssasn(*this, SSREF(str
));
2087 CStdStr(PCMYSTR pT
, MYSIZE n
) : MYBASE(pT
, n
)
2094 *this = reinterpret_cast<PCSTR
>(pU
);
2118 CStdStr(uint16_t* pW
)
2128 CStdStr(uint32_t* pW
)
2138 CStdStr(MYCITER first
, MYCITER last
)
2139 : MYBASE(first
, last
)
2143 CStdStr(MYSIZE nSize
, MYVAL ch
, const MYALLOC
& al
=MYALLOC())
2144 : MYBASE(nSize
, ch
, al
)
2148 #ifdef SS_INC_COMDEF
2149 CStdStr(const _bstr_t
& bstr
)
2151 if ( bstr
.length() > 0 )
2152 this->append(static_cast<PCMYSTR
>(bstr
), bstr
.length());
2156 // CStdStr inline assignment operators -- the ssasn function now takes care
2157 // of fixing the MSVC assignment bug (see knowledge base article Q172398).
2158 MYTYPE
& operator=(const MYTYPE
& str
)
2164 MYTYPE
& operator=(const std::string
& str
)
2170 MYTYPE
& operator=(const std::wstring
& str
)
2176 MYTYPE
& operator=(PCSTR pA
)
2182 MYTYPE
& operator=(PCWSTR pW
)
2189 MYTYPE
& operator=(PCUSTR pU
)
2191 ssasn(*this, reinterpret_cast<PCSTR
>(pU
));
2196 MYTYPE
& operator=(uint16_t* pA
)
2202 MYTYPE
& operator=(uint32_t* pA
)
2208 MYTYPE
& operator=(CT t
)
2215 #ifdef SS_INC_COMDEF
2216 MYTYPE
& operator=(const _bstr_t
& bstr
)
2218 if ( bstr
.length() > 0 )
2220 this->assign(static_cast<PCMYSTR
>(bstr
), bstr
.length());
2232 // Overloads also needed to fix the MSVC assignment bug (KB: Q172398)
2233 // *** Thanks to Pete The Plumber for catching this one ***
2234 // They also are compiled if you have explicitly turned off refcounting
2235 #if ( defined(_MSC_VER) && ( _MSC_VER < 1200 ) ) || defined(SS_NO_REFCOUNT)
2237 MYTYPE
& assign(const MYTYPE
& str
)
2240 sscpy(GetBuffer(str
.size()+1), SSREF(str
));
2241 this->ReleaseBuffer(str
.size());
2245 MYTYPE
& assign(const MYTYPE
& str
, MYSIZE nStart
, MYSIZE nChars
)
2247 // This overload of basic_string::assign is supposed to assign up to
2248 // <nChars> or the NULL terminator, whichever comes first. Since we
2249 // are about to call a less forgiving overload (in which <nChars>
2250 // must be a valid length), we must adjust the length here to a safe
2251 // value. Thanks to Ullrich Poll�hne for catching this bug
2253 nChars
= SSMIN(nChars
, str
.length() - nStart
);
2254 MYTYPE
strTemp(str
.c_str()+nStart
, nChars
);
2256 this->assign(strTemp
);
2260 MYTYPE
& assign(const MYBASE
& str
)
2266 MYTYPE
& assign(const MYBASE
& str
, MYSIZE nStart
, MYSIZE nChars
)
2268 // This overload of basic_string::assign is supposed to assign up to
2269 // <nChars> or the NULL terminator, whichever comes first. Since we
2270 // are about to call a less forgiving overload (in which <nChars>
2271 // must be a valid length), we must adjust the length here to a safe
2272 // value. Thanks to Ullrich Poll�hne for catching this bug
2274 nChars
= SSMIN(nChars
, str
.length() - nStart
);
2276 // Watch out for assignment to self
2280 MYTYPE
strTemp(str
.c_str() + nStart
, nChars
);
2281 static_cast<MYBASE
*>(this)->assign(strTemp
);
2286 static_cast<MYBASE
*>(this)->assign(str
.c_str()+nStart
, nChars
);
2291 MYTYPE
& assign(const CT
* pC
, MYSIZE nChars
)
2293 // Q172398 only fix -- erase before assigning, but not if we're
2294 // assigning from our own buffer
2296 #if defined ( _MSC_VER ) && ( _MSC_VER < 1200 )
2297 if ( !this->empty() &&
2298 ( pC
< this->data() || pC
> this->data() + this->capacity() ) )
2304 static_cast<MYBASE
*>(this)->assign(pC
, nChars
);
2308 MYTYPE
& assign(MYSIZE nChars
, MYVAL val
)
2311 static_cast<MYBASE
*>(this)->assign(nChars
, val
);
2315 MYTYPE
& assign(const CT
* pT
)
2317 return this->assign(pT
, MYBASE::traits_type::length(pT
));
2320 MYTYPE
& assign(MYCITER iterFirst
, MYCITER iterLast
)
2322 #if defined ( _MSC_VER ) && ( _MSC_VER < 1200 )
2323 // Q172398 fix. don't call erase() if we're assigning from ourself
2324 if ( iterFirst
< this->begin() ||
2325 iterFirst
> this->begin() + this->size() )
2330 this->replace(this->begin(), this->end(), iterFirst
, iterLast
);
2336 // -------------------------------------------------------------------------
2337 // CStdStr inline concatenation.
2338 // -------------------------------------------------------------------------
2339 MYTYPE
& operator+=(const MYTYPE
& str
)
2345 MYTYPE
& operator+=(const std::string
& str
)
2351 MYTYPE
& operator+=(const std::wstring
& str
)
2357 MYTYPE
& operator+=(PCSTR pA
)
2363 MYTYPE
& operator+=(PCWSTR pW
)
2369 MYTYPE
& operator+=(uint16_t* pW
)
2375 MYTYPE
& operator+=(uint32_t* pW
)
2381 MYTYPE
& operator+=(CT t
)
2386 #ifdef SS_INC_COMDEF // if we have _bstr_t, define a += for it too.
2387 MYTYPE
& operator+=(const _bstr_t
& bstr
)
2389 return this->operator+=(static_cast<PCMYSTR
>(bstr
));
2394 // -------------------------------------------------------------------------
2395 // Case changing functions
2396 // -------------------------------------------------------------------------
2398 MYTYPE
& ToUpper(const std::locale
& loc
=std::locale())
2400 // Note -- if there are any MBCS character sets in which the lowercase
2401 // form a character takes up a different number of bytes than the
2402 // uppercase form, this would probably not work...
2404 std::transform(this->begin(),
2410 std::bind2nd(SSToUpper
<CT
>(), loc
));
2413 // ...but if it were, this would probably work better. Also, this way
2414 // seems to be a bit faster when anything other then the "C" locale is
2419 // ssupr(this->GetBuf(), this->size(), loc);
2426 MYTYPE
& ToLower(const std::locale
& loc
=std::locale())
2428 // Note -- if there are any MBCS character sets in which the lowercase
2429 // form a character takes up a different number of bytes than the
2430 // uppercase form, this would probably not work...
2432 std::transform(this->begin(),
2438 std::bind2nd(SSToLower
<CT
>(), loc
));
2441 // ...but if it were, this would probably work better. Also, this way
2442 // seems to be a bit faster when anything other then the "C" locale is
2447 // sslwr(this->GetBuf(), this->size(), loc);
2456 return Trim().ToLower();
2460 // -------------------------------------------------------------------------
2461 // CStdStr -- Direct access to character buffer. In the MS' implementation,
2462 // the at() function that we use here also calls _Freeze() providing us some
2463 // protection from multithreading problems associated with ref-counting.
2464 // In VC 7 and later, of course, the ref-counting stuff is gone.
2465 // -------------------------------------------------------------------------
2467 CT
* GetBuf(int nMinLen
=-1)
2469 if ( static_cast<int>(this->size()) < nMinLen
)
2470 this->resize(static_cast<MYSIZE
>(nMinLen
));
2472 return this->empty() ? const_cast<CT
*>(this->data()) : &(this->at(0));
2475 CT
* SetBuf(int nLen
)
2477 nLen
= ( nLen
> 0 ? nLen
: 0 );
2478 if ( this->capacity() < 1 && nLen
== 0 )
2481 this->resize(static_cast<MYSIZE
>(nLen
));
2482 return const_cast<CT
*>(this->data());
2484 void RelBuf(int nNewLen
=-1)
2486 this->resize(static_cast<MYSIZE
>(nNewLen
> -1 ? nNewLen
:
2487 sslen(this->c_str())));
2490 void BufferRel() { RelBuf(); } // backwards compatability
2491 CT
* Buffer() { return GetBuf(); } // backwards compatability
2492 CT
* BufferSet(int nLen
) { return SetBuf(nLen
);}// backwards compatability
2494 bool Equals(const CT
* pT
, bool bUseCase
=false) const
2496 return 0 == (bUseCase
? this->compare(pT
) : ssicmp(this->c_str(), pT
));
2499 // -------------------------------------------------------------------------
2500 // FUNCTION: CStdStr::Load
2502 // Loads string from resource specified by nID
2505 // nID - resource Identifier. Purely a Win32 thing in this case
2508 // true if successful, false otherwise
2509 // -------------------------------------------------------------------------
2513 bool Load(UINT nId
, HMODULE hModule
=NULL
)
2515 bool bLoaded
= false; // set to true of we succeed.
2517 #ifdef _MFC_VER // When in Rome (or MFC land)...
2519 // If they gave a resource handle, use it. Note - this is archaic
2520 // and not really what I would recommend. But then again, in MFC
2521 // land, you ought to be using CString for resources anyway since
2522 // it walks the resource chain for you.
2524 HMODULE hModuleOld
= NULL
;
2526 if ( NULL
!= hModule
)
2528 hModuleOld
= AfxGetResourceHandle();
2529 AfxSetResourceHandle(hModule
);
2532 // ...load the string
2535 bLoaded
= FALSE
!= strRes
.LoadString(nId
);
2537 // ...and if we set the resource handle, restore it.
2539 if ( NULL
!= hModuleOld
)
2540 AfxSetResourceHandle(hModule
);
2545 #else // otherwise make our own hackneyed version of CString's Load
2547 // Get the resource name and module handle
2549 if ( NULL
== hModule
)
2550 hModule
= GetResourceHandle();
2552 PCTSTR szName
= MAKEINTRESOURCE((nId
>>4)+1); // lifted
2555 // No sense continuing if we can't find the resource
2557 HRSRC hrsrc
= ::FindResource(hModule
, szName
, RT_STRING
);
2559 if ( NULL
== hrsrc
)
2561 TRACE(_T("Cannot find resource %d: 0x%X"), nId
, ::GetLastError());
2563 else if ( 0 == (dwSize
= ::SizeofResource(hModule
, hrsrc
) / sizeof(CT
)))
2565 TRACE(_T("Cant get size of resource %d 0x%X\n"),nId
,GetLastError());
2569 bLoaded
= 0 != ssload(hModule
, nId
, GetBuf(dwSize
), dwSize
);
2573 #endif // #ifdef _MFC_VER
2576 TRACE(_T("String not loaded 0x%X\n"), ::GetLastError());
2581 #endif // #ifdef SS_ANSI
2583 // -------------------------------------------------------------------------
2584 // FUNCTION: CStdStr::Format
2585 // void _cdecl Formst(CStdStringA& PCSTR szFormat, ...)
2586 // void _cdecl Format(PCSTR szFormat);
2589 // This function does sprintf/wsprintf style formatting on CStdStringA
2590 // objects. It looks a lot like MFC's CString::Format. Some people
2591 // might even call this identical. Fortunately, these people are now
2595 // nId - ID of string resource holding the format string
2596 // szFormat - a PCSTR holding the format specifiers
2597 // argList - a va_list holding the arguments for the format specifiers.
2599 // RETURN VALUE: None.
2600 // -------------------------------------------------------------------------
2601 // formatting (using wsprintf style formatting)
2603 // If they want a Format() function that safely handles string objects
2606 #ifdef SS_SAFE_FORMAT
2608 // Question: Joe, you wacky coder you, why do you have so many overloads
2609 // of the Format() function
2610 // Answer: One reason only - CString compatability. In short, by making
2611 // the Format() function a template this way, I can do strong typing
2612 // and allow people to pass CStdString arguments as fillers for
2613 // "%s" format specifiers without crashing their program! The downside
2614 // is that I need to overload on the number of arguments. If you are
2615 // passing more arguments than I have listed below in any of my
2616 // overloads, just add another one.
2618 // Yes, yes, this is really ugly. In essence what I am doing here is
2619 // protecting people from a bad (and incorrect) programming practice
2620 // that they should not be doing anyway. I am protecting them from
2621 // themselves. Why am I doing this? Well, if you had any idea the
2622 // number of times I've been emailed by people about this
2623 // "incompatability" in my code, you wouldn't ask.
2625 void Fmt(const CT
* szFmt
, ...)
2628 va_start(argList
, szFmt
);
2629 FormatV(szFmt
, argList
);
2635 void Format(UINT nId
)
2638 if ( strFmt
.Load(nId
) )
2642 void Format(UINT nId
, const A1
& v
)
2645 if ( strFmt
.Load(nId
) )
2646 Fmt(strFmt
, FmtArg
<A1
>(v
)());
2648 template<class A1
, class A2
>
2649 void Format(UINT nId
, const A1
& v1
, const A2
& v2
)
2652 if ( strFmt
.Load(nId
) )
2653 Fmt(strFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)());
2655 template<class A1
, class A2
, class A3
>
2656 void Format(UINT nId
, const A1
& v1
, const A2
& v2
, const A3
& v3
)
2659 if ( strFmt
.Load(nId
) )
2661 Fmt(strFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2665 template<class A1
, class A2
, class A3
, class A4
>
2666 void Format(UINT nId
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
2670 if ( strFmt
.Load(nId
) )
2672 Fmt(strFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2673 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)());
2676 template<class A1
, class A2
, class A3
, class A4
, class A5
>
2677 void Format(UINT nId
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
2678 const A4
& v4
, const A5
& v5
)
2681 if ( strFmt
.Load(nId
) )
2683 Fmt(strFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2684 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(), FmtArg
<A5
>(v5
)());
2687 template<class A1
, class A2
, class A3
, class A4
, class A5
, class A6
>
2688 void Format(UINT nId
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
2689 const A4
& v4
, const A5
& v5
, const A6
& v6
)
2692 if ( strFmt
.Load(nId
) )
2694 Fmt(strFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2695 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(),FmtArg
<A5
>(v5
)(),
2699 template<class A1
, class A2
, class A3
, class A4
, class A5
, class A6
,
2701 void Format(UINT nId
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
2702 const A4
& v4
, const A5
& v5
, const A6
& v6
, const A7
& v7
)
2705 if ( strFmt
.Load(nId
) )
2707 Fmt(strFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2708 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(),FmtArg
<A5
>(v5
)(),
2709 FmtArg
<A6
>(v6
)(), FmtArg
<A7
>(v7
)());
2712 template<class A1
, class A2
, class A3
, class A4
, class A5
, class A6
,
2714 void Format(UINT nId
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
2715 const A4
& v4
, const A5
& v5
, const A6
& v6
, const A7
& v7
,
2719 if ( strFmt
.Load(nId
) )
2721 Fmt(strFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2722 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(), FmtArg
<A5
>(v5
)(),
2723 FmtArg
<A6
>(v6
)(), FmtArg
<A7
>(v7
)(), FmtArg
<A8
>(v8
)());
2726 template<class A1
, class A2
, class A3
, class A4
, class A5
, class A6
,
2727 class A7
, class A8
, class A9
>
2728 void Format(UINT nId
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
2729 const A4
& v4
, const A5
& v5
, const A6
& v6
, const A7
& v7
,
2730 const A8
& v8
, const A9
& v9
)
2733 if ( strFmt
.Load(nId
) )
2735 Fmt(strFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2736 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(), FmtArg
<A5
>(v5
)(),
2737 FmtArg
<A6
>(v6
)(), FmtArg
<A7
>(v7
)(), FmtArg
<A8
>(v8
)(),
2741 template<class A1
, class A2
, class A3
, class A4
, class A5
, class A6
,
2742 class A7
, class A8
, class A9
, class A10
>
2743 void Format(UINT nId
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
2744 const A4
& v4
, const A5
& v5
, const A6
& v6
, const A7
& v7
,
2745 const A8
& v8
, const A9
& v9
, const A10
& v10
)
2748 if ( strFmt
.Load(nId
) )
2750 Fmt(strFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2751 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(), FmtArg
<A5
>(v5
)(),
2752 FmtArg
<A6
>(v6
)(), FmtArg
<A7
>(v7
)(), FmtArg
<A8
>(v8
)(),
2753 FmtArg
<A9
>(v9
)(), FmtArg
<A10
>(v10
)());
2756 template<class A1
, class A2
, class A3
, class A4
, class A5
, class A6
,
2757 class A7
, class A8
, class A9
, class A10
, class A11
>
2758 void Format(UINT nId
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
2759 const A4
& v4
, const A5
& v5
, const A6
& v6
, const A7
& v7
,
2760 const A8
& v8
, const A9
& v9
, const A10
& v10
, const A11
& v11
)
2763 if ( strFmt
.Load(nId
) )
2765 Fmt(strFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2766 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(), FmtArg
<A5
>(v5
)(),
2767 FmtArg
<A6
>(v6
)(), FmtArg
<A7
>(v7
)(), FmtArg
<A8
>(v8
)(),
2768 FmtArg
<A9
>(v9
)(),FmtArg
<A10
>(v10
)(),FmtArg
<A11
>(v11
)());
2771 template<class A1
, class A2
, class A3
, class A4
, class A5
, class A6
,
2772 class A7
, class A8
, class A9
, class A10
, class A11
, class A12
>
2773 void Format(UINT nId
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
2774 const A4
& v4
, const A5
& v5
, const A6
& v6
, const A7
& v7
,
2775 const A8
& v8
, const A9
& v9
, const A10
& v10
, const A11
& v11
,
2779 if ( strFmt
.Load(nId
) )
2781 Fmt(strFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2782 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(), FmtArg
<A5
>(v5
)(),
2783 FmtArg
<A6
>(v6
)(), FmtArg
<A7
>(v7
)(), FmtArg
<A8
>(v8
)(),
2784 FmtArg
<A9
>(v9
)(), FmtArg
<A10
>(v10
)(),FmtArg
<A11
>(v11
)(),
2785 FmtArg
<A12
>(v12
)());
2788 template<class A1
, class A2
, class A3
, class A4
, class A5
, class A6
,
2789 class A7
, class A8
, class A9
, class A10
, class A11
, class A12
,
2791 void Format(UINT nId
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
2792 const A4
& v4
, const A5
& v5
, const A6
& v6
, const A7
& v7
,
2793 const A8
& v8
, const A9
& v9
, const A10
& v10
, const A11
& v11
,
2794 const A12
& v12
, const A13
& v13
)
2797 if ( strFmt
.Load(nId
) )
2799 Fmt(strFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2800 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(), FmtArg
<A5
>(v5
)(),
2801 FmtArg
<A6
>(v6
)(), FmtArg
<A7
>(v7
)(), FmtArg
<A8
>(v8
)(),
2802 FmtArg
<A9
>(v9
)(), FmtArg
<A10
>(v10
)(),FmtArg
<A11
>(v11
)(),
2803 FmtArg
<A12
>(v12
)(), FmtArg
<A13
>(v13
)());
2806 template<class A1
, class A2
, class A3
, class A4
, class A5
, class A6
,
2807 class A7
, class A8
, class A9
, class A10
, class A11
, class A12
,
2808 class A13
, class A14
>
2809 void Format(UINT nId
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
2810 const A4
& v4
, const A5
& v5
, const A6
& v6
, const A7
& v7
,
2811 const A8
& v8
, const A9
& v9
, const A10
& v10
, const A11
& v11
,
2812 const A12
& v12
, const A13
& v13
, const A14
& v14
)
2815 if ( strFmt
.Load(nId
) )
2817 Fmt(strFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2818 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(), FmtArg
<A5
>(v5
)(),
2819 FmtArg
<A6
>(v6
)(), FmtArg
<A7
>(v7
)(), FmtArg
<A8
>(v8
)(),
2820 FmtArg
<A9
>(v9
)(), FmtArg
<A10
>(v10
)(),FmtArg
<A11
>(v11
)(),
2821 FmtArg
<A12
>(v12
)(), FmtArg
<A13
>(v13
)(),FmtArg
<A14
>(v14
)());
2824 template<class A1
, class A2
, class A3
, class A4
, class A5
, class A6
,
2825 class A7
, class A8
, class A9
, class A10
, class A11
, class A12
,
2826 class A13
, class A14
, class A15
>
2827 void Format(UINT nId
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
2828 const A4
& v4
, const A5
& v5
, const A6
& v6
, const A7
& v7
,
2829 const A8
& v8
, const A9
& v9
, const A10
& v10
, const A11
& v11
,
2830 const A12
& v12
, const A13
& v13
, const A14
& v14
, const A15
& v15
)
2833 if ( strFmt
.Load(nId
) )
2835 Fmt(strFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2836 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(), FmtArg
<A5
>(v5
)(),
2837 FmtArg
<A6
>(v6
)(), FmtArg
<A7
>(v7
)(), FmtArg
<A8
>(v8
)(),
2838 FmtArg
<A9
>(v9
)(), FmtArg
<A10
>(v10
)(),FmtArg
<A11
>(v11
)(),
2839 FmtArg
<A12
>(v12
)(),FmtArg
<A13
>(v13
)(),FmtArg
<A14
>(v14
)(),
2840 FmtArg
<A15
>(v15
)());
2843 template<class A1
, class A2
, class A3
, class A4
, class A5
, class A6
,
2844 class A7
, class A8
, class A9
, class A10
, class A11
, class A12
,
2845 class A13
, class A14
, class A15
, class A16
>
2846 void Format(UINT nId
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
2847 const A4
& v4
, const A5
& v5
, const A6
& v6
, const A7
& v7
,
2848 const A8
& v8
, const A9
& v9
, const A10
& v10
, const A11
& v11
,
2849 const A12
& v12
, const A13
& v13
, const A14
& v14
, const A15
& v15
,
2853 if ( strFmt
.Load(nId
) )
2855 Fmt(strFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2856 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(), FmtArg
<A5
>(v5
)(),
2857 FmtArg
<A6
>(v6
)(), FmtArg
<A7
>(v7
)(), FmtArg
<A8
>(v8
)(),
2858 FmtArg
<A9
>(v9
)(), FmtArg
<A10
>(v10
)(),FmtArg
<A11
>(v11
)(),
2859 FmtArg
<A12
>(v12
)(),FmtArg
<A13
>(v13
)(),FmtArg
<A14
>(v14
)(),
2860 FmtArg
<A15
>(v15
)(), FmtArg
<A16
>(v16
)());
2863 template<class A1
, class A2
, class A3
, class A4
, class A5
, class A6
,
2864 class A7
, class A8
, class A9
, class A10
, class A11
, class A12
,
2865 class A13
, class A14
, class A15
, class A16
, class A17
>
2866 void Format(UINT nId
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
2867 const A4
& v4
, const A5
& v5
, const A6
& v6
, const A7
& v7
,
2868 const A8
& v8
, const A9
& v9
, const A10
& v10
, const A11
& v11
,
2869 const A12
& v12
, const A13
& v13
, const A14
& v14
, const A15
& v15
,
2870 const A16
& v16
, const A17
& v17
)
2873 if ( strFmt
.Load(nId
) )
2875 Fmt(strFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2876 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(), FmtArg
<A5
>(v5
)(),
2877 FmtArg
<A6
>(v6
)(), FmtArg
<A7
>(v7
)(), FmtArg
<A8
>(v8
)(),
2878 FmtArg
<A9
>(v9
)(), FmtArg
<A10
>(v10
)(),FmtArg
<A11
>(v11
)(),
2879 FmtArg
<A12
>(v12
)(),FmtArg
<A13
>(v13
)(),FmtArg
<A14
>(v14
)(),
2880 FmtArg
<A15
>(v15
)(),FmtArg
<A16
>(v16
)(),FmtArg
<A17
>(v17
)());
2884 #endif // #ifndef SS_ANSI
2886 // ...now the other overload of Format: the one that takes a string literal
2888 void Format(const CT
* szFmt
)
2893 void Format(const CT
* szFmt
, const A1
& v
)
2895 Fmt(szFmt
, FmtArg
<A1
>(v
)());
2897 template<class A1
, class A2
>
2898 void Format(const CT
* szFmt
, const A1
& v1
, const A2
& v2
)
2900 Fmt(szFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)());
2902 template<class A1
, class A2
, class A3
>
2903 void Format(const CT
* szFmt
, const A1
& v1
, const A2
& v2
, const A3
& v3
)
2905 Fmt(szFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2908 template<class A1
, class A2
, class A3
, class A4
>
2909 void Format(const CT
* szFmt
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
2912 Fmt(szFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2913 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)());
2915 template<class A1
, class A2
, class A3
, class A4
, class A5
>
2916 void Format(const CT
* szFmt
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
2917 const A4
& v4
, const A5
& v5
)
2919 Fmt(szFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2920 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(), FmtArg
<A5
>(v5
)());
2922 template<class A1
, class A2
, class A3
, class A4
, class A5
, class A6
>
2923 void Format(const CT
* szFmt
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
2924 const A4
& v4
, const A5
& v5
, const A6
& v6
)
2926 Fmt(szFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2927 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(), FmtArg
<A5
>(v5
)(),
2930 template<class A1
, class A2
, class A3
, class A4
, class A5
, class A6
,
2932 void Format(const CT
* szFmt
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
2933 const A4
& v4
, const A5
& v5
, const A6
& v6
, const A7
& v7
)
2935 Fmt(szFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2936 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(), FmtArg
<A5
>(v5
)(),
2937 FmtArg
<A6
>(v6
)(), FmtArg
<A7
>(v7
)());
2939 template<class A1
, class A2
, class A3
, class A4
, class A5
, class A6
,
2941 void Format(const CT
* szFmt
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
2942 const A4
& v4
, const A5
& v5
, const A6
& v6
, const A7
& v7
,
2945 Fmt(szFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2946 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(), FmtArg
<A5
>(v5
)(),
2947 FmtArg
<A6
>(v6
)(), FmtArg
<A7
>(v7
)(), FmtArg
<A8
>(v8
)());
2949 template<class A1
, class A2
, class A3
, class A4
, class A5
, class A6
,
2950 class A7
, class A8
, class A9
>
2951 void Format(const CT
* szFmt
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
2952 const A4
& v4
, const A5
& v5
, const A6
& v6
, const A7
& v7
,
2953 const A8
& v8
, const A9
& v9
)
2955 Fmt(szFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2956 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(), FmtArg
<A5
>(v5
)(),
2957 FmtArg
<A6
>(v6
)(), FmtArg
<A7
>(v7
)(), FmtArg
<A8
>(v8
)(),
2960 template<class A1
, class A2
, class A3
, class A4
, class A5
, class A6
,
2961 class A7
, class A8
, class A9
, class A10
>
2962 void Format(const CT
* szFmt
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
2963 const A4
& v4
, const A5
& v5
, const A6
& v6
, const A7
& v7
,
2964 const A8
& v8
, const A9
& v9
, const A10
& v10
)
2966 Fmt(szFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2967 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(), FmtArg
<A5
>(v5
)(),
2968 FmtArg
<A6
>(v6
)(), FmtArg
<A7
>(v7
)(), FmtArg
<A8
>(v8
)(),
2969 FmtArg
<A9
>(v9
)(), FmtArg
<A10
>(v10
)());
2971 template<class A1
, class A2
, class A3
, class A4
, class A5
, class A6
,
2972 class A7
, class A8
, class A9
, class A10
, class A11
>
2973 void Format(const CT
* szFmt
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
2974 const A4
& v4
, const A5
& v5
, const A6
& v6
, const A7
& v7
,
2975 const A8
& v8
, const A9
& v9
, const A10
& v10
, const A11
& v11
)
2977 Fmt(szFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2978 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(), FmtArg
<A5
>(v5
)(),
2979 FmtArg
<A6
>(v6
)(), FmtArg
<A7
>(v7
)(), FmtArg
<A8
>(v8
)(),
2980 FmtArg
<A9
>(v9
)(),FmtArg
<A10
>(v10
)(),FmtArg
<A11
>(v11
)());
2982 template<class A1
, class A2
, class A3
, class A4
, class A5
, class A6
,
2983 class A7
, class A8
, class A9
, class A10
, class A11
, class A12
>
2984 void Format(const CT
* szFmt
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
2985 const A4
& v4
, const A5
& v5
, const A6
& v6
, const A7
& v7
,
2986 const A8
& v8
, const A9
& v9
, const A10
& v10
, const A11
& v11
,
2989 Fmt(szFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2990 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(), FmtArg
<A5
>(v5
)(),
2991 FmtArg
<A6
>(v6
)(), FmtArg
<A7
>(v7
)(), FmtArg
<A8
>(v8
)(),
2992 FmtArg
<A9
>(v9
)(), FmtArg
<A10
>(v10
)(),FmtArg
<A11
>(v11
)(),
2993 FmtArg
<A12
>(v12
)());
2995 template<class A1
, class A2
, class A3
, class A4
, class A5
, class A6
,
2996 class A7
, class A8
, class A9
, class A10
, class A11
, class A12
,
2998 void Format(const CT
* szFmt
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
2999 const A4
& v4
, const A5
& v5
, const A6
& v6
, const A7
& v7
,
3000 const A8
& v8
, const A9
& v9
, const A10
& v10
, const A11
& v11
,
3001 const A12
& v12
, const A13
& v13
)
3003 Fmt(szFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
3004 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(), FmtArg
<A5
>(v5
)(),
3005 FmtArg
<A6
>(v6
)(), FmtArg
<A7
>(v7
)(), FmtArg
<A8
>(v8
)(),
3006 FmtArg
<A9
>(v9
)(), FmtArg
<A10
>(v10
)(),FmtArg
<A11
>(v11
)(),
3007 FmtArg
<A12
>(v12
)(), FmtArg
<A13
>(v13
)());
3009 template<class A1
, class A2
, class A3
, class A4
, class A5
, class A6
,
3010 class A7
, class A8
, class A9
, class A10
, class A11
, class A12
,
3011 class A13
, class A14
>
3012 void Format(const CT
* szFmt
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
3013 const A4
& v4
, const A5
& v5
, const A6
& v6
, const A7
& v7
,
3014 const A8
& v8
, const A9
& v9
, const A10
& v10
, const A11
& v11
,
3015 const A12
& v12
, const A13
& v13
, const A14
& v14
)
3017 Fmt(szFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
3018 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(), FmtArg
<A5
>(v5
)(),
3019 FmtArg
<A6
>(v6
)(), FmtArg
<A7
>(v7
)(), FmtArg
<A8
>(v8
)(),
3020 FmtArg
<A9
>(v9
)(), FmtArg
<A10
>(v10
)(),FmtArg
<A11
>(v11
)(),
3021 FmtArg
<A12
>(v12
)(), FmtArg
<A13
>(v13
)(),FmtArg
<A14
>(v14
)());
3023 template<class A1
, class A2
, class A3
, class A4
, class A5
, class A6
,
3024 class A7
, class A8
, class A9
, class A10
, class A11
, class A12
,
3025 class A13
, class A14
, class A15
>
3026 void Format(const CT
* szFmt
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
3027 const A4
& v4
, const A5
& v5
, const A6
& v6
, const A7
& v7
,
3028 const A8
& v8
, const A9
& v9
, const A10
& v10
, const A11
& v11
,
3029 const A12
& v12
, const A13
& v13
, const A14
& v14
, const A15
& v15
)
3031 Fmt(szFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
3032 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(), FmtArg
<A5
>(v5
)(),
3033 FmtArg
<A6
>(v6
)(), FmtArg
<A7
>(v7
)(), FmtArg
<A8
>(v8
)(),
3034 FmtArg
<A9
>(v9
)(), FmtArg
<A10
>(v10
)(),FmtArg
<A11
>(v11
)(),
3035 FmtArg
<A12
>(v12
)(),FmtArg
<A13
>(v13
)(),FmtArg
<A14
>(v14
)(),
3036 FmtArg
<A15
>(v15
)());
3038 template<class A1
, class A2
, class A3
, class A4
, class A5
, class A6
,
3039 class A7
, class A8
, class A9
, class A10
, class A11
, class A12
,
3040 class A13
, class A14
, class A15
, class A16
>
3041 void Format(const CT
* szFmt
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
3042 const A4
& v4
, const A5
& v5
, const A6
& v6
, const A7
& v7
,
3043 const A8
& v8
, const A9
& v9
, const A10
& v10
, const A11
& v11
,
3044 const A12
& v12
, const A13
& v13
, const A14
& v14
, const A15
& v15
,
3047 Fmt(szFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
3048 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(), FmtArg
<A5
>(v5
)(),
3049 FmtArg
<A6
>(v6
)(), FmtArg
<A7
>(v7
)(), FmtArg
<A8
>(v8
)(),
3050 FmtArg
<A9
>(v9
)(), FmtArg
<A10
>(v10
)(),FmtArg
<A11
>(v11
)(),
3051 FmtArg
<A12
>(v12
)(),FmtArg
<A13
>(v13
)(),FmtArg
<A14
>(v14
)(),
3052 FmtArg
<A15
>(v15
)(), FmtArg
<A16
>(v16
)());
3054 template<class A1
, class A2
, class A3
, class A4
, class A5
, class A6
,
3055 class A7
, class A8
, class A9
, class A10
, class A11
, class A12
,
3056 class A13
, class A14
, class A15
, class A16
, class A17
>
3057 void Format(const CT
* szFmt
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
3058 const A4
& v4
, const A5
& v5
, const A6
& v6
, const A7
& v7
,
3059 const A8
& v8
, const A9
& v9
, const A10
& v10
, const A11
& v11
,
3060 const A12
& v12
, const A13
& v13
, const A14
& v14
, const A15
& v15
,
3061 const A16
& v16
, const A17
& v17
)
3063 Fmt(szFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
3064 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(), FmtArg
<A5
>(v5
)(),
3065 FmtArg
<A6
>(v6
)(), FmtArg
<A7
>(v7
)(), FmtArg
<A8
>(v8
)(),
3066 FmtArg
<A9
>(v9
)(), FmtArg
<A10
>(v10
)(),FmtArg
<A11
>(v11
)(),
3067 FmtArg
<A12
>(v12
)(),FmtArg
<A13
>(v13
)(),FmtArg
<A14
>(v14
)(),
3068 FmtArg
<A15
>(v15
)(),FmtArg
<A16
>(v16
)(),FmtArg
<A17
>(v17
)());
3071 #else // #ifdef SS_SAFE_FORMAT
3076 void Format(UINT nId
, ...)
3079 va_start(argList
, nId
);
3082 if ( strFmt
.Load(nId
) )
3083 FormatV(strFmt
, argList
);
3088 #endif // #ifdef SS_ANSI
3090 void Format(const CT
* szFmt
, ...)
3093 va_start(argList
, szFmt
);
3094 FormatV(szFmt
, argList
);
3098 #endif // #ifdef SS_SAFE_FORMAT
3100 void AppendFormat(const CT
* szFmt
, ...)
3103 va_start(argList
, szFmt
);
3104 AppendFormatV(szFmt
, argList
);
3108 #define MAX_FMT_TRIES 5 // #of times we try
3109 #define FMT_BLOCK_SIZE 2048 // # of bytes to increment per try
3110 #define BUFSIZE_1ST 256
3111 #define BUFSIZE_2ND 512
3112 #define STD_BUF_SIZE 1024
3114 // an efficient way to add formatted characters to the string. You may only
3115 // add up to STD_BUF_SIZE characters at a time, though
3116 void AppendFormatV(const CT
* szFmt
, va_list argList
)
3118 CT szBuf
[STD_BUF_SIZE
];
3119 int nLen
= ssnprintf(szBuf
, STD_BUF_SIZE
-1, szFmt
, argList
);
3122 this->append(szBuf
, nLen
);
3125 // -------------------------------------------------------------------------
3126 // FUNCTION: FormatV
3127 // void FormatV(PCSTR szFormat, va_list, argList);
3130 // This function formats the string with sprintf style format-specs.
3131 // It makes a general guess at required buffer size and then tries
3132 // successively larger buffers until it finds one big enough or a
3133 // threshold (MAX_FMT_TRIES) is exceeded.
3136 // szFormat - a PCSTR holding the format of the output
3137 // argList - a Microsoft specific va_list for variable argument lists
3140 // -------------------------------------------------------------------------
3142 // NOTE: Changed by JM to actually function under non-win32,
3143 // and to remove the upper limit on size.
3144 void FormatV(const CT
* szFormat
, va_list argList
)
3146 // try and grab a sufficient buffersize
3147 int nChars
= FMT_BLOCK_SIZE
;
3150 CT
*p
= reinterpret_cast<CT
*>(malloc(sizeof(CT
)*nChars
));
3155 va_copy(argCopy
, argList
);
3157 int nActual
= ssvsprintf(p
, nChars
, szFormat
, argCopy
);
3158 /* If that worked, return the string. */
3159 if (nActual
> -1 && nActual
< nChars
)
3160 { /* make sure it's NULL terminated */
3162 this->assign(p
, nActual
);
3167 /* Else try again with more space. */
3168 if (nActual
> -1) /* glibc 2.1 */
3169 nChars
= nActual
+ 1; /* precisely what is needed */
3170 else /* glibc 2.0 */
3171 nChars
*= 2; /* twice the old size */
3173 CT
*np
= reinterpret_cast<CT
*>(realloc(p
, sizeof(CT
)*nChars
));
3178 return; // failed :(
3185 // -------------------------------------------------------------------------
3186 // CString Facade Functions:
3188 // The following methods are intended to allow you to use this class as a
3189 // near drop-in replacement for CString.
3190 // -------------------------------------------------------------------------
3192 BSTR
AllocSysString() const
3196 return ::SysAllocString(os
.c_str());
3200 #ifndef SS_NO_LOCALE
3201 int Collate(PCMYSTR szThat
) const
3203 return sscoll(this->c_str(), this->length(), szThat
, sslen(szThat
));
3206 int CollateNoCase(PCMYSTR szThat
) const
3208 return ssicoll(this->c_str(), this->length(), szThat
, sslen(szThat
));
3211 int Compare(PCMYSTR szThat
) const
3213 return this->compare(szThat
);
3216 int CompareNoCase(PCMYSTR szThat
) const
3218 return ssicmp(this->c_str(), szThat
);
3221 int Delete(int nIdx
, int nCount
=1)
3226 if ( nIdx
< this->GetLength() )
3227 this->erase(static_cast<MYSIZE
>(nIdx
), static_cast<MYSIZE
>(nCount
));
3237 int Find(CT ch
) const
3239 MYSIZE nIdx
= this->find_first_of(ch
);
3240 return static_cast<int>(MYBASE::npos
== nIdx
? -1 : nIdx
);
3243 int Find(PCMYSTR szSub
) const
3245 MYSIZE nIdx
= this->find(szSub
);
3246 return static_cast<int>(MYBASE::npos
== nIdx
? -1 : nIdx
);
3249 int Find(CT ch
, int nStart
) const
3251 // CString::Find docs say add 1 to nStart when it's not zero
3252 // CString::Find code doesn't do that however. We'll stick
3253 // with what the code does
3255 MYSIZE nIdx
= this->find_first_of(ch
, static_cast<MYSIZE
>(nStart
));
3256 return static_cast<int>(MYBASE::npos
== nIdx
? -1 : nIdx
);
3259 int Find(PCMYSTR szSub
, int nStart
) const
3261 // CString::Find docs say add 1 to nStart when it's not zero
3262 // CString::Find code doesn't do that however. We'll stick
3263 // with what the code does
3265 MYSIZE nIdx
= this->find(szSub
, static_cast<MYSIZE
>(nStart
));
3266 return static_cast<int>(MYBASE::npos
== nIdx
? -1 : nIdx
);
3269 int FindOneOf(PCMYSTR szCharSet
) const
3271 MYSIZE nIdx
= this->find_first_of(szCharSet
);
3272 return static_cast<int>(MYBASE::npos
== nIdx
? -1 : nIdx
);
3276 void FormatMessage(PCMYSTR szFormat
, ...) throw(std::exception
)
3279 va_start(argList
, szFormat
);
3281 if ( ssfmtmsg(FORMAT_MESSAGE_FROM_STRING
|FORMAT_MESSAGE_ALLOCATE_BUFFER
,
3283 reinterpret_cast<PMYSTR
>(&szTemp
), 0, &argList
) == 0 ||
3286 throw std::runtime_error("out of memory");
3293 void FormatMessage(UINT nFormatId
, ...) throw(std::exception
)
3296 VERIFY(sFormat
.LoadString(nFormatId
));
3298 va_start(argList
, nFormatId
);
3300 if ( ssfmtmsg(FORMAT_MESSAGE_FROM_STRING
|FORMAT_MESSAGE_ALLOCATE_BUFFER
,
3302 reinterpret_cast<PMYSTR
>(&szTemp
), 0, &argList
) == 0 ||
3305 throw std::runtime_error("out of memory");
3313 // GetAllocLength -- an MSVC7 function but it costs us nothing to add it.
3315 int GetAllocLength()
3317 return static_cast<int>(this->capacity());
3320 // -------------------------------------------------------------------------
3321 // GetXXXX -- Direct access to character buffer
3322 // -------------------------------------------------------------------------
3323 CT
GetAt(int nIdx
) const
3325 return this->at(static_cast<MYSIZE
>(nIdx
));
3328 CT
* GetBuffer(int nMinLen
=-1)
3330 return GetBuf(nMinLen
);
3333 CT
* GetBufferSetLength(int nLen
)
3335 return BufferSet(nLen
);
3338 // GetLength() -- MFC docs say this is the # of BYTES but
3339 // in truth it is the number of CHARACTERs (chars or wchar_ts)
3340 int GetLength() const
3342 return static_cast<int>(this->length());
3345 int Insert(int nIdx
, CT ch
)
3347 if ( static_cast<MYSIZE
>(nIdx
) > this->size()-1 )
3348 this->append(1, ch
);
3350 this->insert(static_cast<MYSIZE
>(nIdx
), 1, ch
);
3354 int Insert(int nIdx
, PCMYSTR sz
)
3356 if ( static_cast<MYSIZE
>(nIdx
) >= this->size() )
3357 this->append(sz
, static_cast<MYSIZE
>(sslen(sz
)));
3359 this->insert(static_cast<MYSIZE
>(nIdx
), sz
);
3364 bool IsEmpty() const
3366 return this->empty();
3369 MYTYPE
Left(int nCount
) const
3371 // Range check the count.
3373 nCount
= SSMAX(0, SSMIN(nCount
, static_cast<int>(this->size())));
3374 return this->substr(0, static_cast<MYSIZE
>(nCount
));
3378 bool LoadString(UINT nId
)
3380 return this->Load(nId
);
3391 std::reverse(this->begin(), this->end());
3399 MYTYPE
Mid(int nFirst
) const
3401 return Mid(nFirst
, this->GetLength()-nFirst
);
3404 MYTYPE
Mid(int nFirst
, int nCount
) const
3406 // CString does range checking here. Since we're trying to emulate it,
3407 // we must check too.
3414 int nSize
= static_cast<int>(this->size());
3416 if ( nFirst
+ nCount
> nSize
)
3417 nCount
= nSize
- nFirst
;
3419 if ( nFirst
> nSize
)
3422 ASSERT(nFirst
>= 0);
3423 ASSERT(nFirst
+ nCount
<= nSize
);
3425 return this->substr(static_cast<MYSIZE
>(nFirst
),
3426 static_cast<MYSIZE
>(nCount
));
3429 void ReleaseBuffer(int nNewLen
=-1)
3438 while ( (nIdx
=this->find_first_of(ch
)) != MYBASE::npos
)
3440 this->erase(nIdx
, 1);
3446 int Replace(CT chOld
, CT chNew
)
3450 for ( MYITER iter
=this->begin(); iter
!= this->end(); iter
++ )
3452 if ( *iter
== chOld
)
3462 int Replace(PCMYSTR szOld
, PCMYSTR szNew
)
3466 MYSIZE nOldLen
= sslen(szOld
);
3470 // If the replacement string is longer than the one it replaces, this
3471 // string is going to have to grow in size, Figure out how much
3472 // and grow it all the way now, rather than incrementally
3474 MYSIZE nNewLen
= sslen(szNew
);
3475 if ( nNewLen
> nOldLen
)
3478 while ( nIdx
< this->length() &&
3479 (nIdx
=this->find(szOld
, nIdx
)) != MYBASE::npos
)
3484 this->reserve(this->size() + nFound
* (nNewLen
- nOldLen
));
3488 static const CT ch
= CT(0);
3489 PCMYSTR szRealNew
= szNew
== 0 ? &ch
: szNew
;
3492 while ( nIdx
< this->length() &&
3493 (nIdx
=this->find(szOld
, nIdx
)) != MYBASE::npos
)
3495 this->replace(this->begin()+nIdx
, this->begin()+nIdx
+nOldLen
,
3506 int ReverseFind(CT ch
) const
3508 MYSIZE nIdx
= this->find_last_of(ch
);
3509 return static_cast<int>(MYBASE::npos
== nIdx
? -1 : nIdx
);
3512 // ReverseFind overload that's not in CString but might be useful
3513 int ReverseFind(PCMYSTR szFind
, MYSIZE pos
=MYBASE::npos
) const
3515 //yuvalt - this does not compile with g++ since MYTTYPE() is different type
3516 //MYSIZE nIdx = this->rfind(0 == szFind ? MYTYPE() : szFind, pos);
3517 MYSIZE nIdx
= this->rfind(0 == szFind
? "" : szFind
, pos
);
3518 return static_cast<int>(MYBASE::npos
== nIdx
? -1 : nIdx
);
3521 MYTYPE
Right(int nCount
) const
3523 // Range check the count.
3525 nCount
= SSMAX(0, SSMIN(nCount
, static_cast<int>(this->size())));
3526 return this->substr(this->size()-static_cast<MYSIZE
>(nCount
));
3529 void SetAt(int nIndex
, CT ch
)
3531 ASSERT(this->size() > static_cast<MYSIZE
>(nIndex
));
3532 this->at(static_cast<MYSIZE
>(nIndex
)) = ch
;
3536 BSTR
SetSysString(BSTR
* pbstr
) const
3540 if ( !::SysReAllocStringLen(pbstr
, os
.c_str(), os
.length()) )
3541 throw std::runtime_error("out of memory");
3543 ASSERT(*pbstr
!= 0);
3548 MYTYPE
SpanExcluding(PCMYSTR szCharSet
) const
3550 MYSIZE pos
= this->find_first_of(szCharSet
);
3551 return pos
== MYBASE::npos
? *this : Left(pos
);
3554 MYTYPE
SpanIncluding(PCMYSTR szCharSet
) const
3556 MYSIZE pos
= this->find_first_not_of(szCharSet
);
3557 return pos
== MYBASE::npos
? *this : Left(pos
);
3560 #if defined SS_WIN32 && !defined(UNICODE) && !defined(SS_ANSI)
3562 // CString's OemToAnsi and AnsiToOem functions are available only in
3563 // Unicode builds. However since we're a template we also need a
3564 // runtime check of CT and a reinterpret_cast to account for the fact
3565 // that CStdStringW gets instantiated even in non-Unicode builds.
3569 if ( sizeof(CT
) == sizeof(char) && !empty() )
3571 ::CharToOem(reinterpret_cast<PCSTR
>(this->c_str()),
3572 reinterpret_cast<PSTR
>(GetBuf()));
3582 if ( sizeof(CT
) == sizeof(char) && !empty() )
3584 ::OemToChar(reinterpret_cast<PCSTR
>(this->c_str()),
3585 reinterpret_cast<PSTR
>(GetBuf()));
3596 // -------------------------------------------------------------------------
3597 // Trim and its variants
3598 // -------------------------------------------------------------------------
3601 return TrimLeft().TrimRight();
3606 this->erase(this->begin(),
3607 std::find_if(this->begin(), this->end(), NotSpace
<CT
>()));
3612 MYTYPE
& TrimLeft(CT tTrim
)
3614 this->erase(0, this->find_first_not_of(tTrim
));
3618 MYTYPE
& TrimLeft(PCMYSTR szTrimChars
)
3620 this->erase(0, this->find_first_not_of(szTrimChars
));
3626 // NOTE: When comparing reverse_iterators here (MYRITER), I avoid using
3627 // operator!=. This is because namespace rel_ops also has a template
3628 // operator!= which conflicts with the global operator!= already defined
3629 // for reverse_iterator in the header <utility>.
3630 // Thanks to John James for alerting me to this.
3632 MYRITER it
= std::find_if(this->rbegin(), this->rend(), NotSpace
<CT
>());
3633 if ( !(this->rend() == it
) )
3634 this->erase(this->rend() - it
);
3636 this->erase(!(it
== this->rend()) ? this->find_last_of(*it
) + 1 : 0);
3640 MYTYPE
& TrimRight(CT tTrim
)
3642 MYSIZE nIdx
= this->find_last_not_of(tTrim
);
3643 this->erase(MYBASE::npos
== nIdx
? 0 : ++nIdx
);
3647 MYTYPE
& TrimRight(PCMYSTR szTrimChars
)
3649 MYSIZE nIdx
= this->find_last_not_of(szTrimChars
);
3650 this->erase(MYBASE::npos
== nIdx
? 0 : ++nIdx
);
3659 this->assign(mt
.c_str(), mt
.size());
3662 // I have intentionally not implemented the following CString
3663 // functions. You cannot make them work without taking advantage
3664 // of implementation specific behavior. However if you absolutely
3665 // MUST have them, uncomment out these lines for "sort-of-like"
3666 // their behavior. You're on your own.
3668 // CT* LockBuffer() { return GetBuf(); }// won't really lock
3669 // void UnlockBuffer(); { } // why have UnlockBuffer w/o LockBuffer?
3671 // Array-indexing operators. Required because we defined an implicit cast
3672 // to operator const CT* (Thanks to Julian Selman for pointing this out)
3674 CT
& operator[](int nIdx
)
3676 return static_cast<MYBASE
*>(this)->operator[](static_cast<MYSIZE
>(nIdx
));
3679 const CT
& operator[](int nIdx
) const
3681 return static_cast<const MYBASE
*>(this)->operator[](static_cast<MYSIZE
>(nIdx
));
3684 CT
& operator[](unsigned int nIdx
)
3686 return static_cast<MYBASE
*>(this)->operator[](static_cast<MYSIZE
>(nIdx
));
3689 const CT
& operator[](unsigned int nIdx
) const
3691 return static_cast<const MYBASE
*>(this)->operator[](static_cast<MYSIZE
>(nIdx
));
3694 CT
& operator[](unsigned long nIdx
)
3696 return static_cast<MYBASE
*>(this)->operator[](static_cast<MYSIZE
>(nIdx
));
3699 const CT
& operator[](unsigned long nIdx
) const
3701 return static_cast<const MYBASE
*>(this)->operator[](static_cast<MYSIZE
>(nIdx
));
3704 #ifndef SS_NO_IMPLICIT_CAST
3705 operator const CT
*() const
3707 return this->c_str();
3711 // IStream related functions. Useful in IPersistStream implementations
3713 #ifdef SS_INC_COMDEF
3715 // struct SSSHDR - useful for non Std C++ persistence schemes.
3716 typedef struct SSSHDR
3720 } SSSHDR
; // as in "Standard String Stream Header"
3722 #define SSSO_UNICODE 0x01 // the string is a wide string
3723 #define SSSO_COMPRESS 0x02 // the string is compressed
3725 // -------------------------------------------------------------------------
3726 // FUNCTION: StreamSize
3728 // Returns how many bytes it will take to StreamSave() this CStdString
3729 // object to an IStream.
3730 // -------------------------------------------------------------------------
3731 ULONG
StreamSize() const
3733 // Control header plus string
3734 ASSERT(this->size()*sizeof(CT
) < 0xffffffffUL
- sizeof(SSSHDR
));
3735 return (this->size() * sizeof(CT
)) + sizeof(SSSHDR
);
3738 // -------------------------------------------------------------------------
3739 // FUNCTION: StreamSave
3741 // Saves this CStdString object to a COM IStream.
3742 // -------------------------------------------------------------------------
3743 HRESULT
StreamSave(IStream
* pStream
) const
3745 ASSERT(this->size()*sizeof(CT
) < 0xffffffffUL
- sizeof(SSSHDR
));
3746 HRESULT hr
= E_FAIL
;
3747 ASSERT(pStream
!= 0);
3749 hdr
.byCtrl
= sizeof(CT
) == 2 ? SSSO_UNICODE
: 0;
3750 hdr
.nChars
= this->size();
3753 if ( FAILED(hr
=pStream
->Write(&hdr
, sizeof(SSSHDR
), 0)) )
3755 TRACE(_T("StreamSave: Cannot write control header, ERR=0x%X\n"),hr
);
3759 ; // nothing to write
3761 else if ( FAILED(hr
=pStream
->Write(this->c_str(),
3762 this->size()*sizeof(CT
), 0)) )
3764 TRACE(_T("StreamSave: Cannot write string to stream 0x%X\n"), hr
);
3771 // -------------------------------------------------------------------------
3772 // FUNCTION: StreamLoad
3774 // This method loads the object from an IStream.
3775 // -------------------------------------------------------------------------
3776 HRESULT
StreamLoad(IStream
* pStream
)
3778 ASSERT(pStream
!= 0);
3780 HRESULT hr
= E_FAIL
;
3782 if ( FAILED(hr
=pStream
->Read(&hdr
, sizeof(SSSHDR
), 0)) )
3784 TRACE(_T("StreamLoad: Cant read control header, ERR=0x%X\n"), hr
);
3786 else if ( hdr
.nChars
> 0 )
3789 PMYSTR pMyBuf
= BufferSet(hdr
.nChars
);
3791 // If our character size matches the character size of the string
3792 // we're trying to read, then we can read it directly into our
3793 // buffer. Otherwise, we have to read into an intermediate buffer
3796 if ( (hdr
.byCtrl
& SSSO_UNICODE
) != 0 )
3798 ULONG nBytes
= hdr
.nChars
* sizeof(wchar_t);
3799 if ( sizeof(CT
) == sizeof(wchar_t) )
3801 if ( FAILED(hr
=pStream
->Read(pMyBuf
, nBytes
, &nRead
)) )
3802 TRACE(_T("StreamLoad: Cannot read string: 0x%X\n"), hr
);
3806 PWSTR pBufW
= reinterpret_cast<PWSTR
>(_alloca((nBytes
)+1));
3807 if ( FAILED(hr
=pStream
->Read(pBufW
, nBytes
, &nRead
)) )
3808 TRACE(_T("StreamLoad: Cannot read string: 0x%X\n"), hr
);
3810 sscpy(pMyBuf
, pBufW
, hdr
.nChars
);
3815 ULONG nBytes
= hdr
.nChars
* sizeof(char);
3816 if ( sizeof(CT
) == sizeof(char) )
3818 if ( FAILED(hr
=pStream
->Read(pMyBuf
, nBytes
, &nRead
)) )
3819 TRACE(_T("StreamLoad: Cannot read string: 0x%X\n"), hr
);
3823 PSTR pBufA
= reinterpret_cast<PSTR
>(_alloca(nBytes
));
3824 if ( FAILED(hr
=pStream
->Read(pBufA
, hdr
.nChars
, &nRead
)) )
3825 TRACE(_T("StreamLoad: Cannot read string: 0x%X\n"), hr
);
3827 sscpy(pMyBuf
, pBufA
, hdr
.nChars
);
3837 #endif // #ifdef SS_INC_COMDEF
3841 // SetResourceHandle/GetResourceHandle. In MFC builds, these map directly
3842 // to AfxSetResourceHandle and AfxGetResourceHandle. In non-MFC builds they
3843 // point to a single static HINST so that those who call the member
3844 // functions that take resource IDs can provide an alternate HINST of a DLL
3845 // to search. This is not exactly the list of HMODULES that MFC provides
3846 // but it's better than nothing.
3849 static void SetResourceHandle(HMODULE hNew
)
3851 AfxSetResourceHandle(hNew
);
3853 static HMODULE
GetResourceHandle()
3855 return AfxGetResourceHandle();
3858 static void SetResourceHandle(HMODULE hNew
)
3860 SSResourceHandle() = hNew
;
3862 static HMODULE
GetResourceHandle()
3864 return SSResourceHandle();
3871 // -----------------------------------------------------------------------------
3872 // MSVC USERS: HOW TO EXPORT CSTDSTRING FROM A DLL
3874 // If you are using MS Visual C++ and you want to export CStdStringA and
3875 // CStdStringW from a DLL, then all you need to
3877 // 1. make sure that all components link to the same DLL version
3878 // of the CRT (not the static one).
3879 // 2. Uncomment the 3 lines of code below
3880 // 3. #define 2 macros per the instructions in MS KnowledgeBase
3881 // article Q168958. The macros are:
3883 // MACRO DEFINTION WHEN EXPORTING DEFINITION WHEN IMPORTING
3884 // ----- ------------------------ -------------------------
3885 // SSDLLEXP (nothing, just #define it) extern
3886 // SSDLLSPEC __declspec(dllexport) __declspec(dllimport)
3888 // Note that these macros must be available to ALL clients who want to
3889 // link to the DLL and use the class. If they
3891 // A word of advice: Don't bother.
3893 // Really, it is not necessary to export CStdString functions from a DLL. I
3894 // never do. In my projects, I do generally link to the DLL version of the
3895 // Standard C++ Library, but I do NOT attempt to export CStdString functions.
3896 // I simply include the header where it is needed and allow for the code
3899 // That redundancy is a lot less than you think. This class does most of its
3900 // work via the Standard C++ Library, particularly the base_class basic_string<>
3901 // member functions. Most of the functions here are small enough to be inlined
3902 // anyway. Besides, you'll find that in actual practice you use less than 1/2
3903 // of the code here, even in big projects and different modules will use as
3904 // little as 10% of it. That means a lot less functions actually get linked
3905 // your binaries. If you export this code from a DLL, it ALL gets linked in.
3907 // I've compared the size of the binaries from exporting vs NOT exporting. Take
3908 // my word for it -- exporting this code is not worth the hassle.
3910 // -----------------------------------------------------------------------------
3911 //#pragma warning(disable:4231) // non-standard extension ("extern template")
3912 // SSDLLEXP template class SSDLLSPEC CStdStr<char>;
3913 // SSDLLEXP template class SSDLLSPEC CStdStr<wchar_t>;
3916 // =============================================================================
3917 // END OF CStdStr INLINE FUNCTION DEFINITIONS
3918 // =============================================================================
3920 // Now typedef our class names based upon this humongous template
3922 typedef CStdStr
<char> CStdStringA
; // a better std::string
3923 typedef CStdStr
<wchar_t> CStdStringW
; // a better std::wstring
3924 typedef CStdStr
<uint16_t> CStdString16
; // a 16bit char string
3925 typedef CStdStr
<uint32_t> CStdString32
; // a 32bit char string
3926 typedef CStdStr
<OLECHAR
> CStdStringO
; // almost always CStdStringW
3928 // -----------------------------------------------------------------------------
3929 // CStdStr addition functions defined as inline
3930 // -----------------------------------------------------------------------------
3933 inline CStdStringA
operator+(const CStdStringA
& s1
, const CStdStringA
& s2
)
3935 CStdStringA
sRet(SSREF(s1
));
3939 inline CStdStringA
operator+(const CStdStringA
& s1
, CStdStringA::value_type t
)
3941 CStdStringA
sRet(SSREF(s1
));
3945 inline CStdStringA
operator+(const CStdStringA
& s1
, PCSTR pA
)
3947 CStdStringA
sRet(SSREF(s1
));
3951 inline CStdStringA
operator+(PCSTR pA
, const CStdStringA
& sA
)
3954 CStdStringA::size_type nObjSize
= sA
.size();
3955 CStdStringA::size_type nLitSize
=
3956 static_cast<CStdStringA::size_type
>(sslen(pA
));
3958 sRet
.reserve(nLitSize
+ nObjSize
);
3965 inline CStdStringA
operator+(const CStdStringA
& s1
, const CStdStringW
& s2
)
3967 return s1
+ CStdStringA(s2
);
3969 inline CStdStringW
operator+(const CStdStringW
& s1
, const CStdStringW
& s2
)
3971 CStdStringW
sRet(SSREF(s1
));
3975 inline CStdStringA
operator+(const CStdStringA
& s1
, PCWSTR pW
)
3977 return s1
+ CStdStringA(pW
);
3981 inline CStdStringW
operator+(PCWSTR pW
, const CStdStringA
& sA
)
3983 return CStdStringW(pW
) + CStdStringW(SSREF(sA
));
3985 inline CStdStringW
operator+(PCSTR pA
, const CStdStringW
& sW
)
3987 return CStdStringW(pA
) + sW
;
3990 inline CStdStringA
operator+(PCWSTR pW
, const CStdStringA
& sA
)
3992 return CStdStringA(pW
) + sA
;
3994 inline CStdStringA
operator+(PCSTR pA
, const CStdStringW
& sW
)
3996 return pA
+ CStdStringA(sW
);
4000 // ...Now the wide string versions.
4001 inline CStdStringW
operator+(const CStdStringW
& s1
, CStdStringW::value_type t
)
4003 CStdStringW
sRet(SSREF(s1
));
4007 inline CStdStringW
operator+(const CStdStringW
& s1
, PCWSTR pW
)
4009 CStdStringW
sRet(SSREF(s1
));
4013 inline CStdStringW
operator+(PCWSTR pW
, const CStdStringW
& sW
)
4016 CStdStringW::size_type nObjSize
= sW
.size();
4017 CStdStringA::size_type nLitSize
=
4018 static_cast<CStdStringW::size_type
>(sslen(pW
));
4020 sRet
.reserve(nLitSize
+ nObjSize
);
4026 inline CStdStringW
operator+(const CStdStringW
& s1
, const CStdStringA
& s2
)
4028 return s1
+ CStdStringW(s2
);
4030 inline CStdStringW
operator+(const CStdStringW
& s1
, PCSTR pA
)
4032 return s1
+ CStdStringW(pA
);
4036 // New-style format function is a template
4038 #ifdef SS_SAFE_FORMAT
4041 struct FmtArg
<CStdStringA
>
4043 explicit FmtArg(const CStdStringA
& arg
) : a_(arg
) {}
4044 PCSTR
operator()() const { return a_
.c_str(); }
4045 const CStdStringA
& a_
;
4047 FmtArg
<CStdStringA
>& operator=(const FmtArg
<CStdStringA
>&) { return *this; }
4050 struct FmtArg
<CStdStringW
>
4052 explicit FmtArg(const CStdStringW
& arg
) : a_(arg
) {}
4053 PCWSTR
operator()() const { return a_
.c_str(); }
4054 const CStdStringW
& a_
;
4056 FmtArg
<CStdStringW
>& operator=(const FmtArg
<CStdStringW
>&) { return *this; }
4060 struct FmtArg
<std::string
>
4062 explicit FmtArg(const std::string
& arg
) : a_(arg
) {}
4063 PCSTR
operator()() const { return a_
.c_str(); }
4064 const std::string
& a_
;
4066 FmtArg
<std::string
>& operator=(const FmtArg
<std::string
>&) { return *this; }
4069 struct FmtArg
<std::wstring
>
4071 explicit FmtArg(const std::wstring
& arg
) : a_(arg
) {}
4072 PCWSTR
operator()() const { return a_
.c_str(); }
4073 const std::wstring
& a_
;
4075 FmtArg
<std::wstring
>& operator=(const FmtArg
<std::wstring
>&) {return *this;}
4077 #endif // #ifdef SS_SAFEFORMAT
4080 // SSResourceHandle: our MFC-like resource handle
4081 inline HMODULE
& SSResourceHandle()
4083 static HMODULE hModuleSS
= GetModuleHandle(0);
4089 // In MFC builds, define some global serialization operators
4090 // Special operators that allow us to serialize CStdStrings to CArchives.
4091 // Note that we use an intermediate CString object in order to ensure that
4092 // we use the exact same format.
4095 inline CArchive
& AFXAPI
operator<<(CArchive
& ar
, const CStdStringA
& strA
)
4097 CString strTemp
= strA
;
4098 return ar
<< strTemp
;
4100 inline CArchive
& AFXAPI
operator<<(CArchive
& ar
, const CStdStringW
& strW
)
4102 CString strTemp
= strW
;
4103 return ar
<< strTemp
;
4106 inline CArchive
& AFXAPI
operator>>(CArchive
& ar
, CStdStringA
& strA
)
4113 inline CArchive
& AFXAPI
operator>>(CArchive
& ar
, CStdStringW
& strW
)
4120 #endif // #ifdef _MFC_VER -- (i.e. is this MFC?)
4124 // -----------------------------------------------------------------------------
4125 // GLOBAL FUNCTION: WUFormat
4126 // CStdStringA WUFormat(UINT nId, ...);
4127 // CStdStringA WUFormat(PCSTR szFormat, ...);
4130 // This function allows the caller for format and return a CStdStringA
4131 // object with a single line of code.
4132 // -----------------------------------------------------------------------------
4135 inline CStdStringA
WUFormatA(UINT nId
, ...)
4138 va_start(argList
, nId
);
4142 if ( strFmt
.Load(nId
) )
4143 strOut
.FormatV(strFmt
, argList
);
4148 inline CStdStringA
WUFormatA(PCSTR szFormat
, ...)
4151 va_start(argList
, szFormat
);
4153 strOut
.FormatV(szFormat
, argList
);
4157 inline CStdStringW
WUFormatW(UINT nId
, ...)
4160 va_start(argList
, nId
);
4164 if ( strFmt
.Load(nId
) )
4165 strOut
.FormatV(strFmt
, argList
);
4170 inline CStdStringW
WUFormatW(PCWSTR szwFormat
, ...)
4173 va_start(argList
, szwFormat
);
4175 strOut
.FormatV(szwFormat
, argList
);
4179 #endif // #ifdef SS_ANSI
4183 #if defined(SS_WIN32) && !defined (SS_ANSI)
4184 // -------------------------------------------------------------------------
4185 // FUNCTION: WUSysMessage
4186 // CStdStringA WUSysMessageA(DWORD dwError, DWORD dwLangId=SS_DEFLANGID);
4187 // CStdStringW WUSysMessageW(DWORD dwError, DWORD dwLangId=SS_DEFLANGID);
4190 // This function simplifies the process of obtaining a string equivalent
4191 // of a system error code returned from GetLastError(). You simply
4192 // supply the value returned by GetLastError() to this function and the
4193 // corresponding system string is returned in the form of a CStdStringA.
4196 // dwError - a DWORD value representing the error code to be translated
4197 // dwLangId - the language id to use. defaults to english.
4200 // a CStdStringA equivalent of the error code. Currently, this function
4201 // only returns either English of the system default language strings.
4202 // -------------------------------------------------------------------------
4203 #define SS_DEFLANGID MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT)
4204 inline CStdStringA
WUSysMessageA(DWORD dwError
, DWORD dwLangId
=SS_DEFLANGID
)
4208 if ( 0 != ::FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM
, NULL
, dwError
,
4209 dwLangId
, szBuf
, 511, NULL
) )
4210 return WUFormatA("%s (0x%X)", szBuf
, dwError
);
4212 return WUFormatA("Unknown error (0x%X)", dwError
);
4214 inline CStdStringW
WUSysMessageW(DWORD dwError
, DWORD dwLangId
=SS_DEFLANGID
)
4218 if ( 0 != ::FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM
, NULL
, dwError
,
4219 dwLangId
, szBuf
, 511, NULL
) )
4220 return WUFormatW(L
"%s (0x%X)", szBuf
, dwError
);
4222 return WUFormatW(L
"Unknown error (0x%X)", dwError
);
4226 // Define TCHAR based friendly names for some of these functions
4229 //#define CStdString CStdStringW
4230 typedef CStdStringW CStdString
;
4231 #define WUSysMessage WUSysMessageW
4232 #define WUFormat WUFormatW
4234 //#define CStdString CStdStringA
4235 typedef CStdStringA CStdString
;
4236 #define WUSysMessage WUSysMessageA
4237 #define WUFormat WUFormatA
4240 // ...and some shorter names for the space-efficient
4242 #define WUSysMsg WUSysMessage
4243 #define WUSysMsgA WUSysMessageA
4244 #define WUSysMsgW WUSysMessageW
4245 #define WUFmtA WUFormatA
4246 #define WUFmtW WUFormatW
4247 #define WUFmt WUFormat
4248 #define WULastErrMsg() WUSysMessage(::GetLastError())
4249 #define WULastErrMsgA() WUSysMessageA(::GetLastError())
4250 #define WULastErrMsgW() WUSysMessageW(::GetLastError())
4253 // -----------------------------------------------------------------------------
4254 // FUNCTIONAL COMPARATORS:
4256 // These structs are derived from the std::binary_function template. They
4257 // give us functional classes (which may be used in Standard C++ Library
4258 // collections and algorithms) that perform case-insensitive comparisons of
4259 // CStdString objects. This is useful for maps in which the key may be the
4260 // proper string but in the wrong case.
4261 // -----------------------------------------------------------------------------
4262 #define StdStringLessNoCaseW SSLNCW // avoid VC compiler warning 4786
4263 #define StdStringEqualsNoCaseW SSENCW
4264 #define StdStringLessNoCaseA SSLNCA
4265 #define StdStringEqualsNoCaseA SSENCA
4268 #define StdStringLessNoCase SSLNCW
4269 #define StdStringEqualsNoCase SSENCW
4271 #define StdStringLessNoCase SSLNCA
4272 #define StdStringEqualsNoCase SSENCA
4275 struct StdStringLessNoCaseW
4276 : std::binary_function
<CStdStringW
, CStdStringW
, bool>
4279 bool operator()(const CStdStringW
& sLeft
, const CStdStringW
& sRight
) const
4280 { return ssicmp(sLeft
.c_str(), sRight
.c_str()) < 0; }
4282 struct StdStringEqualsNoCaseW
4283 : std::binary_function
<CStdStringW
, CStdStringW
, bool>
4286 bool operator()(const CStdStringW
& sLeft
, const CStdStringW
& sRight
) const
4287 { return ssicmp(sLeft
.c_str(), sRight
.c_str()) == 0; }
4289 struct StdStringLessNoCaseA
4290 : std::binary_function
<CStdStringA
, CStdStringA
, bool>
4293 bool operator()(const CStdStringA
& sLeft
, const CStdStringA
& sRight
) const
4294 { return ssicmp(sLeft
.c_str(), sRight
.c_str()) < 0; }
4296 struct StdStringEqualsNoCaseA
4297 : std::binary_function
<CStdStringA
, CStdStringA
, bool>
4300 bool operator()(const CStdStringA
& sLeft
, const CStdStringA
& sRight
) const
4301 { return ssicmp(sLeft
.c_str(), sRight
.c_str()) == 0; }
4304 // If we had to define our own version of TRACE above, get rid of it now
4306 #ifdef TRACE_DEFINED_HERE
4308 #undef TRACE_DEFINED_HERE
4312 // These std::swap specializations come courtesy of Mike Crusader.
4316 // inline void swap(CStdStringA& s1, CStdStringA& s2) throw()
4321 // inline void swap(CStdStringW& s1, CStdStringW& s2) throw()
4327 // Turn back on any Borland warnings we turned off.
4330 #pragma option pop // Turn back on inline function warnings
4331 // #pragma warn +inl // Turn back on inline function warnings
4334 typedef std::vector
<CStdString
> CStdStringArray
;
4336 #endif // #ifndef STDSTRING_H