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) (((uint64_t)(_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 #if defined(TARGET_DARWIN) || defined(__FreeBSD__) || defined(TARGET_ANDROID)
868 SSCodeCvt::state_type st
= { { 0 } };
870 SSCodeCvt::state_type st
= { 0 };
873 pSrcA
, pSrcA
+ nSrc
, pNextSrcA
,
874 pDstW
, pDstW
+ nDst
, pNextDstW
);
876 #define ASSERT2(a) if (!(a)) {fprintf(stderr, "StdString: Assertion Failed on line %d\n", __LINE__);}
878 #define ASSERT2 ASSERT
880 ASSERT2(SSCodeCvt::ok
== res
);
881 ASSERT2(SSCodeCvt::error
!= res
);
882 ASSERT2(pNextDstW
>= pDstW
);
883 ASSERT2(pNextSrcA
>= pSrcA
);
885 // Null terminate the converted string
887 if ( pNextDstW
- pDstW
> nDst
)
888 *(pDstW
+ nDst
) = '\0';
894 inline PWSTR
StdCodeCvt(PWSTR pDstW
, int nDst
, PCUSTR pSrcA
, int nSrc
,
895 const std::locale
& loc
=std::locale())
897 return StdCodeCvt(pDstW
, nDst
, (PCSTR
)pSrcA
, nSrc
, loc
);
900 inline PSTR
StdCodeCvt(PSTR pDstA
, int nDst
, PCWSTR pSrcW
, int nSrc
,
901 const std::locale
& loc
=std::locale())
910 PSTR pNextDstA
= pDstA
;
911 PCWSTR pNextSrcW
= pSrcW
;
912 SSCodeCvt::result res
= SSCodeCvt::ok
;
913 const SSCodeCvt
& conv
= SS_USE_FACET(loc
, SSCodeCvt
);
914 #if defined(TARGET_DARWIN) || defined(__FreeBSD__) || defined(TARGET_ANDROID)
915 SSCodeCvt::state_type st
= { { 0 } };
917 SSCodeCvt::state_type st
= { 0 };
920 pSrcW
, pSrcW
+ nSrc
, pNextSrcW
,
921 pDstA
, pDstA
+ nDst
, pNextDstA
);
923 #define ASSERT2(a) if (!(a)) {fprintf(stderr, "StdString: Assertion Failed on line %d\n", __LINE__);}
925 #define ASSERT2 ASSERT
927 ASSERT2(SSCodeCvt::error
!= res
);
928 ASSERT2(SSCodeCvt::ok
== res
); // strict, comment out for sanity
929 ASSERT2(pNextDstA
>= pDstA
);
930 ASSERT2(pNextSrcW
>= pSrcW
);
933 // Null terminate the converted string
935 if ( pNextDstA
- pDstA
> nDst
)
936 *(pDstA
+ nDst
) = '\0';
943 inline PUSTR
StdCodeCvt(PUSTR pDstA
, int nDst
, PCWSTR pSrcW
, int nSrc
,
944 const std::locale
& loc
=std::locale())
946 return (PUSTR
)StdCodeCvt((PSTR
)pDstA
, nDst
, pSrcW
, nSrc
, loc
);
953 // Unicode/MBCS conversion macros are only available on implementations of
954 // the "C" library that have the non-standard _alloca function. As far as I
955 // know that's only Microsoft's though I've heard that the function exists
958 #if defined(SS_ALLOCA) && !defined SS_NO_CONVERSION
960 #include <malloc.h> // needed for _alloca
962 // Define our conversion macros to look exactly like Microsoft's to
963 // facilitate using this stuff both with and without MFC/ATL
965 #ifdef _CONVERSION_USES_THREAD_LOCALE
968 #define SSCVT int _cvt; _cvt; UINT _acp=GetACP(); \
969 _acp; PCWSTR _pw; _pw; PCSTR _pa; _pa
971 #define SSCVT int _cvt = 0; _cvt; UINT _acp=GetACP();\
972 _acp; PCWSTR _pw=0; _pw; PCSTR _pa=0; _pa
975 ((_pa = pa) == 0) ? 0 : (\
976 _cvt = (sslen(_pa)),\
977 StdCodeCvt((PWSTR) _alloca((_cvt+1)*2), (_cvt+1)*2, \
980 ((_pw = pw) == 0) ? 0 : (\
982 StdCodeCvt((LPSTR) _alloca((_cvt+1)*2), (_cvt+1)*2, \
987 #define SSCVT int _cvt; _cvt; UINT _acp=CP_ACP; _acp;\
988 PCWSTR _pw; _pw; PCSTR _pa; _pa
990 #define SSCVT int _cvt = 0; _cvt; UINT _acp=CP_ACP; \
991 _acp; PCWSTR _pw=0; _pw; PCSTR _pa=0; _pa
994 ((_pa = pa) == 0) ? 0 : (\
995 _cvt = (sslen(_pa)),\
996 StdCodeCvt((PWSTR) _alloca((_cvt+1)*2), (_cvt+1)*2, \
999 ((_pw = pw) == 0) ? 0 : (\
1000 _cvt = (sslen(_pw)),\
1001 StdCodeCvt((LPSTR) _alloca((_cvt+1)*2), (_cvt+1)*2, \
1005 #define SSA2CW(pa) ((PCWSTR)SSA2W((pa)))
1006 #define SSW2CA(pw) ((PCSTR)SSW2A((pw)))
1011 #define SST2CA SSW2CA
1012 #define SSA2CT SSA2CW
1013 // (Did you get a compiler error here about not being able to convert
1014 // PTSTR into PWSTR? Then your _UNICODE and UNICODE flags are messed
1015 // up. Best bet: #define BOTH macros before including any MS headers.)
1016 inline PWSTR
SST2W(PTSTR p
) { return p
; }
1017 inline PTSTR
SSW2T(PWSTR p
) { return p
; }
1018 inline PCWSTR
SST2CW(PCTSTR p
) { return p
; }
1019 inline PCTSTR
SSW2CT(PCWSTR p
) { return p
; }
1023 #define SST2CW SSA2CW
1024 #define SSW2CT SSW2CA
1025 inline PSTR
SST2A(PTSTR p
) { return p
; }
1026 inline PTSTR
SSA2T(PSTR p
) { return p
; }
1027 inline PCSTR
SST2CA(PCTSTR p
) { return p
; }
1028 inline PCTSTR
SSA2CT(PCSTR p
) { return p
; }
1029 #endif // #ifdef UNICODE
1031 #if defined(UNICODE)
1032 // in these cases the default (TCHAR) is the same as OLECHAR
1033 inline PCOLESTR
SST2COLE(PCTSTR p
) { return p
; }
1034 inline PCTSTR
SSOLE2CT(PCOLESTR p
) { return p
; }
1035 inline POLESTR
SST2OLE(PTSTR p
) { return p
; }
1036 inline PTSTR
SSOLE2T(POLESTR p
) { return p
; }
1037 #elif defined(OLE2ANSI)
1038 // in these cases the default (TCHAR) is the same as OLECHAR
1039 inline PCOLESTR
SST2COLE(PCTSTR p
) { return p
; }
1040 inline PCTSTR
SSOLE2CT(PCOLESTR p
) { return p
; }
1041 inline POLESTR
SST2OLE(PTSTR p
) { return p
; }
1042 inline PTSTR
SSOLE2T(POLESTR p
) { return p
; }
1044 //CharNextW doesn't work on Win95 so we use this
1045 #define SST2COLE(pa) SSA2CW((pa))
1046 #define SST2OLE(pa) SSA2W((pa))
1047 #define SSOLE2CT(po) SSW2CA((po))
1048 #define SSOLE2T(po) SSW2A((po))
1052 #define SSW2OLE SSW2A
1053 #define SSOLE2W SSA2W
1054 #define SSW2COLE SSW2CA
1055 #define SSOLE2CW SSA2CW
1056 inline POLESTR
SSA2OLE(PSTR p
) { return p
; }
1057 inline PSTR
SSOLE2A(POLESTR p
) { return p
; }
1058 inline PCOLESTR
SSA2COLE(PCSTR p
) { return p
; }
1059 inline PCSTR
SSOLE2CA(PCOLESTR p
){ return p
; }
1061 #define SSA2OLE SSA2W
1062 #define SSOLE2A SSW2A
1063 #define SSA2COLE SSA2CW
1064 #define SSOLE2CA SSW2CA
1065 inline POLESTR
SSW2OLE(PWSTR p
) { return p
; }
1066 inline PWSTR
SSOLE2W(POLESTR p
) { return p
; }
1067 inline PCOLESTR
SSW2COLE(PCWSTR p
) { return p
; }
1068 inline PCWSTR
SSOLE2CW(PCOLESTR p
){ return p
; }
1071 // Above we've defined macros that look like MS' but all have
1072 // an 'SS' prefix. Now we need the real macros. We'll either
1073 // get them from the macros above or from MFC/ATL.
1075 #if defined (USES_CONVERSION)
1077 #define _NO_STDCONVERSION // just to be consistent
1083 #include <afxconv.h>
1084 #define _NO_STDCONVERSION // just to be consistent
1088 #define USES_CONVERSION SSCVT
1099 #define ocslen sslen
1100 #define ocscpy sscpy
1101 #define T2COLE SST2COLE
1102 #define OLE2CT SSOLE2CT
1103 #define T2OLE SST2COLE
1104 #define OLE2T SSOLE2CT
1105 #define A2OLE SSA2OLE
1106 #define OLE2A SSOLE2A
1107 #define W2OLE SSW2OLE
1108 #define OLE2W SSOLE2W
1109 #define A2COLE SSA2COLE
1110 #define OLE2CA SSOLE2CA
1111 #define W2COLE SSW2COLE
1112 #define OLE2CW SSOLE2CW
1114 #endif // #ifdef _MFC_VER
1115 #endif // #ifndef USES_CONVERSION
1116 #endif // #ifndef SS_NO_CONVERSION
1118 // Define ostring - generic name for std::basic_string<OLECHAR>
1120 #if !defined(ostring) && !defined(OSTRING_DEFINED)
1121 typedef std::basic_string
<OLECHAR
> ostring
;
1122 #define OSTRING_DEFINED
1125 // StdCodeCvt when there's no conversion to be done
1126 template <typename T
>
1127 inline T
* StdCodeCvt(T
* pDst
, int nDst
, const T
* pSrc
, int nSrc
)
1129 int nChars
= SSMIN(nSrc
, nDst
);
1134 std::basic_string
<T
>::traits_type::copy(pDst
, pSrc
, nChars
);
1135 // std::char_traits<T>::copy(pDst, pSrc, nChars);
1136 pDst
[nChars
] = '\0';
1141 inline PSTR
StdCodeCvt(PSTR pDst
, int nDst
, PCUSTR pSrc
, int nSrc
)
1143 return StdCodeCvt(pDst
, nDst
, (PCSTR
)pSrc
, nSrc
);
1145 inline PUSTR
StdCodeCvt(PUSTR pDst
, int nDst
, PCSTR pSrc
, int nSrc
)
1147 return (PUSTR
)StdCodeCvt((PSTR
)pDst
, nDst
, pSrc
, nSrc
);
1150 // Define tstring -- generic name for std::basic_string<TCHAR>
1152 #if !defined(tstring) && !defined(TSTRING_DEFINED)
1153 typedef std::basic_string
<TCHAR
> tstring
;
1154 #define TSTRING_DEFINED
1157 // a very shorthand way of applying the fix for KB problem Q172398
1158 // (basic_string assignment bug)
1160 #if defined ( _MSC_VER ) && ( _MSC_VER < 1200 )
1161 #define Q172398(x) (x).erase()
1166 // =============================================================================
1167 // INLINE FUNCTIONS ON WHICH CSTDSTRING RELIES
1169 // Usually for generic text mapping, we rely on preprocessor macro definitions
1170 // to map to string functions. However the CStdStr<> template cannot use
1171 // macro-based generic text mappings because its character types do not get
1172 // resolved until template processing which comes AFTER macro processing. In
1173 // other words, the preprocessor macro UNICODE is of little help to us in the
1176 // Therefore, to keep the CStdStr declaration simple, we have these inline
1177 // functions. The template calls them often. Since they are inline (and NOT
1178 // exported when this is built as a DLL), they will probably be resolved away
1181 // Without these functions, the CStdStr<> template would probably have to broken
1182 // out into two, almost identical classes. Either that or it would be a huge,
1183 // convoluted mess, with tons of "if" statements all over the place checking the
1184 // size of template parameter CT.
1185 // =============================================================================
1189 // --------------------------------------------------------------------------
1190 // Win32 GetStringTypeEx wrappers
1191 // --------------------------------------------------------------------------
1192 inline bool wsGetStringType(LCID lc
, DWORD dwT
, PCSTR pS
, int nSize
,
1195 return FALSE
!= GetStringTypeExA(lc
, dwT
, pS
, nSize
, pWd
);
1197 inline bool wsGetStringType(LCID lc
, DWORD dwT
, PCWSTR pS
, int nSize
,
1200 return FALSE
!= GetStringTypeExW(lc
, dwT
, pS
, nSize
, pWd
);
1204 template<typename CT
>
1205 inline bool ssisspace (CT t
)
1208 return wsGetStringType(GetThreadLocale(), CT_CTYPE1
, &t
, 1, &toYourMother
)
1209 && 0 != (C1_BLANK
& toYourMother
);
1214 // If they defined SS_NO_REFCOUNT, then we must convert all assignments
1216 #if defined (_MSC_VER) && (_MSC_VER < 1300)
1217 #ifdef SS_NO_REFCOUNT
1218 #define SSREF(x) (x).c_str()
1220 #define SSREF(x) (x)
1223 #define SSREF(x) (x)
1226 // -----------------------------------------------------------------------------
1227 // sslen: strlen/wcslen wrappers
1228 // -----------------------------------------------------------------------------
1229 template<typename CT
> inline int sslen(const CT
* pT
)
1231 return 0 == pT
? 0 : (int)std::basic_string
<CT
>::traits_type::length(pT
);
1232 // return 0 == pT ? 0 : std::char_traits<CT>::length(pT);
1234 inline SS_NOTHROW
int sslen(const std::string
& s
)
1236 return static_cast<int>(s
.length());
1238 inline SS_NOTHROW
int sslen(const std::wstring
& s
)
1240 return static_cast<int>(s
.length());
1243 // -----------------------------------------------------------------------------
1244 // sstolower/sstoupper -- convert characters to upper/lower case
1245 // -----------------------------------------------------------------------------
1248 inline char sstoupper(char ch
) { return (char)::toupper(ch
); }
1249 inline wchar_t sstoupper(wchar_t ch
){ return (wchar_t)::towupper(ch
); }
1250 inline char sstolower(char ch
) { return (char)::tolower(ch
); }
1251 inline wchar_t sstolower(wchar_t ch
){ return (wchar_t)::tolower(ch
); }
1253 template<typename CT
>
1254 inline CT
sstolower(const CT
& t
, const std::locale
& loc
= std::locale())
1256 return std::tolower
<CT
>(t
, loc
);
1258 template<typename CT
>
1259 inline CT
sstoupper(const CT
& t
, const std::locale
& loc
= std::locale())
1261 return std::toupper
<CT
>(t
, loc
);
1265 // -----------------------------------------------------------------------------
1266 // ssasn: assignment functions -- assign "sSrc" to "sDst"
1267 // -----------------------------------------------------------------------------
1268 typedef std::string::size_type SS_SIZETYPE
; // just for shorthand, really
1269 typedef std::string::pointer SS_PTRTYPE
;
1270 typedef std::wstring::size_type SW_SIZETYPE
;
1271 typedef std::wstring::pointer SW_PTRTYPE
;
1274 template <typename T
>
1275 inline void ssasn(std::basic_string
<T
>& sDst
, const std::basic_string
<T
>& sSrc
)
1277 if ( sDst
.c_str() != sSrc
.c_str() )
1280 sDst
.assign(SSREF(sSrc
));
1283 template <typename T
>
1284 inline void ssasn(std::basic_string
<T
>& sDst
, const T
*pA
)
1286 // Watch out for NULLs, as always.
1293 // If pA actually points to part of sDst, we must NOT erase(), but
1294 // rather take a substring
1296 else if ( pA
>= sDst
.c_str() && pA
<= sDst
.c_str() + sDst
.size() )
1298 sDst
=sDst
.substr(static_cast<typename
std::basic_string
<T
>::size_type
>(pA
-sDst
.c_str()));
1301 // Otherwise (most cases) apply the assignment bug fix, if applicable
1302 // and do the assignment
1310 inline void ssasn(std::string
& sDst
, const std::wstring
& sSrc
)
1318 int nDst
= static_cast<int>(sSrc
.size());
1320 // In MBCS builds, pad the buffer to account for the possibility of
1321 // some 3 byte characters. Not perfect but should get most cases.
1324 // In MBCS builds, we don't know how long the destination string will be.
1325 nDst
= static_cast<int>(static_cast<double>(nDst
) * 1.3);
1326 sDst
.resize(nDst
+1);
1327 PCSTR szCvt
= StdCodeCvt(const_cast<SS_PTRTYPE
>(sDst
.data()), nDst
,
1328 sSrc
.c_str(), static_cast<int>(sSrc
.size()));
1329 sDst
.resize(sslen(szCvt
));
1331 sDst
.resize(nDst
+1);
1332 StdCodeCvt(const_cast<SS_PTRTYPE
>(sDst
.data()), nDst
,
1333 sSrc
.c_str(), static_cast<int>(sSrc
.size()));
1334 sDst
.resize(sSrc
.size());
1338 inline void ssasn(std::string
& sDst
, PCWSTR pW
)
1340 int nSrc
= sslen(pW
);
1343 int nSrc
= sslen(pW
);
1346 // In MBCS builds, pad the buffer to account for the possibility of
1347 // some 3 byte characters. Not perfect but should get most cases.
1350 nDst
= static_cast<int>(static_cast<double>(nDst
) * 1.3);
1351 // In MBCS builds, we don't know how long the destination string will be.
1352 sDst
.resize(nDst
+ 1);
1353 PCSTR szCvt
= StdCodeCvt(const_cast<SS_PTRTYPE
>(sDst
.data()), nDst
,
1355 sDst
.resize(sslen(szCvt
));
1357 sDst
.resize(nDst
+ 1);
1358 StdCodeCvt(const_cast<SS_PTRTYPE
>(sDst
.data()), nDst
, pW
, nSrc
);
1367 inline void ssasn(std::string
& sDst
, const int nNull
)
1374 inline void ssasn(std::wstring
& sDst
, const std::string
& sSrc
)
1382 int nSrc
= static_cast<int>(sSrc
.size());
1385 sDst
.resize(nSrc
+1);
1386 PCWSTR szCvt
= StdCodeCvt(const_cast<SW_PTRTYPE
>(sDst
.data()), nDst
,
1387 sSrc
.c_str(), nSrc
);
1389 sDst
.resize(sslen(szCvt
));
1392 inline void ssasn(std::wstring
& sDst
, PCSTR pA
)
1394 int nSrc
= sslen(pA
);
1403 sDst
.resize(nDst
+1);
1404 PCWSTR szCvt
= StdCodeCvt(const_cast<SW_PTRTYPE
>(sDst
.data()), nDst
, pA
,
1407 sDst
.resize(sslen(szCvt
));
1410 inline void ssasn(std::wstring
& sDst
, const int nNull
)
1417 // -----------------------------------------------------------------------------
1418 // ssadd: string object concatenation -- add second argument to first
1419 // -----------------------------------------------------------------------------
1420 inline void ssadd(std::string
& sDst
, const std::wstring
& sSrc
)
1422 int nSrc
= static_cast<int>(sSrc
.size());
1426 int nDst
= static_cast<int>(sDst
.size());
1429 // In MBCS builds, pad the buffer to account for the possibility of
1430 // some 3 byte characters. Not perfect but should get most cases.
1433 nAdd
= static_cast<int>(static_cast<double>(nAdd
) * 1.3);
1434 sDst
.resize(nDst
+nAdd
+1);
1435 PCSTR szCvt
= StdCodeCvt(const_cast<SS_PTRTYPE
>(sDst
.data()+nDst
),
1436 nAdd
, sSrc
.c_str(), nSrc
);
1437 sDst
.resize(nDst
+ sslen(szCvt
));
1439 sDst
.resize(nDst
+nAdd
+1);
1440 StdCodeCvt(const_cast<SS_PTRTYPE
>(sDst
.data()+nDst
), nAdd
, sSrc
.c_str(), nSrc
);
1441 sDst
.resize(nDst
+ nAdd
);
1445 template <typename T
>
1446 inline void ssadd(typename
std::basic_string
<T
>& sDst
, const typename
std::basic_string
<T
>& sSrc
)
1450 inline void ssadd(std::string
& sDst
, PCWSTR pW
)
1452 int nSrc
= sslen(pW
);
1455 int nDst
= static_cast<int>(sDst
.size());
1459 nAdd
= static_cast<int>(static_cast<double>(nAdd
) * 1.3);
1460 sDst
.resize(nDst
+ nAdd
+ 1);
1461 PCSTR szCvt
= StdCodeCvt(const_cast<SS_PTRTYPE
>(sDst
.data()+nDst
),
1463 sDst
.resize(nDst
+ sslen(szCvt
));
1465 sDst
.resize(nDst
+ nAdd
+ 1);
1466 StdCodeCvt(const_cast<SS_PTRTYPE
>(sDst
.data()+nDst
), nAdd
, pW
, nSrc
);
1467 sDst
.resize(nDst
+ nSrc
);
1471 template <typename T
>
1472 inline void ssadd(typename
std::basic_string
<T
>& sDst
, const T
*pA
)
1476 // If the string being added is our internal string or a part of our
1477 // internal string, then we must NOT do any reallocation without
1478 // first copying that string to another object (since we're using a
1481 if ( pA
>= sDst
.c_str() && pA
<= sDst
.c_str()+sDst
.length())
1483 if ( sDst
.capacity() <= sDst
.size()+sslen(pA
) )
1484 sDst
.append(std::basic_string
<T
>(pA
));
1494 inline void ssadd(std::wstring
& sDst
, const std::string
& sSrc
)
1496 if ( !sSrc
.empty() )
1498 int nSrc
= static_cast<int>(sSrc
.size());
1499 int nDst
= static_cast<int>(sDst
.size());
1501 sDst
.resize(nDst
+ nSrc
+ 1);
1503 PCWSTR szCvt
= StdCodeCvt(const_cast<SW_PTRTYPE
>(sDst
.data()+nDst
),
1504 nSrc
, sSrc
.c_str(), nSrc
+1);
1505 sDst
.resize(nDst
+ sslen(szCvt
));
1507 StdCodeCvt(const_cast<SW_PTRTYPE
>(sDst
.data()+nDst
), nSrc
, sSrc
.c_str(), nSrc
+1);
1508 sDst
.resize(nDst
+ nSrc
);
1512 inline void ssadd(std::wstring
& sDst
, PCSTR pA
)
1514 int nSrc
= sslen(pA
);
1518 int nDst
= static_cast<int>(sDst
.size());
1520 sDst
.resize(nDst
+ nSrc
+ 1);
1522 PCWSTR szCvt
= StdCodeCvt(const_cast<SW_PTRTYPE
>(sDst
.data()+nDst
),
1524 sDst
.resize(nDst
+ sslen(szCvt
));
1526 StdCodeCvt(const_cast<SW_PTRTYPE
>(sDst
.data()+nDst
), nSrc
, pA
, nSrc
+1);
1527 sDst
.resize(nDst
+ nSrc
);
1532 // -----------------------------------------------------------------------------
1533 // sscmp: comparison (case sensitive, not affected by locale)
1534 // -----------------------------------------------------------------------------
1535 template<typename CT
>
1536 inline int sscmp(const CT
* pA1
, const CT
* pA2
)
1545 } while ( (f
) && (f
== l
) );
1547 return (int)(f
- l
);
1550 // -----------------------------------------------------------------------------
1551 // ssicmp: comparison (case INsensitive, not affected by locale)
1552 // -----------------------------------------------------------------------------
1553 template<typename CT
>
1554 inline int ssicmp(const CT
* pA1
, const CT
* pA2
)
1556 // Using the "C" locale = "not affected by locale"
1558 std::locale loc
= std::locale::classic();
1559 const std::ctype
<CT
>& ct
= SS_USE_FACET(loc
, std::ctype
<CT
>);
1565 f
= ct
.tolower(*(pA1
++));
1566 l
= ct
.tolower(*(pA2
++));
1567 } while ( (f
) && (f
== l
) );
1569 return (int)(f
- l
);
1572 // -----------------------------------------------------------------------------
1573 // ssupr/sslwr: Uppercase/Lowercase conversion functions
1574 // -----------------------------------------------------------------------------
1576 template<typename CT
>
1577 inline void sslwr(CT
* pT
, size_t nLen
, const std::locale
& loc
=std::locale())
1579 SS_USE_FACET(loc
, std::ctype
<CT
>).tolower(pT
, pT
+nLen
);
1581 template<typename CT
>
1582 inline void ssupr(CT
* pT
, size_t nLen
, const std::locale
& loc
=std::locale())
1584 SS_USE_FACET(loc
, std::ctype
<CT
>).toupper(pT
, pT
+nLen
);
1587 // -----------------------------------------------------------------------------
1588 // vsprintf/vswprintf or _vsnprintf/_vsnwprintf equivalents. In standard
1589 // builds we can't use _vsnprintf/_vsnwsprintf because they're MS extensions.
1591 // -----------------------------------------------------------------------------
1592 // Borland's headers put some ANSI "C" functions in the 'std' namespace.
1593 // Promote them to the global namespace so we can use them here.
1595 #if defined(__BORLANDC__)
1596 using std::vsprintf
;
1597 using std::vswprintf
;
1600 // GNU is supposed to have vsnprintf and vsnwprintf. But only the newer
1601 // distributions do.
1603 #if defined(__GNUC__)
1605 inline int ssvsprintf(PSTR pA
, size_t nCount
, PCSTR pFmtA
, va_list vl
)
1607 return vsnprintf(pA
, nCount
, pFmtA
, vl
);
1609 inline int ssvsprintf(PWSTR pW
, size_t nCount
, PCWSTR pFmtW
, va_list vl
)
1611 return vswprintf(pW
, nCount
, pFmtW
, vl
);
1614 // Microsofties can use
1615 #elif defined(_MSC_VER) && !defined(SS_ANSI)
1617 inline int ssvsprintf(PSTR pA
, size_t nCount
, PCSTR pFmtA
, va_list vl
)
1619 return _vsnprintf(pA
, nCount
, pFmtA
, vl
);
1621 inline int ssvsprintf(PWSTR pW
, size_t nCount
, PCWSTR pFmtW
, va_list vl
)
1623 return _vsnwprintf(pW
, nCount
, pFmtW
, vl
);
1626 #elif defined (SS_DANGEROUS_FORMAT) // ignore buffer size parameter if needed?
1628 inline int ssvsprintf(PSTR pA
, size_t /*nCount*/, PCSTR pFmtA
, va_list vl
)
1630 return vsprintf(pA
, pFmtA
, vl
);
1633 inline int ssvsprintf(PWSTR pW
, size_t nCount
, PCWSTR pFmtW
, va_list vl
)
1635 // JMO: Some distributions of the "C" have a version of vswprintf that
1636 // takes 3 arguments (e.g. Microsoft, Borland, GNU). Others have a
1637 // version which takes 4 arguments (an extra "count" argument in the
1638 // second position. The best stab I can take at this so far is that if
1639 // you are NOT running with MS, Borland, or GNU, then I'll assume you
1640 // have the version that takes 4 arguments.
1642 // I'm sure that these checks don't catch every platform correctly so if
1643 // you get compiler errors on one of the lines immediately below, it's
1644 // probably because your implemntation takes a different number of
1645 // arguments. You can comment out the offending line (and use the
1646 // alternate version) or you can figure out what compiler flag to check
1647 // and add that preprocessor check in. Regardless, if you get an error
1648 // on these lines, I'd sure like to hear from you about it.
1650 // Thanks to Ronny Schulz for the SGI-specific checks here.
1652 // #if !defined(__MWERKS__) && !defined(__SUNPRO_CC_COMPAT) && !defined(__SUNPRO_CC)
1653 #if !defined(_MSC_VER) \
1654 && !defined (__BORLANDC__) \
1655 && !defined(__GNUC__) \
1658 return vswprintf(pW
, nCount
, pFmtW
, vl
);
1660 // suddenly with the current SGI 7.3 compiler there is no such function as
1661 // vswprintf and the substitute needs explicit casts to compile
1663 #elif defined(__sgi)
1666 return vsprintf( (char *)pW
, (char *)pFmtW
, vl
);
1671 return vswprintf(pW
, pFmtW
, vl
);
1679 // GOT COMPILER PROBLEMS HERE?
1680 // ---------------------------
1681 // Does your compiler choke on one or more of the following 2 functions? It
1682 // probably means that you don't have have either vsnprintf or vsnwprintf in
1683 // your version of the CRT. This is understandable since neither is an ANSI
1684 // "C" function. However it still leaves you in a dilemma. In order to make
1685 // this code build, you're going to have to to use some non-length-checked
1686 // formatting functions that every CRT has: vsprintf and vswprintf.
1688 // This is very dangerous. With the proper erroneous (or malicious) code, it
1689 // can lead to buffer overlows and crashing your PC. Use at your own risk
1690 // In order to use them, just #define SS_DANGEROUS_FORMAT at the top of
1693 // Even THEN you might not be all the way home due to some non-conforming
1694 // distributions. More on this in the comments below.
1696 inline int ssnprintf(PSTR pA
, size_t nCount
, PCSTR pFmtA
, va_list vl
)
1699 return _vsnprintf(pA
, nCount
, pFmtA
, vl
);
1701 return vsnprintf(pA
, nCount
, pFmtA
, vl
);
1704 inline int ssnprintf(PWSTR pW
, size_t nCount
, PCWSTR pFmtW
, va_list vl
)
1707 return _vsnwprintf(pW
, nCount
, pFmtW
, vl
);
1709 return vswprintf(pW
, nCount
, pFmtW
, vl
);
1716 // -----------------------------------------------------------------------------
1717 // ssload: Type safe, overloaded ::LoadString wrappers
1718 // There is no equivalent of these in non-Win32-specific builds. However, I'm
1719 // thinking that with the message facet, there might eventually be one
1720 // -----------------------------------------------------------------------------
1721 #if defined (SS_WIN32) && !defined(SS_ANSI)
1722 inline int ssload(HMODULE hInst
, UINT uId
, PSTR pBuf
, int nMax
)
1724 return ::LoadStringA(hInst
, uId
, pBuf
, nMax
);
1726 inline int ssload(HMODULE hInst
, UINT uId
, PWSTR pBuf
, int nMax
)
1728 return ::LoadStringW(hInst
, uId
, pBuf
, nMax
);
1730 #if defined ( _MSC_VER ) && ( _MSC_VER >= 1500 )
1731 inline int ssload(HMODULE hInst
, UINT uId
, uint16_t *pBuf
, int nMax
)
1735 inline int ssload(HMODULE hInst
, UINT uId
, uint32_t *pBuf
, int nMax
)
1743 // -----------------------------------------------------------------------------
1744 // sscoll/ssicoll: Collation wrappers
1745 // Note -- with MSVC I have reversed the arguments order here because the
1746 // functions appear to return the opposite of what they should
1747 // -----------------------------------------------------------------------------
1748 #ifndef SS_NO_LOCALE
1749 template <typename CT
>
1750 inline int sscoll(const CT
* sz1
, int nLen1
, const CT
* sz2
, int nLen2
)
1752 const std::collate
<CT
>& coll
=
1753 SS_USE_FACET(std::locale(), std::collate
<CT
>);
1755 return coll
.compare(sz2
, sz2
+nLen2
, sz1
, sz1
+nLen1
);
1757 template <typename CT
>
1758 inline int ssicoll(const CT
* sz1
, int nLen1
, const CT
* sz2
, int nLen2
)
1760 const std::locale loc
;
1761 const std::collate
<CT
>& coll
= SS_USE_FACET(loc
, std::collate
<CT
>);
1763 // Some implementations seem to have trouble using the collate<>
1764 // facet typedefs so we'll just default to basic_string and hope
1765 // that's what the collate facet uses (which it generally should)
1767 // std::collate<CT>::string_type s1(sz1);
1768 // std::collate<CT>::string_type s2(sz2);
1769 const std::basic_string
<CT
> sEmpty
;
1770 std::basic_string
<CT
> s1(sz1
? sz1
: sEmpty
.c_str());
1771 std::basic_string
<CT
> s2(sz2
? sz2
: sEmpty
.c_str());
1773 sslwr(const_cast<CT
*>(s1
.c_str()), nLen1
, loc
);
1774 sslwr(const_cast<CT
*>(s2
.c_str()), nLen2
, loc
);
1775 return coll
.compare(s2
.c_str(), s2
.c_str()+nLen2
,
1776 s1
.c_str(), s1
.c_str()+nLen1
);
1781 // -----------------------------------------------------------------------------
1782 // ssfmtmsg: FormatMessage equivalents. Needed because I added a CString facade
1783 // Again -- no equivalent of these on non-Win32 builds but their might one day
1784 // be one if the message facet gets implemented
1785 // -----------------------------------------------------------------------------
1786 #if defined (SS_WIN32) && !defined(SS_ANSI)
1787 inline DWORD
ssfmtmsg(DWORD dwFlags
, LPCVOID pSrc
, DWORD dwMsgId
,
1788 DWORD dwLangId
, PSTR pBuf
, DWORD nSize
,
1791 return FormatMessageA(dwFlags
, pSrc
, dwMsgId
, dwLangId
,
1792 pBuf
, nSize
,vlArgs
);
1794 inline DWORD
ssfmtmsg(DWORD dwFlags
, LPCVOID pSrc
, DWORD dwMsgId
,
1795 DWORD dwLangId
, PWSTR pBuf
, DWORD nSize
,
1798 return FormatMessageW(dwFlags
, pSrc
, dwMsgId
, dwLangId
,
1799 pBuf
, nSize
,vlArgs
);
1806 // FUNCTION: sscpy. Copies up to 'nMax' characters from pSrc to pDst.
1807 // -----------------------------------------------------------------------------
1809 // inline int sscpy(PSTR pDst, PCSTR pSrc, int nMax=-1);
1810 // inline int sscpy(PUSTR pDst, PCSTR pSrc, int nMax=-1)
1811 // inline int sscpy(PSTR pDst, PCWSTR pSrc, int nMax=-1);
1812 // inline int sscpy(PWSTR pDst, PCWSTR pSrc, int nMax=-1);
1813 // inline int sscpy(PWSTR pDst, PCSTR pSrc, int nMax=-1);
1816 // This function is very much (but not exactly) like strcpy. These
1817 // overloads simplify copying one C-style string into another by allowing
1818 // the caller to specify two different types of strings if necessary.
1820 // The strings must NOT overlap
1822 // "Character" is expressed in terms of the destination string, not
1823 // the source. If no 'nMax' argument is supplied, then the number of
1824 // characters copied will be sslen(pSrc). A NULL terminator will
1825 // also be added so pDst must actually be big enough to hold nMax+1
1826 // characters. The return value is the number of characters copied,
1827 // not including the NULL terminator.
1830 // pSrc - the string to be copied FROM. May be a char based string, an
1831 // MBCS string (in Win32 builds) or a wide string (wchar_t).
1832 // pSrc - the string to be copied TO. Also may be either MBCS or wide
1833 // nMax - the maximum number of characters to be copied into szDest. Note
1834 // that this is expressed in whatever a "character" means to pDst.
1835 // If pDst is a wchar_t type string than this will be the maximum
1836 // number of wchar_ts that my be copied. The pDst string must be
1837 // large enough to hold least nMaxChars+1 characters.
1838 // If the caller supplies no argument for nMax this is a signal to
1839 // the routine to copy all the characters in pSrc, regardless of
1842 // RETURN VALUE: none
1843 // -----------------------------------------------------------------------------
1845 template<typename CT1
, typename CT2
>
1846 inline int sscpycvt(CT1
* pDst
, const CT2
* pSrc
, int nMax
)
1848 // Note -- we assume pDst is big enough to hold pSrc. If not, we're in
1849 // big trouble. No bounds checking. Caveat emptor.
1851 int nSrc
= sslen(pSrc
);
1853 const CT1
* szCvt
= StdCodeCvt(pDst
, nMax
, pSrc
, nSrc
);
1855 // If we're copying the same size characters, then all the "code convert"
1856 // just did was basically memcpy so the #of characters copied is the same
1857 // as the number requested. I should probably specialize this function
1858 // template to achieve this purpose as it is silly to do a runtime check
1859 // of a fact known at compile time. I'll get around to it.
1861 return sslen(szCvt
);
1864 template<typename T
>
1865 inline int sscpycvt(T
* pDst
, const T
* pSrc
, int nMax
)
1868 for (; nCount
> 0 && *pSrc
; ++pSrc
, ++pDst
, --nCount
)
1869 std::basic_string
<T
>::traits_type::assign(*pDst
, *pSrc
);
1872 return nMax
- nCount
;
1875 inline int sscpycvt(PWSTR pDst
, PCSTR pSrc
, int nMax
)
1877 // Note -- we assume pDst is big enough to hold pSrc. If not, we're in
1878 // big trouble. No bounds checking. Caveat emptor.
1880 const PWSTR szCvt
= StdCodeCvt(pDst
, nMax
, pSrc
, nMax
);
1881 return sslen(szCvt
);
1884 template<typename CT1
, typename CT2
>
1885 inline int sscpy(CT1
* pDst
, const CT2
* pSrc
, int nMax
, int nLen
)
1887 return sscpycvt(pDst
, pSrc
, SSMIN(nMax
, nLen
));
1889 template<typename CT1
, typename CT2
>
1890 inline int sscpy(CT1
* pDst
, const CT2
* pSrc
, int nMax
)
1892 return sscpycvt(pDst
, pSrc
, SSMIN(nMax
, sslen(pSrc
)));
1894 template<typename CT1
, typename CT2
>
1895 inline int sscpy(CT1
* pDst
, const CT2
* pSrc
)
1897 return sscpycvt(pDst
, pSrc
, sslen(pSrc
));
1899 template<typename CT1
, typename CT2
>
1900 inline int sscpy(CT1
* pDst
, const std::basic_string
<CT2
>& sSrc
, int nMax
)
1902 return sscpycvt(pDst
, sSrc
.c_str(), SSMIN(nMax
, (int)sSrc
.length()));
1904 template<typename CT1
, typename CT2
>
1905 inline int sscpy(CT1
* pDst
, const std::basic_string
<CT2
>& sSrc
)
1907 return sscpycvt(pDst
, sSrc
.c_str(), (int)sSrc
.length());
1910 #ifdef SS_INC_COMDEF
1911 template<typename CT1
>
1912 inline int sscpy(CT1
* pDst
, const _bstr_t
& bs
, int nMax
)
1914 return sscpycvt(pDst
, static_cast<PCOLESTR
>(bs
),
1915 SSMIN(nMax
, static_cast<int>(bs
.length())));
1917 template<typename CT1
>
1918 inline int sscpy(CT1
* pDst
, const _bstr_t
& bs
)
1920 return sscpy(pDst
, bs
, static_cast<int>(bs
.length()));
1925 // -----------------------------------------------------------------------------
1926 // Functional objects for changing case. They also let you pass locales
1927 // -----------------------------------------------------------------------------
1930 template<typename CT
>
1931 struct SSToUpper
: public std::unary_function
<CT
, CT
>
1933 inline CT
operator()(const CT
& t
) const
1935 return sstoupper(t
);
1938 template<typename CT
>
1939 struct SSToLower
: public std::unary_function
<CT
, CT
>
1941 inline CT
operator()(const CT
& t
) const
1943 return sstolower(t
);
1947 template<typename CT
>
1948 struct SSToUpper
: public std::binary_function
<CT
, std::locale
, CT
>
1950 inline CT
operator()(const CT
& t
, const std::locale
& loc
) const
1952 return sstoupper
<CT
>(t
, loc
);
1955 template<typename CT
>
1956 struct SSToLower
: public std::binary_function
<CT
, std::locale
, CT
>
1958 inline CT
operator()(const CT
& t
, const std::locale
& loc
) const
1960 return sstolower
<CT
>(t
, loc
);
1965 // This struct is used for TrimRight() and TrimLeft() function implementations.
1966 //template<typename CT>
1967 //struct NotSpace : public std::unary_function<CT, bool>
1969 // const std::locale& loc;
1970 // inline NotSpace(const std::locale& locArg) : loc(locArg) {}
1971 // inline bool operator() (CT t) { return !std::isspace(t, loc); }
1973 template<typename CT
>
1974 struct NotSpace
: public std::unary_function
<CT
, bool>
1977 // Note -- using std::isspace in a COM DLL gives us access violations
1978 // because it causes the dynamic addition of a function to be called
1979 // when the library shuts down. Unfortunately the list is maintained
1980 // in DLL memory but the function is in static memory. So the COM DLL
1981 // goes away along with the function that was supposed to be called,
1982 // and then later when the DLL CRT shuts down it unloads the list and
1983 // tries to call the long-gone function.
1984 // This is DinkumWare's implementation problem. If you encounter this
1985 // problem, you may replace the calls here with good old isspace() and
1986 // iswspace() from the CRT unless they specify SS_ANSI
1990 bool operator() (CT t
) const { return !ssisspace(t
); }
1993 const std::locale loc
;
1994 NotSpace(const std::locale
& locArg
=std::locale()) : loc(locArg
) {}
1995 bool operator() (CT t
) const { return !std::isspace(t
, loc
); }
2002 // Now we can define the template (finally!)
2003 // =============================================================================
2004 // TEMPLATE: CStdStr
2005 // template<typename CT> class CStdStr : public std::basic_string<CT>
2008 // This template derives from basic_string<CT> and adds some MFC CString-
2009 // like functionality
2011 // Basically, this is my attempt to make Standard C++ library strings as
2012 // easy to use as the MFC CString class.
2014 // Note that although this is a template, it makes the assumption that the
2015 // template argument (CT, the character type) is either char or wchar_t.
2016 // =============================================================================
2018 //#define CStdStr _SS // avoid compiler warning 4786
2020 // template<typename ARG> ARG& FmtArg(ARG& arg) { return arg; }
2021 // PCSTR FmtArg(const std::string& arg) { return arg.c_str(); }
2022 // PCWSTR FmtArg(const std::wstring& arg) { return arg.c_str(); }
2024 template<typename ARG
>
2027 explicit FmtArg(const ARG
& arg
) : a_(arg
) {}
2028 const ARG
& operator()() const { return a_
; }
2031 FmtArg
& operator=(const FmtArg
&) { return *this; }
2034 template<typename CT
>
2035 class CStdStr
: public std::basic_string
<CT
>
2037 // Typedefs for shorter names. Using these names also appears to help
2038 // us avoid some ambiguities that otherwise arise on some platforms
2040 #define MYBASE std::basic_string<CT> // my base class
2041 //typedef typename std::basic_string<CT> MYBASE; // my base class
2042 typedef CStdStr
<CT
> MYTYPE
; // myself
2043 typedef typename
MYBASE::const_pointer PCMYSTR
; // PCSTR or PCWSTR
2044 typedef typename
MYBASE::pointer PMYSTR
; // PSTR or PWSTR
2045 typedef typename
MYBASE::iterator MYITER
; // my iterator type
2046 typedef typename
MYBASE::const_iterator MYCITER
; // you get the idea...
2047 typedef typename
MYBASE::reverse_iterator MYRITER
;
2048 typedef typename
MYBASE::size_type MYSIZE
;
2049 typedef typename
MYBASE::value_type MYVAL
;
2050 typedef typename
MYBASE::allocator_type MYALLOC
;
2053 // shorthand conversion from PCTSTR to string resource ID
2054 #define SSRES(pctstr) LOWORD(reinterpret_cast<unsigned long>(pctstr))
2056 bool TryLoad(const void* pT
)
2058 bool bLoaded
= false;
2060 #if defined(SS_WIN32) && !defined(SS_ANSI)
2061 if ( ( pT
!= NULL
) && SS_IS_INTRESOURCE(pT
) )
2063 UINT nId
= LOWORD(reinterpret_cast<unsigned long>(pT
));
2064 if ( !LoadString(nId
) )
2066 TRACE(_T("Can't load string %u\n"), SSRES(pT
));
2076 // CStdStr inline constructors
2081 CStdStr(const MYTYPE
& str
) : MYBASE(SSREF(str
))
2085 CStdStr(const std::string
& str
)
2087 ssasn(*this, SSREF(str
));
2090 CStdStr(const std::wstring
& str
)
2092 ssasn(*this, SSREF(str
));
2095 CStdStr(PCMYSTR pT
, MYSIZE n
) : MYBASE(pT
, n
)
2102 *this = reinterpret_cast<PCSTR
>(pU
);
2126 CStdStr(uint16_t* pW
)
2136 CStdStr(uint32_t* pW
)
2146 CStdStr(MYCITER first
, MYCITER last
)
2147 : MYBASE(first
, last
)
2151 CStdStr(MYSIZE nSize
, MYVAL ch
, const MYALLOC
& al
=MYALLOC())
2152 : MYBASE(nSize
, ch
, al
)
2156 #ifdef SS_INC_COMDEF
2157 CStdStr(const _bstr_t
& bstr
)
2159 if ( bstr
.length() > 0 )
2160 this->append(static_cast<PCMYSTR
>(bstr
), bstr
.length());
2164 // CStdStr inline assignment operators -- the ssasn function now takes care
2165 // of fixing the MSVC assignment bug (see knowledge base article Q172398).
2166 MYTYPE
& operator=(const MYTYPE
& str
)
2172 MYTYPE
& operator=(const std::string
& str
)
2178 MYTYPE
& operator=(const std::wstring
& str
)
2184 MYTYPE
& operator=(PCSTR pA
)
2190 MYTYPE
& operator=(PCWSTR pW
)
2197 MYTYPE
& operator=(PCUSTR pU
)
2199 ssasn(*this, reinterpret_cast<PCSTR
>(pU
));
2204 MYTYPE
& operator=(uint16_t* pA
)
2210 MYTYPE
& operator=(uint32_t* pA
)
2216 MYTYPE
& operator=(CT t
)
2223 #ifdef SS_INC_COMDEF
2224 MYTYPE
& operator=(const _bstr_t
& bstr
)
2226 if ( bstr
.length() > 0 )
2228 this->assign(static_cast<PCMYSTR
>(bstr
), bstr
.length());
2240 // Overloads also needed to fix the MSVC assignment bug (KB: Q172398)
2241 // *** Thanks to Pete The Plumber for catching this one ***
2242 // They also are compiled if you have explicitly turned off refcounting
2243 #if ( defined(_MSC_VER) && ( _MSC_VER < 1200 ) ) || defined(SS_NO_REFCOUNT)
2245 MYTYPE
& assign(const MYTYPE
& str
)
2248 sscpy(GetBuffer(str
.size()+1), SSREF(str
));
2249 this->ReleaseBuffer(str
.size());
2253 MYTYPE
& assign(const MYTYPE
& str
, MYSIZE nStart
, MYSIZE nChars
)
2255 // This overload of basic_string::assign is supposed to assign up to
2256 // <nChars> or the NULL terminator, whichever comes first. Since we
2257 // are about to call a less forgiving overload (in which <nChars>
2258 // must be a valid length), we must adjust the length here to a safe
2259 // value. Thanks to Ullrich Poll�hne for catching this bug
2261 nChars
= SSMIN(nChars
, str
.length() - nStart
);
2262 MYTYPE
strTemp(str
.c_str()+nStart
, nChars
);
2264 this->assign(strTemp
);
2268 MYTYPE
& assign(const MYBASE
& str
)
2274 MYTYPE
& assign(const MYBASE
& str
, MYSIZE nStart
, MYSIZE nChars
)
2276 // This overload of basic_string::assign is supposed to assign up to
2277 // <nChars> or the NULL terminator, whichever comes first. Since we
2278 // are about to call a less forgiving overload (in which <nChars>
2279 // must be a valid length), we must adjust the length here to a safe
2280 // value. Thanks to Ullrich Poll�hne for catching this bug
2282 nChars
= SSMIN(nChars
, str
.length() - nStart
);
2284 // Watch out for assignment to self
2288 MYTYPE
strTemp(str
.c_str() + nStart
, nChars
);
2289 static_cast<MYBASE
*>(this)->assign(strTemp
);
2294 static_cast<MYBASE
*>(this)->assign(str
.c_str()+nStart
, nChars
);
2299 MYTYPE
& assign(const CT
* pC
, MYSIZE nChars
)
2301 // Q172398 only fix -- erase before assigning, but not if we're
2302 // assigning from our own buffer
2304 #if defined ( _MSC_VER ) && ( _MSC_VER < 1200 )
2305 if ( !this->empty() &&
2306 ( pC
< this->data() || pC
> this->data() + this->capacity() ) )
2312 static_cast<MYBASE
*>(this)->assign(pC
, nChars
);
2316 MYTYPE
& assign(MYSIZE nChars
, MYVAL val
)
2319 static_cast<MYBASE
*>(this)->assign(nChars
, val
);
2323 MYTYPE
& assign(const CT
* pT
)
2325 return this->assign(pT
, MYBASE::traits_type::length(pT
));
2328 MYTYPE
& assign(MYCITER iterFirst
, MYCITER iterLast
)
2330 #if defined ( _MSC_VER ) && ( _MSC_VER < 1200 )
2331 // Q172398 fix. don't call erase() if we're assigning from ourself
2332 if ( iterFirst
< this->begin() ||
2333 iterFirst
> this->begin() + this->size() )
2338 this->replace(this->begin(), this->end(), iterFirst
, iterLast
);
2344 // -------------------------------------------------------------------------
2345 // CStdStr inline concatenation.
2346 // -------------------------------------------------------------------------
2347 MYTYPE
& operator+=(const MYTYPE
& str
)
2353 MYTYPE
& operator+=(const std::string
& str
)
2359 MYTYPE
& operator+=(const std::wstring
& str
)
2365 MYTYPE
& operator+=(PCSTR pA
)
2371 MYTYPE
& operator+=(PCWSTR pW
)
2377 MYTYPE
& operator+=(uint16_t* pW
)
2383 MYTYPE
& operator+=(uint32_t* pW
)
2389 MYTYPE
& operator+=(CT t
)
2394 #ifdef SS_INC_COMDEF // if we have _bstr_t, define a += for it too.
2395 MYTYPE
& operator+=(const _bstr_t
& bstr
)
2397 return this->operator+=(static_cast<PCMYSTR
>(bstr
));
2402 // -------------------------------------------------------------------------
2403 // Case changing functions
2404 // -------------------------------------------------------------------------
2406 MYTYPE
& ToUpper(const std::locale
& loc
=std::locale())
2408 // Note -- if there are any MBCS character sets in which the lowercase
2409 // form a character takes up a different number of bytes than the
2410 // uppercase form, this would probably not work...
2412 std::transform(this->begin(),
2418 std::bind2nd(SSToUpper
<CT
>(), loc
));
2421 // ...but if it were, this would probably work better. Also, this way
2422 // seems to be a bit faster when anything other then the "C" locale is
2427 // ssupr(this->GetBuf(), this->size(), loc);
2434 MYTYPE
& ToLower(const std::locale
& loc
=std::locale())
2436 // Note -- if there are any MBCS character sets in which the lowercase
2437 // form a character takes up a different number of bytes than the
2438 // uppercase form, this would probably not work...
2440 std::transform(this->begin(),
2446 std::bind2nd(SSToLower
<CT
>(), loc
));
2449 // ...but if it were, this would probably work better. Also, this way
2450 // seems to be a bit faster when anything other then the "C" locale is
2455 // sslwr(this->GetBuf(), this->size(), loc);
2464 return Trim().ToLower();
2468 // -------------------------------------------------------------------------
2469 // CStdStr -- Direct access to character buffer. In the MS' implementation,
2470 // the at() function that we use here also calls _Freeze() providing us some
2471 // protection from multithreading problems associated with ref-counting.
2472 // In VC 7 and later, of course, the ref-counting stuff is gone.
2473 // -------------------------------------------------------------------------
2475 CT
* GetBuf(int nMinLen
=-1)
2477 if ( static_cast<int>(this->size()) < nMinLen
)
2478 this->resize(static_cast<MYSIZE
>(nMinLen
));
2480 return this->empty() ? const_cast<CT
*>(this->data()) : &(this->at(0));
2483 CT
* SetBuf(int nLen
)
2485 nLen
= ( nLen
> 0 ? nLen
: 0 );
2486 if ( this->capacity() < 1 && nLen
== 0 )
2489 this->resize(static_cast<MYSIZE
>(nLen
));
2490 return const_cast<CT
*>(this->data());
2492 void RelBuf(int nNewLen
=-1)
2494 this->resize(static_cast<MYSIZE
>(nNewLen
> -1 ? nNewLen
:
2495 sslen(this->c_str())));
2498 void BufferRel() { RelBuf(); } // backwards compatability
2499 CT
* Buffer() { return GetBuf(); } // backwards compatability
2500 CT
* BufferSet(int nLen
) { return SetBuf(nLen
);}// backwards compatability
2502 bool Equals(const CT
* pT
, bool bUseCase
=false) const
2504 return 0 == (bUseCase
? this->compare(pT
) : ssicmp(this->c_str(), pT
));
2507 // -------------------------------------------------------------------------
2508 // FUNCTION: CStdStr::Load
2510 // Loads string from resource specified by nID
2513 // nID - resource Identifier. Purely a Win32 thing in this case
2516 // true if successful, false otherwise
2517 // -------------------------------------------------------------------------
2521 bool Load(UINT nId
, HMODULE hModule
=NULL
)
2523 bool bLoaded
= false; // set to true of we succeed.
2525 #ifdef _MFC_VER // When in Rome (or MFC land)...
2527 // If they gave a resource handle, use it. Note - this is archaic
2528 // and not really what I would recommend. But then again, in MFC
2529 // land, you ought to be using CString for resources anyway since
2530 // it walks the resource chain for you.
2532 HMODULE hModuleOld
= NULL
;
2534 if ( NULL
!= hModule
)
2536 hModuleOld
= AfxGetResourceHandle();
2537 AfxSetResourceHandle(hModule
);
2540 // ...load the string
2543 bLoaded
= FALSE
!= strRes
.LoadString(nId
);
2545 // ...and if we set the resource handle, restore it.
2547 if ( NULL
!= hModuleOld
)
2548 AfxSetResourceHandle(hModule
);
2553 #else // otherwise make our own hackneyed version of CString's Load
2555 // Get the resource name and module handle
2557 if ( NULL
== hModule
)
2558 hModule
= GetResourceHandle();
2560 PCTSTR szName
= MAKEINTRESOURCE((nId
>>4)+1); // lifted
2563 // No sense continuing if we can't find the resource
2565 HRSRC hrsrc
= ::FindResource(hModule
, szName
, RT_STRING
);
2567 if ( NULL
== hrsrc
)
2569 TRACE(_T("Cannot find resource %d: 0x%X"), nId
, ::GetLastError());
2571 else if ( 0 == (dwSize
= ::SizeofResource(hModule
, hrsrc
) / sizeof(CT
)))
2573 TRACE(_T("Cant get size of resource %d 0x%X\n"),nId
,GetLastError());
2577 bLoaded
= 0 != ssload(hModule
, nId
, GetBuf(dwSize
), dwSize
);
2581 #endif // #ifdef _MFC_VER
2584 TRACE(_T("String not loaded 0x%X\n"), ::GetLastError());
2589 #endif // #ifdef SS_ANSI
2591 // -------------------------------------------------------------------------
2592 // FUNCTION: CStdStr::Format
2593 // void _cdecl Formst(CStdStringA& PCSTR szFormat, ...)
2594 // void _cdecl Format(PCSTR szFormat);
2597 // This function does sprintf/wsprintf style formatting on CStdStringA
2598 // objects. It looks a lot like MFC's CString::Format. Some people
2599 // might even call this identical. Fortunately, these people are now
2603 // nId - ID of string resource holding the format string
2604 // szFormat - a PCSTR holding the format specifiers
2605 // argList - a va_list holding the arguments for the format specifiers.
2607 // RETURN VALUE: None.
2608 // -------------------------------------------------------------------------
2609 // formatting (using wsprintf style formatting)
2611 // If they want a Format() function that safely handles string objects
2614 #ifdef SS_SAFE_FORMAT
2616 // Question: Joe, you wacky coder you, why do you have so many overloads
2617 // of the Format() function
2618 // Answer: One reason only - CString compatability. In short, by making
2619 // the Format() function a template this way, I can do strong typing
2620 // and allow people to pass CStdString arguments as fillers for
2621 // "%s" format specifiers without crashing their program! The downside
2622 // is that I need to overload on the number of arguments. If you are
2623 // passing more arguments than I have listed below in any of my
2624 // overloads, just add another one.
2626 // Yes, yes, this is really ugly. In essence what I am doing here is
2627 // protecting people from a bad (and incorrect) programming practice
2628 // that they should not be doing anyway. I am protecting them from
2629 // themselves. Why am I doing this? Well, if you had any idea the
2630 // number of times I've been emailed by people about this
2631 // "incompatability" in my code, you wouldn't ask.
2633 void Fmt(const CT
* szFmt
, ...)
2636 va_start(argList
, szFmt
);
2637 FormatV(szFmt
, argList
);
2643 void Format(UINT nId
)
2646 if ( strFmt
.Load(nId
) )
2650 void Format(UINT nId
, const A1
& v
)
2653 if ( strFmt
.Load(nId
) )
2654 Fmt(strFmt
, FmtArg
<A1
>(v
)());
2656 template<class A1
, class A2
>
2657 void Format(UINT nId
, const A1
& v1
, const A2
& v2
)
2660 if ( strFmt
.Load(nId
) )
2661 Fmt(strFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)());
2663 template<class A1
, class A2
, class A3
>
2664 void Format(UINT nId
, const A1
& v1
, const A2
& v2
, const A3
& v3
)
2667 if ( strFmt
.Load(nId
) )
2669 Fmt(strFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2673 template<class A1
, class A2
, class A3
, class A4
>
2674 void Format(UINT nId
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
2678 if ( strFmt
.Load(nId
) )
2680 Fmt(strFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2681 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)());
2684 template<class A1
, class A2
, class A3
, class A4
, class A5
>
2685 void Format(UINT nId
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
2686 const A4
& v4
, const A5
& v5
)
2689 if ( strFmt
.Load(nId
) )
2691 Fmt(strFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2692 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(), FmtArg
<A5
>(v5
)());
2695 template<class A1
, class A2
, class A3
, class A4
, class A5
, class A6
>
2696 void Format(UINT nId
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
2697 const A4
& v4
, const A5
& v5
, const A6
& v6
)
2700 if ( strFmt
.Load(nId
) )
2702 Fmt(strFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2703 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(),FmtArg
<A5
>(v5
)(),
2707 template<class A1
, class A2
, class A3
, class A4
, class A5
, class A6
,
2709 void Format(UINT nId
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
2710 const A4
& v4
, const A5
& v5
, const A6
& v6
, const A7
& v7
)
2713 if ( strFmt
.Load(nId
) )
2715 Fmt(strFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2716 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(),FmtArg
<A5
>(v5
)(),
2717 FmtArg
<A6
>(v6
)(), FmtArg
<A7
>(v7
)());
2720 template<class A1
, class A2
, class A3
, class A4
, class A5
, class A6
,
2722 void Format(UINT nId
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
2723 const A4
& v4
, const A5
& v5
, const A6
& v6
, const A7
& v7
,
2727 if ( strFmt
.Load(nId
) )
2729 Fmt(strFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2730 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(), FmtArg
<A5
>(v5
)(),
2731 FmtArg
<A6
>(v6
)(), FmtArg
<A7
>(v7
)(), FmtArg
<A8
>(v8
)());
2734 template<class A1
, class A2
, class A3
, class A4
, class A5
, class A6
,
2735 class A7
, class A8
, class A9
>
2736 void Format(UINT nId
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
2737 const A4
& v4
, const A5
& v5
, const A6
& v6
, const A7
& v7
,
2738 const A8
& v8
, const A9
& v9
)
2741 if ( strFmt
.Load(nId
) )
2743 Fmt(strFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2744 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(), FmtArg
<A5
>(v5
)(),
2745 FmtArg
<A6
>(v6
)(), FmtArg
<A7
>(v7
)(), FmtArg
<A8
>(v8
)(),
2749 template<class A1
, class A2
, class A3
, class A4
, class A5
, class A6
,
2750 class A7
, class A8
, class A9
, class A10
>
2751 void Format(UINT nId
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
2752 const A4
& v4
, const A5
& v5
, const A6
& v6
, const A7
& v7
,
2753 const A8
& v8
, const A9
& v9
, const A10
& v10
)
2756 if ( strFmt
.Load(nId
) )
2758 Fmt(strFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2759 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(), FmtArg
<A5
>(v5
)(),
2760 FmtArg
<A6
>(v6
)(), FmtArg
<A7
>(v7
)(), FmtArg
<A8
>(v8
)(),
2761 FmtArg
<A9
>(v9
)(), FmtArg
<A10
>(v10
)());
2764 template<class A1
, class A2
, class A3
, class A4
, class A5
, class A6
,
2765 class A7
, class A8
, class A9
, class A10
, class A11
>
2766 void Format(UINT nId
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
2767 const A4
& v4
, const A5
& v5
, const A6
& v6
, const A7
& v7
,
2768 const A8
& v8
, const A9
& v9
, const A10
& v10
, const A11
& v11
)
2771 if ( strFmt
.Load(nId
) )
2773 Fmt(strFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2774 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(), FmtArg
<A5
>(v5
)(),
2775 FmtArg
<A6
>(v6
)(), FmtArg
<A7
>(v7
)(), FmtArg
<A8
>(v8
)(),
2776 FmtArg
<A9
>(v9
)(),FmtArg
<A10
>(v10
)(),FmtArg
<A11
>(v11
)());
2779 template<class A1
, class A2
, class A3
, class A4
, class A5
, class A6
,
2780 class A7
, class A8
, class A9
, class A10
, class A11
, class A12
>
2781 void Format(UINT nId
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
2782 const A4
& v4
, const A5
& v5
, const A6
& v6
, const A7
& v7
,
2783 const A8
& v8
, const A9
& v9
, const A10
& v10
, const A11
& v11
,
2787 if ( strFmt
.Load(nId
) )
2789 Fmt(strFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2790 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(), FmtArg
<A5
>(v5
)(),
2791 FmtArg
<A6
>(v6
)(), FmtArg
<A7
>(v7
)(), FmtArg
<A8
>(v8
)(),
2792 FmtArg
<A9
>(v9
)(), FmtArg
<A10
>(v10
)(),FmtArg
<A11
>(v11
)(),
2793 FmtArg
<A12
>(v12
)());
2796 template<class A1
, class A2
, class A3
, class A4
, class A5
, class A6
,
2797 class A7
, class A8
, class A9
, class A10
, class A11
, class A12
,
2799 void Format(UINT nId
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
2800 const A4
& v4
, const A5
& v5
, const A6
& v6
, const A7
& v7
,
2801 const A8
& v8
, const A9
& v9
, const A10
& v10
, const A11
& v11
,
2802 const A12
& v12
, const A13
& v13
)
2805 if ( strFmt
.Load(nId
) )
2807 Fmt(strFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2808 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(), FmtArg
<A5
>(v5
)(),
2809 FmtArg
<A6
>(v6
)(), FmtArg
<A7
>(v7
)(), FmtArg
<A8
>(v8
)(),
2810 FmtArg
<A9
>(v9
)(), FmtArg
<A10
>(v10
)(),FmtArg
<A11
>(v11
)(),
2811 FmtArg
<A12
>(v12
)(), FmtArg
<A13
>(v13
)());
2814 template<class A1
, class A2
, class A3
, class A4
, class A5
, class A6
,
2815 class A7
, class A8
, class A9
, class A10
, class A11
, class A12
,
2816 class A13
, class A14
>
2817 void Format(UINT nId
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
2818 const A4
& v4
, const A5
& v5
, const A6
& v6
, const A7
& v7
,
2819 const A8
& v8
, const A9
& v9
, const A10
& v10
, const A11
& v11
,
2820 const A12
& v12
, const A13
& v13
, const A14
& v14
)
2823 if ( strFmt
.Load(nId
) )
2825 Fmt(strFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2826 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(), FmtArg
<A5
>(v5
)(),
2827 FmtArg
<A6
>(v6
)(), FmtArg
<A7
>(v7
)(), FmtArg
<A8
>(v8
)(),
2828 FmtArg
<A9
>(v9
)(), FmtArg
<A10
>(v10
)(),FmtArg
<A11
>(v11
)(),
2829 FmtArg
<A12
>(v12
)(), FmtArg
<A13
>(v13
)(),FmtArg
<A14
>(v14
)());
2832 template<class A1
, class A2
, class A3
, class A4
, class A5
, class A6
,
2833 class A7
, class A8
, class A9
, class A10
, class A11
, class A12
,
2834 class A13
, class A14
, class A15
>
2835 void Format(UINT nId
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
2836 const A4
& v4
, const A5
& v5
, const A6
& v6
, const A7
& v7
,
2837 const A8
& v8
, const A9
& v9
, const A10
& v10
, const A11
& v11
,
2838 const A12
& v12
, const A13
& v13
, const A14
& v14
, const A15
& v15
)
2841 if ( strFmt
.Load(nId
) )
2843 Fmt(strFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2844 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(), FmtArg
<A5
>(v5
)(),
2845 FmtArg
<A6
>(v6
)(), FmtArg
<A7
>(v7
)(), FmtArg
<A8
>(v8
)(),
2846 FmtArg
<A9
>(v9
)(), FmtArg
<A10
>(v10
)(),FmtArg
<A11
>(v11
)(),
2847 FmtArg
<A12
>(v12
)(),FmtArg
<A13
>(v13
)(),FmtArg
<A14
>(v14
)(),
2848 FmtArg
<A15
>(v15
)());
2851 template<class A1
, class A2
, class A3
, class A4
, class A5
, class A6
,
2852 class A7
, class A8
, class A9
, class A10
, class A11
, class A12
,
2853 class A13
, class A14
, class A15
, class A16
>
2854 void Format(UINT nId
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
2855 const A4
& v4
, const A5
& v5
, const A6
& v6
, const A7
& v7
,
2856 const A8
& v8
, const A9
& v9
, const A10
& v10
, const A11
& v11
,
2857 const A12
& v12
, const A13
& v13
, const A14
& v14
, const A15
& v15
,
2861 if ( strFmt
.Load(nId
) )
2863 Fmt(strFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2864 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(), FmtArg
<A5
>(v5
)(),
2865 FmtArg
<A6
>(v6
)(), FmtArg
<A7
>(v7
)(), FmtArg
<A8
>(v8
)(),
2866 FmtArg
<A9
>(v9
)(), FmtArg
<A10
>(v10
)(),FmtArg
<A11
>(v11
)(),
2867 FmtArg
<A12
>(v12
)(),FmtArg
<A13
>(v13
)(),FmtArg
<A14
>(v14
)(),
2868 FmtArg
<A15
>(v15
)(), FmtArg
<A16
>(v16
)());
2871 template<class A1
, class A2
, class A3
, class A4
, class A5
, class A6
,
2872 class A7
, class A8
, class A9
, class A10
, class A11
, class A12
,
2873 class A13
, class A14
, class A15
, class A16
, class A17
>
2874 void Format(UINT nId
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
2875 const A4
& v4
, const A5
& v5
, const A6
& v6
, const A7
& v7
,
2876 const A8
& v8
, const A9
& v9
, const A10
& v10
, const A11
& v11
,
2877 const A12
& v12
, const A13
& v13
, const A14
& v14
, const A15
& v15
,
2878 const A16
& v16
, const A17
& v17
)
2881 if ( strFmt
.Load(nId
) )
2883 Fmt(strFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2884 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(), FmtArg
<A5
>(v5
)(),
2885 FmtArg
<A6
>(v6
)(), FmtArg
<A7
>(v7
)(), FmtArg
<A8
>(v8
)(),
2886 FmtArg
<A9
>(v9
)(), FmtArg
<A10
>(v10
)(),FmtArg
<A11
>(v11
)(),
2887 FmtArg
<A12
>(v12
)(),FmtArg
<A13
>(v13
)(),FmtArg
<A14
>(v14
)(),
2888 FmtArg
<A15
>(v15
)(),FmtArg
<A16
>(v16
)(),FmtArg
<A17
>(v17
)());
2892 #endif // #ifndef SS_ANSI
2894 // ...now the other overload of Format: the one that takes a string literal
2896 void Format(const CT
* szFmt
)
2901 void Format(const CT
* szFmt
, const A1
& v
)
2903 Fmt(szFmt
, FmtArg
<A1
>(v
)());
2905 template<class A1
, class A2
>
2906 void Format(const CT
* szFmt
, const A1
& v1
, const A2
& v2
)
2908 Fmt(szFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)());
2910 template<class A1
, class A2
, class A3
>
2911 void Format(const CT
* szFmt
, const A1
& v1
, const A2
& v2
, const A3
& v3
)
2913 Fmt(szFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2916 template<class A1
, class A2
, class A3
, class A4
>
2917 void Format(const CT
* szFmt
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
2920 Fmt(szFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2921 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)());
2923 template<class A1
, class A2
, class A3
, class A4
, class A5
>
2924 void Format(const CT
* szFmt
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
2925 const A4
& v4
, const A5
& v5
)
2927 Fmt(szFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2928 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(), FmtArg
<A5
>(v5
)());
2930 template<class A1
, class A2
, class A3
, class A4
, class A5
, class A6
>
2931 void Format(const CT
* szFmt
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
2932 const A4
& v4
, const A5
& v5
, const A6
& v6
)
2934 Fmt(szFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2935 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(), FmtArg
<A5
>(v5
)(),
2938 template<class A1
, class A2
, class A3
, class A4
, class A5
, class A6
,
2940 void Format(const CT
* szFmt
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
2941 const A4
& v4
, const A5
& v5
, const A6
& v6
, const A7
& v7
)
2943 Fmt(szFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2944 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(), FmtArg
<A5
>(v5
)(),
2945 FmtArg
<A6
>(v6
)(), FmtArg
<A7
>(v7
)());
2947 template<class A1
, class A2
, class A3
, class A4
, class A5
, class A6
,
2949 void Format(const CT
* szFmt
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
2950 const A4
& v4
, const A5
& v5
, const A6
& v6
, const A7
& v7
,
2953 Fmt(szFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2954 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(), FmtArg
<A5
>(v5
)(),
2955 FmtArg
<A6
>(v6
)(), FmtArg
<A7
>(v7
)(), FmtArg
<A8
>(v8
)());
2957 template<class A1
, class A2
, class A3
, class A4
, class A5
, class A6
,
2958 class A7
, class A8
, class A9
>
2959 void Format(const CT
* szFmt
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
2960 const A4
& v4
, const A5
& v5
, const A6
& v6
, const A7
& v7
,
2961 const A8
& v8
, const A9
& v9
)
2963 Fmt(szFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2964 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(), FmtArg
<A5
>(v5
)(),
2965 FmtArg
<A6
>(v6
)(), FmtArg
<A7
>(v7
)(), FmtArg
<A8
>(v8
)(),
2968 template<class A1
, class A2
, class A3
, class A4
, class A5
, class A6
,
2969 class A7
, class A8
, class A9
, class A10
>
2970 void Format(const CT
* szFmt
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
2971 const A4
& v4
, const A5
& v5
, const A6
& v6
, const A7
& v7
,
2972 const A8
& v8
, const A9
& v9
, const A10
& v10
)
2974 Fmt(szFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2975 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(), FmtArg
<A5
>(v5
)(),
2976 FmtArg
<A6
>(v6
)(), FmtArg
<A7
>(v7
)(), FmtArg
<A8
>(v8
)(),
2977 FmtArg
<A9
>(v9
)(), FmtArg
<A10
>(v10
)());
2979 template<class A1
, class A2
, class A3
, class A4
, class A5
, class A6
,
2980 class A7
, class A8
, class A9
, class A10
, class A11
>
2981 void Format(const CT
* szFmt
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
2982 const A4
& v4
, const A5
& v5
, const A6
& v6
, const A7
& v7
,
2983 const A8
& v8
, const A9
& v9
, const A10
& v10
, const A11
& v11
)
2985 Fmt(szFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2986 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(), FmtArg
<A5
>(v5
)(),
2987 FmtArg
<A6
>(v6
)(), FmtArg
<A7
>(v7
)(), FmtArg
<A8
>(v8
)(),
2988 FmtArg
<A9
>(v9
)(),FmtArg
<A10
>(v10
)(),FmtArg
<A11
>(v11
)());
2990 template<class A1
, class A2
, class A3
, class A4
, class A5
, class A6
,
2991 class A7
, class A8
, class A9
, class A10
, class A11
, class A12
>
2992 void Format(const CT
* szFmt
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
2993 const A4
& v4
, const A5
& v5
, const A6
& v6
, const A7
& v7
,
2994 const A8
& v8
, const A9
& v9
, const A10
& v10
, const A11
& v11
,
2997 Fmt(szFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
2998 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(), FmtArg
<A5
>(v5
)(),
2999 FmtArg
<A6
>(v6
)(), FmtArg
<A7
>(v7
)(), FmtArg
<A8
>(v8
)(),
3000 FmtArg
<A9
>(v9
)(), FmtArg
<A10
>(v10
)(),FmtArg
<A11
>(v11
)(),
3001 FmtArg
<A12
>(v12
)());
3003 template<class A1
, class A2
, class A3
, class A4
, class A5
, class A6
,
3004 class A7
, class A8
, class A9
, class A10
, class A11
, class A12
,
3006 void Format(const CT
* szFmt
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
3007 const A4
& v4
, const A5
& v5
, const A6
& v6
, const A7
& v7
,
3008 const A8
& v8
, const A9
& v9
, const A10
& v10
, const A11
& v11
,
3009 const A12
& v12
, const A13
& v13
)
3011 Fmt(szFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
3012 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(), FmtArg
<A5
>(v5
)(),
3013 FmtArg
<A6
>(v6
)(), FmtArg
<A7
>(v7
)(), FmtArg
<A8
>(v8
)(),
3014 FmtArg
<A9
>(v9
)(), FmtArg
<A10
>(v10
)(),FmtArg
<A11
>(v11
)(),
3015 FmtArg
<A12
>(v12
)(), FmtArg
<A13
>(v13
)());
3017 template<class A1
, class A2
, class A3
, class A4
, class A5
, class A6
,
3018 class A7
, class A8
, class A9
, class A10
, class A11
, class A12
,
3019 class A13
, class A14
>
3020 void Format(const CT
* szFmt
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
3021 const A4
& v4
, const A5
& v5
, const A6
& v6
, const A7
& v7
,
3022 const A8
& v8
, const A9
& v9
, const A10
& v10
, const A11
& v11
,
3023 const A12
& v12
, const A13
& v13
, const A14
& v14
)
3025 Fmt(szFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
3026 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(), FmtArg
<A5
>(v5
)(),
3027 FmtArg
<A6
>(v6
)(), FmtArg
<A7
>(v7
)(), FmtArg
<A8
>(v8
)(),
3028 FmtArg
<A9
>(v9
)(), FmtArg
<A10
>(v10
)(),FmtArg
<A11
>(v11
)(),
3029 FmtArg
<A12
>(v12
)(), FmtArg
<A13
>(v13
)(),FmtArg
<A14
>(v14
)());
3031 template<class A1
, class A2
, class A3
, class A4
, class A5
, class A6
,
3032 class A7
, class A8
, class A9
, class A10
, class A11
, class A12
,
3033 class A13
, class A14
, class A15
>
3034 void Format(const CT
* szFmt
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
3035 const A4
& v4
, const A5
& v5
, const A6
& v6
, const A7
& v7
,
3036 const A8
& v8
, const A9
& v9
, const A10
& v10
, const A11
& v11
,
3037 const A12
& v12
, const A13
& v13
, const A14
& v14
, const A15
& v15
)
3039 Fmt(szFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
3040 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(), FmtArg
<A5
>(v5
)(),
3041 FmtArg
<A6
>(v6
)(), FmtArg
<A7
>(v7
)(), FmtArg
<A8
>(v8
)(),
3042 FmtArg
<A9
>(v9
)(), FmtArg
<A10
>(v10
)(),FmtArg
<A11
>(v11
)(),
3043 FmtArg
<A12
>(v12
)(),FmtArg
<A13
>(v13
)(),FmtArg
<A14
>(v14
)(),
3044 FmtArg
<A15
>(v15
)());
3046 template<class A1
, class A2
, class A3
, class A4
, class A5
, class A6
,
3047 class A7
, class A8
, class A9
, class A10
, class A11
, class A12
,
3048 class A13
, class A14
, class A15
, class A16
>
3049 void Format(const CT
* szFmt
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
3050 const A4
& v4
, const A5
& v5
, const A6
& v6
, const A7
& v7
,
3051 const A8
& v8
, const A9
& v9
, const A10
& v10
, const A11
& v11
,
3052 const A12
& v12
, const A13
& v13
, const A14
& v14
, const A15
& v15
,
3055 Fmt(szFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
3056 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(), FmtArg
<A5
>(v5
)(),
3057 FmtArg
<A6
>(v6
)(), FmtArg
<A7
>(v7
)(), FmtArg
<A8
>(v8
)(),
3058 FmtArg
<A9
>(v9
)(), FmtArg
<A10
>(v10
)(),FmtArg
<A11
>(v11
)(),
3059 FmtArg
<A12
>(v12
)(),FmtArg
<A13
>(v13
)(),FmtArg
<A14
>(v14
)(),
3060 FmtArg
<A15
>(v15
)(), FmtArg
<A16
>(v16
)());
3062 template<class A1
, class A2
, class A3
, class A4
, class A5
, class A6
,
3063 class A7
, class A8
, class A9
, class A10
, class A11
, class A12
,
3064 class A13
, class A14
, class A15
, class A16
, class A17
>
3065 void Format(const CT
* szFmt
, const A1
& v1
, const A2
& v2
, const A3
& v3
,
3066 const A4
& v4
, const A5
& v5
, const A6
& v6
, const A7
& v7
,
3067 const A8
& v8
, const A9
& v9
, const A10
& v10
, const A11
& v11
,
3068 const A12
& v12
, const A13
& v13
, const A14
& v14
, const A15
& v15
,
3069 const A16
& v16
, const A17
& v17
)
3071 Fmt(szFmt
, FmtArg
<A1
>(v1
)(), FmtArg
<A2
>(v2
)(),
3072 FmtArg
<A3
>(v3
)(), FmtArg
<A4
>(v4
)(), FmtArg
<A5
>(v5
)(),
3073 FmtArg
<A6
>(v6
)(), FmtArg
<A7
>(v7
)(), FmtArg
<A8
>(v8
)(),
3074 FmtArg
<A9
>(v9
)(), FmtArg
<A10
>(v10
)(),FmtArg
<A11
>(v11
)(),
3075 FmtArg
<A12
>(v12
)(),FmtArg
<A13
>(v13
)(),FmtArg
<A14
>(v14
)(),
3076 FmtArg
<A15
>(v15
)(),FmtArg
<A16
>(v16
)(),FmtArg
<A17
>(v17
)());
3079 #else // #ifdef SS_SAFE_FORMAT
3084 void Format(UINT nId
, ...)
3087 va_start(argList
, nId
);
3090 if ( strFmt
.Load(nId
) )
3091 FormatV(strFmt
, argList
);
3096 #endif // #ifdef SS_ANSI
3098 void Format(const CT
* szFmt
, ...)
3101 va_start(argList
, szFmt
);
3102 FormatV(szFmt
, argList
);
3106 #endif // #ifdef SS_SAFE_FORMAT
3108 void AppendFormat(const CT
* szFmt
, ...)
3111 va_start(argList
, szFmt
);
3112 AppendFormatV(szFmt
, argList
);
3116 #define MAX_FMT_TRIES 5 // #of times we try
3117 #define FMT_BLOCK_SIZE 2048 // # of bytes to increment per try
3118 #define BUFSIZE_1ST 256
3119 #define BUFSIZE_2ND 512
3120 #define STD_BUF_SIZE 1024
3122 // an efficient way to add formatted characters to the string. You may only
3123 // add up to STD_BUF_SIZE characters at a time, though
3124 void AppendFormatV(const CT
* szFmt
, va_list argList
)
3126 CT szBuf
[STD_BUF_SIZE
];
3127 int nLen
= ssnprintf(szBuf
, STD_BUF_SIZE
-1, szFmt
, argList
);
3130 this->append(szBuf
, nLen
);
3133 // -------------------------------------------------------------------------
3134 // FUNCTION: FormatV
3135 // void FormatV(PCSTR szFormat, va_list, argList);
3138 // This function formats the string with sprintf style format-specs.
3139 // It makes a general guess at required buffer size and then tries
3140 // successively larger buffers until it finds one big enough or a
3141 // threshold (MAX_FMT_TRIES) is exceeded.
3144 // szFormat - a PCSTR holding the format of the output
3145 // argList - a Microsoft specific va_list for variable argument lists
3148 // -------------------------------------------------------------------------
3150 // NOTE: Changed by JM to actually function under non-win32,
3151 // and to remove the upper limit on size.
3152 void FormatV(const CT
* szFormat
, va_list argList
)
3154 // try and grab a sufficient buffersize
3155 int nChars
= FMT_BLOCK_SIZE
;
3158 CT
*p
= reinterpret_cast<CT
*>(malloc(sizeof(CT
)*nChars
));
3163 va_copy(argCopy
, argList
);
3165 int nActual
= ssvsprintf(p
, nChars
, szFormat
, argCopy
);
3166 /* If that worked, return the string. */
3167 if (nActual
> -1 && nActual
< nChars
)
3168 { /* make sure it's NULL terminated */
3170 this->assign(p
, nActual
);
3175 /* Else try again with more space. */
3176 if (nActual
> -1) /* glibc 2.1 */
3177 nChars
= nActual
+ 1; /* precisely what is needed */
3178 else /* glibc 2.0 */
3179 nChars
*= 2; /* twice the old size */
3181 CT
*np
= reinterpret_cast<CT
*>(realloc(p
, sizeof(CT
)*nChars
));
3186 return; // failed :(
3193 // -------------------------------------------------------------------------
3194 // CString Facade Functions:
3196 // The following methods are intended to allow you to use this class as a
3197 // near drop-in replacement for CString.
3198 // -------------------------------------------------------------------------
3200 BSTR
AllocSysString() const
3204 return ::SysAllocString(os
.c_str());
3208 #ifndef SS_NO_LOCALE
3209 int Collate(PCMYSTR szThat
) const
3211 return sscoll(this->c_str(), this->length(), szThat
, sslen(szThat
));
3214 int CollateNoCase(PCMYSTR szThat
) const
3216 return ssicoll(this->c_str(), this->length(), szThat
, sslen(szThat
));
3219 int Compare(PCMYSTR szThat
) const
3221 return this->compare(szThat
);
3224 int CompareNoCase(PCMYSTR szThat
) const
3226 return ssicmp(this->c_str(), szThat
);
3229 int Delete(int nIdx
, int nCount
=1)
3234 if ( nIdx
< this->GetLength() )
3235 this->erase(static_cast<MYSIZE
>(nIdx
), static_cast<MYSIZE
>(nCount
));
3245 int Find(CT ch
) const
3247 MYSIZE nIdx
= this->find_first_of(ch
);
3248 return static_cast<int>(MYBASE::npos
== nIdx
? -1 : nIdx
);
3251 int Find(PCMYSTR szSub
) const
3253 MYSIZE nIdx
= this->find(szSub
);
3254 return static_cast<int>(MYBASE::npos
== nIdx
? -1 : nIdx
);
3257 int Find(CT ch
, int nStart
) const
3259 // CString::Find docs say add 1 to nStart when it's not zero
3260 // CString::Find code doesn't do that however. We'll stick
3261 // with what the code does
3263 MYSIZE nIdx
= this->find_first_of(ch
, static_cast<MYSIZE
>(nStart
));
3264 return static_cast<int>(MYBASE::npos
== nIdx
? -1 : nIdx
);
3267 int Find(PCMYSTR szSub
, int nStart
) const
3269 // CString::Find docs say add 1 to nStart when it's not zero
3270 // CString::Find code doesn't do that however. We'll stick
3271 // with what the code does
3273 MYSIZE nIdx
= this->find(szSub
, static_cast<MYSIZE
>(nStart
));
3274 return static_cast<int>(MYBASE::npos
== nIdx
? -1 : nIdx
);
3277 int FindOneOf(PCMYSTR szCharSet
) const
3279 MYSIZE nIdx
= this->find_first_of(szCharSet
);
3280 return static_cast<int>(MYBASE::npos
== nIdx
? -1 : nIdx
);
3284 void FormatMessage(PCMYSTR szFormat
, ...) throw(std::exception
)
3287 va_start(argList
, szFormat
);
3289 if ( ssfmtmsg(FORMAT_MESSAGE_FROM_STRING
|FORMAT_MESSAGE_ALLOCATE_BUFFER
,
3291 reinterpret_cast<PMYSTR
>(&szTemp
), 0, &argList
) == 0 ||
3294 throw std::runtime_error("out of memory");
3301 void FormatMessage(UINT nFormatId
, ...) throw(std::exception
)
3304 VERIFY(sFormat
.LoadString(nFormatId
));
3306 va_start(argList
, nFormatId
);
3308 if ( ssfmtmsg(FORMAT_MESSAGE_FROM_STRING
|FORMAT_MESSAGE_ALLOCATE_BUFFER
,
3310 reinterpret_cast<PMYSTR
>(&szTemp
), 0, &argList
) == 0 ||
3313 throw std::runtime_error("out of memory");
3321 // GetAllocLength -- an MSVC7 function but it costs us nothing to add it.
3323 int GetAllocLength()
3325 return static_cast<int>(this->capacity());
3328 // -------------------------------------------------------------------------
3329 // GetXXXX -- Direct access to character buffer
3330 // -------------------------------------------------------------------------
3331 CT
GetAt(int nIdx
) const
3333 return this->at(static_cast<MYSIZE
>(nIdx
));
3336 CT
* GetBuffer(int nMinLen
=-1)
3338 return GetBuf(nMinLen
);
3341 CT
* GetBufferSetLength(int nLen
)
3343 return BufferSet(nLen
);
3346 // GetLength() -- MFC docs say this is the # of BYTES but
3347 // in truth it is the number of CHARACTERs (chars or wchar_ts)
3348 int GetLength() const
3350 return static_cast<int>(this->length());
3353 int Insert(int nIdx
, CT ch
)
3355 if ( static_cast<MYSIZE
>(nIdx
) > this->size()-1 )
3356 this->append(1, ch
);
3358 this->insert(static_cast<MYSIZE
>(nIdx
), 1, ch
);
3362 int Insert(int nIdx
, PCMYSTR sz
)
3364 if ( static_cast<MYSIZE
>(nIdx
) >= this->size() )
3365 this->append(sz
, static_cast<MYSIZE
>(sslen(sz
)));
3367 this->insert(static_cast<MYSIZE
>(nIdx
), sz
);
3372 bool IsEmpty() const
3374 return this->empty();
3377 MYTYPE
Left(int nCount
) const
3379 // Range check the count.
3381 nCount
= SSMAX(0, SSMIN(nCount
, static_cast<int>(this->size())));
3382 return this->substr(0, static_cast<MYSIZE
>(nCount
));
3386 bool LoadString(UINT nId
)
3388 return this->Load(nId
);
3399 std::reverse(this->begin(), this->end());
3407 MYTYPE
Mid(int nFirst
) const
3409 return Mid(nFirst
, this->GetLength()-nFirst
);
3412 MYTYPE
Mid(int nFirst
, int nCount
) const
3414 // CString does range checking here. Since we're trying to emulate it,
3415 // we must check too.
3422 int nSize
= static_cast<int>(this->size());
3424 if ( nFirst
+ nCount
> nSize
)
3425 nCount
= nSize
- nFirst
;
3427 if ( nFirst
> nSize
)
3430 ASSERT(nFirst
>= 0);
3431 ASSERT(nFirst
+ nCount
<= nSize
);
3433 return this->substr(static_cast<MYSIZE
>(nFirst
),
3434 static_cast<MYSIZE
>(nCount
));
3437 void ReleaseBuffer(int nNewLen
=-1)
3446 while ( (nIdx
=this->find_first_of(ch
)) != MYBASE::npos
)
3448 this->erase(nIdx
, 1);
3454 int Replace(CT chOld
, CT chNew
)
3458 for ( MYITER iter
=this->begin(); iter
!= this->end(); iter
++ )
3460 if ( *iter
== chOld
)
3470 int Replace(PCMYSTR szOld
, PCMYSTR szNew
)
3474 MYSIZE nOldLen
= sslen(szOld
);
3478 // If the replacement string is longer than the one it replaces, this
3479 // string is going to have to grow in size, Figure out how much
3480 // and grow it all the way now, rather than incrementally
3482 MYSIZE nNewLen
= sslen(szNew
);
3483 if ( nNewLen
> nOldLen
)
3486 while ( nIdx
< this->length() &&
3487 (nIdx
=this->find(szOld
, nIdx
)) != MYBASE::npos
)
3492 this->reserve(this->size() + nFound
* (nNewLen
- nOldLen
));
3496 static const CT ch
= CT(0);
3497 PCMYSTR szRealNew
= szNew
== 0 ? &ch
: szNew
;
3500 while ( nIdx
< this->length() &&
3501 (nIdx
=this->find(szOld
, nIdx
)) != MYBASE::npos
)
3503 this->replace(this->begin()+nIdx
, this->begin()+nIdx
+nOldLen
,
3514 int ReverseFind(CT ch
) const
3516 MYSIZE nIdx
= this->find_last_of(ch
);
3517 return static_cast<int>(MYBASE::npos
== nIdx
? -1 : nIdx
);
3520 // ReverseFind overload that's not in CString but might be useful
3521 int ReverseFind(PCMYSTR szFind
, MYSIZE pos
=MYBASE::npos
) const
3523 //yuvalt - this does not compile with g++ since MYTTYPE() is different type
3524 //MYSIZE nIdx = this->rfind(0 == szFind ? MYTYPE() : szFind, pos);
3525 MYSIZE nIdx
= this->rfind(0 == szFind
? "" : szFind
, pos
);
3526 return static_cast<int>(MYBASE::npos
== nIdx
? -1 : nIdx
);
3529 MYTYPE
Right(int nCount
) const
3531 // Range check the count.
3533 nCount
= SSMAX(0, SSMIN(nCount
, static_cast<int>(this->size())));
3534 return this->substr(this->size()-static_cast<MYSIZE
>(nCount
));
3537 void SetAt(int nIndex
, CT ch
)
3539 ASSERT(this->size() > static_cast<MYSIZE
>(nIndex
));
3540 this->at(static_cast<MYSIZE
>(nIndex
)) = ch
;
3544 BSTR
SetSysString(BSTR
* pbstr
) const
3548 if ( !::SysReAllocStringLen(pbstr
, os
.c_str(), os
.length()) )
3549 throw std::runtime_error("out of memory");
3551 ASSERT(*pbstr
!= 0);
3556 MYTYPE
SpanExcluding(PCMYSTR szCharSet
) const
3558 MYSIZE pos
= this->find_first_of(szCharSet
);
3559 return pos
== MYBASE::npos
? *this : Left(pos
);
3562 MYTYPE
SpanIncluding(PCMYSTR szCharSet
) const
3564 MYSIZE pos
= this->find_first_not_of(szCharSet
);
3565 return pos
== MYBASE::npos
? *this : Left(pos
);
3568 #if defined SS_WIN32 && !defined(UNICODE) && !defined(SS_ANSI)
3570 // CString's OemToAnsi and AnsiToOem functions are available only in
3571 // Unicode builds. However since we're a template we also need a
3572 // runtime check of CT and a reinterpret_cast to account for the fact
3573 // that CStdStringW gets instantiated even in non-Unicode builds.
3577 if ( sizeof(CT
) == sizeof(char) && !empty() )
3579 ::CharToOem(reinterpret_cast<PCSTR
>(this->c_str()),
3580 reinterpret_cast<PSTR
>(GetBuf()));
3590 if ( sizeof(CT
) == sizeof(char) && !empty() )
3592 ::OemToChar(reinterpret_cast<PCSTR
>(this->c_str()),
3593 reinterpret_cast<PSTR
>(GetBuf()));
3604 // -------------------------------------------------------------------------
3605 // Trim and its variants
3606 // -------------------------------------------------------------------------
3609 return TrimLeft().TrimRight();
3614 this->erase(this->begin(),
3615 std::find_if(this->begin(), this->end(), NotSpace
<CT
>()));
3620 MYTYPE
& TrimLeft(CT tTrim
)
3622 this->erase(0, this->find_first_not_of(tTrim
));
3626 MYTYPE
& TrimLeft(PCMYSTR szTrimChars
)
3628 this->erase(0, this->find_first_not_of(szTrimChars
));
3634 // NOTE: When comparing reverse_iterators here (MYRITER), I avoid using
3635 // operator!=. This is because namespace rel_ops also has a template
3636 // operator!= which conflicts with the global operator!= already defined
3637 // for reverse_iterator in the header <utility>.
3638 // Thanks to John James for alerting me to this.
3640 MYRITER it
= std::find_if(this->rbegin(), this->rend(), NotSpace
<CT
>());
3641 if ( !(this->rend() == it
) )
3642 this->erase(this->rend() - it
);
3644 this->erase(!(it
== this->rend()) ? this->find_last_of(*it
) + 1 : 0);
3648 MYTYPE
& TrimRight(CT tTrim
)
3650 MYSIZE nIdx
= this->find_last_not_of(tTrim
);
3651 this->erase(MYBASE::npos
== nIdx
? 0 : ++nIdx
);
3655 MYTYPE
& TrimRight(PCMYSTR szTrimChars
)
3657 MYSIZE nIdx
= this->find_last_not_of(szTrimChars
);
3658 this->erase(MYBASE::npos
== nIdx
? 0 : ++nIdx
);
3667 this->assign(mt
.c_str(), mt
.size());
3670 // I have intentionally not implemented the following CString
3671 // functions. You cannot make them work without taking advantage
3672 // of implementation specific behavior. However if you absolutely
3673 // MUST have them, uncomment out these lines for "sort-of-like"
3674 // their behavior. You're on your own.
3676 // CT* LockBuffer() { return GetBuf(); }// won't really lock
3677 // void UnlockBuffer(); { } // why have UnlockBuffer w/o LockBuffer?
3679 // Array-indexing operators. Required because we defined an implicit cast
3680 // to operator const CT* (Thanks to Julian Selman for pointing this out)
3682 CT
& operator[](int nIdx
)
3684 return static_cast<MYBASE
*>(this)->operator[](static_cast<MYSIZE
>(nIdx
));
3687 const CT
& operator[](int nIdx
) const
3689 return static_cast<const MYBASE
*>(this)->operator[](static_cast<MYSIZE
>(nIdx
));
3692 CT
& operator[](unsigned int nIdx
)
3694 return static_cast<MYBASE
*>(this)->operator[](static_cast<MYSIZE
>(nIdx
));
3697 const CT
& operator[](unsigned int nIdx
) const
3699 return static_cast<const MYBASE
*>(this)->operator[](static_cast<MYSIZE
>(nIdx
));
3702 CT
& operator[](unsigned long nIdx
)
3704 return static_cast<MYBASE
*>(this)->operator[](static_cast<MYSIZE
>(nIdx
));
3707 const CT
& operator[](unsigned long nIdx
) const
3709 return static_cast<const MYBASE
*>(this)->operator[](static_cast<MYSIZE
>(nIdx
));
3712 #ifndef SS_NO_IMPLICIT_CAST
3713 operator const CT
*() const
3715 return this->c_str();
3719 // IStream related functions. Useful in IPersistStream implementations
3721 #ifdef SS_INC_COMDEF
3723 // struct SSSHDR - useful for non Std C++ persistence schemes.
3724 typedef struct SSSHDR
3728 } SSSHDR
; // as in "Standard String Stream Header"
3730 #define SSSO_UNICODE 0x01 // the string is a wide string
3731 #define SSSO_COMPRESS 0x02 // the string is compressed
3733 // -------------------------------------------------------------------------
3734 // FUNCTION: StreamSize
3736 // Returns how many bytes it will take to StreamSave() this CStdString
3737 // object to an IStream.
3738 // -------------------------------------------------------------------------
3739 ULONG
StreamSize() const
3741 // Control header plus string
3742 ASSERT(this->size()*sizeof(CT
) < 0xffffffffUL
- sizeof(SSSHDR
));
3743 return (this->size() * sizeof(CT
)) + sizeof(SSSHDR
);
3746 // -------------------------------------------------------------------------
3747 // FUNCTION: StreamSave
3749 // Saves this CStdString object to a COM IStream.
3750 // -------------------------------------------------------------------------
3751 HRESULT
StreamSave(IStream
* pStream
) const
3753 ASSERT(this->size()*sizeof(CT
) < 0xffffffffUL
- sizeof(SSSHDR
));
3754 HRESULT hr
= E_FAIL
;
3755 ASSERT(pStream
!= 0);
3757 hdr
.byCtrl
= sizeof(CT
) == 2 ? SSSO_UNICODE
: 0;
3758 hdr
.nChars
= this->size();
3761 if ( FAILED(hr
=pStream
->Write(&hdr
, sizeof(SSSHDR
), 0)) )
3763 TRACE(_T("StreamSave: Cannot write control header, ERR=0x%X\n"),hr
);
3767 ; // nothing to write
3769 else if ( FAILED(hr
=pStream
->Write(this->c_str(),
3770 this->size()*sizeof(CT
), 0)) )
3772 TRACE(_T("StreamSave: Cannot write string to stream 0x%X\n"), hr
);
3779 // -------------------------------------------------------------------------
3780 // FUNCTION: StreamLoad
3782 // This method loads the object from an IStream.
3783 // -------------------------------------------------------------------------
3784 HRESULT
StreamLoad(IStream
* pStream
)
3786 ASSERT(pStream
!= 0);
3788 HRESULT hr
= E_FAIL
;
3790 if ( FAILED(hr
=pStream
->Read(&hdr
, sizeof(SSSHDR
), 0)) )
3792 TRACE(_T("StreamLoad: Cant read control header, ERR=0x%X\n"), hr
);
3794 else if ( hdr
.nChars
> 0 )
3797 PMYSTR pMyBuf
= BufferSet(hdr
.nChars
);
3799 // If our character size matches the character size of the string
3800 // we're trying to read, then we can read it directly into our
3801 // buffer. Otherwise, we have to read into an intermediate buffer
3804 if ( (hdr
.byCtrl
& SSSO_UNICODE
) != 0 )
3806 ULONG nBytes
= hdr
.nChars
* sizeof(wchar_t);
3807 if ( sizeof(CT
) == sizeof(wchar_t) )
3809 if ( FAILED(hr
=pStream
->Read(pMyBuf
, nBytes
, &nRead
)) )
3810 TRACE(_T("StreamLoad: Cannot read string: 0x%X\n"), hr
);
3814 PWSTR pBufW
= reinterpret_cast<PWSTR
>(_alloca((nBytes
)+1));
3815 if ( FAILED(hr
=pStream
->Read(pBufW
, nBytes
, &nRead
)) )
3816 TRACE(_T("StreamLoad: Cannot read string: 0x%X\n"), hr
);
3818 sscpy(pMyBuf
, pBufW
, hdr
.nChars
);
3823 ULONG nBytes
= hdr
.nChars
* sizeof(char);
3824 if ( sizeof(CT
) == sizeof(char) )
3826 if ( FAILED(hr
=pStream
->Read(pMyBuf
, nBytes
, &nRead
)) )
3827 TRACE(_T("StreamLoad: Cannot read string: 0x%X\n"), hr
);
3831 PSTR pBufA
= reinterpret_cast<PSTR
>(_alloca(nBytes
));
3832 if ( FAILED(hr
=pStream
->Read(pBufA
, hdr
.nChars
, &nRead
)) )
3833 TRACE(_T("StreamLoad: Cannot read string: 0x%X\n"), hr
);
3835 sscpy(pMyBuf
, pBufA
, hdr
.nChars
);
3845 #endif // #ifdef SS_INC_COMDEF
3849 // SetResourceHandle/GetResourceHandle. In MFC builds, these map directly
3850 // to AfxSetResourceHandle and AfxGetResourceHandle. In non-MFC builds they
3851 // point to a single static HINST so that those who call the member
3852 // functions that take resource IDs can provide an alternate HINST of a DLL
3853 // to search. This is not exactly the list of HMODULES that MFC provides
3854 // but it's better than nothing.
3857 static void SetResourceHandle(HMODULE hNew
)
3859 AfxSetResourceHandle(hNew
);
3861 static HMODULE
GetResourceHandle()
3863 return AfxGetResourceHandle();
3866 static void SetResourceHandle(HMODULE hNew
)
3868 SSResourceHandle() = hNew
;
3870 static HMODULE
GetResourceHandle()
3872 return SSResourceHandle();
3879 // -----------------------------------------------------------------------------
3880 // MSVC USERS: HOW TO EXPORT CSTDSTRING FROM A DLL
3882 // If you are using MS Visual C++ and you want to export CStdStringA and
3883 // CStdStringW from a DLL, then all you need to
3885 // 1. make sure that all components link to the same DLL version
3886 // of the CRT (not the static one).
3887 // 2. Uncomment the 3 lines of code below
3888 // 3. #define 2 macros per the instructions in MS KnowledgeBase
3889 // article Q168958. The macros are:
3891 // MACRO DEFINTION WHEN EXPORTING DEFINITION WHEN IMPORTING
3892 // ----- ------------------------ -------------------------
3893 // SSDLLEXP (nothing, just #define it) extern
3894 // SSDLLSPEC __declspec(dllexport) __declspec(dllimport)
3896 // Note that these macros must be available to ALL clients who want to
3897 // link to the DLL and use the class. If they
3899 // A word of advice: Don't bother.
3901 // Really, it is not necessary to export CStdString functions from a DLL. I
3902 // never do. In my projects, I do generally link to the DLL version of the
3903 // Standard C++ Library, but I do NOT attempt to export CStdString functions.
3904 // I simply include the header where it is needed and allow for the code
3907 // That redundancy is a lot less than you think. This class does most of its
3908 // work via the Standard C++ Library, particularly the base_class basic_string<>
3909 // member functions. Most of the functions here are small enough to be inlined
3910 // anyway. Besides, you'll find that in actual practice you use less than 1/2
3911 // of the code here, even in big projects and different modules will use as
3912 // little as 10% of it. That means a lot less functions actually get linked
3913 // your binaries. If you export this code from a DLL, it ALL gets linked in.
3915 // I've compared the size of the binaries from exporting vs NOT exporting. Take
3916 // my word for it -- exporting this code is not worth the hassle.
3918 // -----------------------------------------------------------------------------
3919 //#pragma warning(disable:4231) // non-standard extension ("extern template")
3920 // SSDLLEXP template class SSDLLSPEC CStdStr<char>;
3921 // SSDLLEXP template class SSDLLSPEC CStdStr<wchar_t>;
3924 // =============================================================================
3925 // END OF CStdStr INLINE FUNCTION DEFINITIONS
3926 // =============================================================================
3928 // Now typedef our class names based upon this humongous template
3930 typedef CStdStr
<char> CStdStringA
; // a better std::string
3931 typedef CStdStr
<wchar_t> CStdStringW
; // a better std::wstring
3932 typedef CStdStr
<uint16_t> CStdString16
; // a 16bit char string
3933 typedef CStdStr
<uint32_t> CStdString32
; // a 32bit char string
3934 typedef CStdStr
<OLECHAR
> CStdStringO
; // almost always CStdStringW
3936 // -----------------------------------------------------------------------------
3937 // CStdStr addition functions defined as inline
3938 // -----------------------------------------------------------------------------
3941 inline CStdStringA
operator+(const CStdStringA
& s1
, const CStdStringA
& s2
)
3943 CStdStringA
sRet(SSREF(s1
));
3947 inline CStdStringA
operator+(const CStdStringA
& s1
, CStdStringA::value_type t
)
3949 CStdStringA
sRet(SSREF(s1
));
3953 inline CStdStringA
operator+(const CStdStringA
& s1
, PCSTR pA
)
3955 CStdStringA
sRet(SSREF(s1
));
3959 inline CStdStringA
operator+(PCSTR pA
, const CStdStringA
& sA
)
3962 CStdStringA::size_type nObjSize
= sA
.size();
3963 CStdStringA::size_type nLitSize
=
3964 static_cast<CStdStringA::size_type
>(sslen(pA
));
3966 sRet
.reserve(nLitSize
+ nObjSize
);
3973 inline CStdStringA
operator+(const CStdStringA
& s1
, const CStdStringW
& s2
)
3975 return s1
+ CStdStringA(s2
);
3977 inline CStdStringW
operator+(const CStdStringW
& s1
, const CStdStringW
& s2
)
3979 CStdStringW
sRet(SSREF(s1
));
3983 inline CStdStringA
operator+(const CStdStringA
& s1
, PCWSTR pW
)
3985 return s1
+ CStdStringA(pW
);
3989 inline CStdStringW
operator+(PCWSTR pW
, const CStdStringA
& sA
)
3991 return CStdStringW(pW
) + CStdStringW(SSREF(sA
));
3993 inline CStdStringW
operator+(PCSTR pA
, const CStdStringW
& sW
)
3995 return CStdStringW(pA
) + sW
;
3998 inline CStdStringA
operator+(PCWSTR pW
, const CStdStringA
& sA
)
4000 return CStdStringA(pW
) + sA
;
4002 inline CStdStringA
operator+(PCSTR pA
, const CStdStringW
& sW
)
4004 return pA
+ CStdStringA(sW
);
4008 // ...Now the wide string versions.
4009 inline CStdStringW
operator+(const CStdStringW
& s1
, CStdStringW::value_type t
)
4011 CStdStringW
sRet(SSREF(s1
));
4015 inline CStdStringW
operator+(const CStdStringW
& s1
, PCWSTR pW
)
4017 CStdStringW
sRet(SSREF(s1
));
4021 inline CStdStringW
operator+(PCWSTR pW
, const CStdStringW
& sW
)
4024 CStdStringW::size_type nObjSize
= sW
.size();
4025 CStdStringA::size_type nLitSize
=
4026 static_cast<CStdStringW::size_type
>(sslen(pW
));
4028 sRet
.reserve(nLitSize
+ nObjSize
);
4034 inline CStdStringW
operator+(const CStdStringW
& s1
, const CStdStringA
& s2
)
4036 return s1
+ CStdStringW(s2
);
4038 inline CStdStringW
operator+(const CStdStringW
& s1
, PCSTR pA
)
4040 return s1
+ CStdStringW(pA
);
4044 // New-style format function is a template
4046 #ifdef SS_SAFE_FORMAT
4049 struct FmtArg
<CStdStringA
>
4051 explicit FmtArg(const CStdStringA
& arg
) : a_(arg
) {}
4052 PCSTR
operator()() const { return a_
.c_str(); }
4053 const CStdStringA
& a_
;
4055 FmtArg
<CStdStringA
>& operator=(const FmtArg
<CStdStringA
>&) { return *this; }
4058 struct FmtArg
<CStdStringW
>
4060 explicit FmtArg(const CStdStringW
& arg
) : a_(arg
) {}
4061 PCWSTR
operator()() const { return a_
.c_str(); }
4062 const CStdStringW
& a_
;
4064 FmtArg
<CStdStringW
>& operator=(const FmtArg
<CStdStringW
>&) { return *this; }
4068 struct FmtArg
<std::string
>
4070 explicit FmtArg(const std::string
& arg
) : a_(arg
) {}
4071 PCSTR
operator()() const { return a_
.c_str(); }
4072 const std::string
& a_
;
4074 FmtArg
<std::string
>& operator=(const FmtArg
<std::string
>&) { return *this; }
4077 struct FmtArg
<std::wstring
>
4079 explicit FmtArg(const std::wstring
& arg
) : a_(arg
) {}
4080 PCWSTR
operator()() const { return a_
.c_str(); }
4081 const std::wstring
& a_
;
4083 FmtArg
<std::wstring
>& operator=(const FmtArg
<std::wstring
>&) {return *this;}
4085 #endif // #ifdef SS_SAFEFORMAT
4088 // SSResourceHandle: our MFC-like resource handle
4089 inline HMODULE
& SSResourceHandle()
4091 static HMODULE hModuleSS
= GetModuleHandle(0);
4097 // In MFC builds, define some global serialization operators
4098 // Special operators that allow us to serialize CStdStrings to CArchives.
4099 // Note that we use an intermediate CString object in order to ensure that
4100 // we use the exact same format.
4103 inline CArchive
& AFXAPI
operator<<(CArchive
& ar
, const CStdStringA
& strA
)
4105 CString strTemp
= strA
;
4106 return ar
<< strTemp
;
4108 inline CArchive
& AFXAPI
operator<<(CArchive
& ar
, const CStdStringW
& strW
)
4110 CString strTemp
= strW
;
4111 return ar
<< strTemp
;
4114 inline CArchive
& AFXAPI
operator>>(CArchive
& ar
, CStdStringA
& strA
)
4121 inline CArchive
& AFXAPI
operator>>(CArchive
& ar
, CStdStringW
& strW
)
4128 #endif // #ifdef _MFC_VER -- (i.e. is this MFC?)
4132 // -----------------------------------------------------------------------------
4133 // GLOBAL FUNCTION: WUFormat
4134 // CStdStringA WUFormat(UINT nId, ...);
4135 // CStdStringA WUFormat(PCSTR szFormat, ...);
4138 // This function allows the caller for format and return a CStdStringA
4139 // object with a single line of code.
4140 // -----------------------------------------------------------------------------
4143 inline CStdStringA
WUFormatA(UINT nId
, ...)
4146 va_start(argList
, nId
);
4150 if ( strFmt
.Load(nId
) )
4151 strOut
.FormatV(strFmt
, argList
);
4156 inline CStdStringA
WUFormatA(PCSTR szFormat
, ...)
4159 va_start(argList
, szFormat
);
4161 strOut
.FormatV(szFormat
, argList
);
4165 inline CStdStringW
WUFormatW(UINT nId
, ...)
4168 va_start(argList
, nId
);
4172 if ( strFmt
.Load(nId
) )
4173 strOut
.FormatV(strFmt
, argList
);
4178 inline CStdStringW
WUFormatW(PCWSTR szwFormat
, ...)
4181 va_start(argList
, szwFormat
);
4183 strOut
.FormatV(szwFormat
, argList
);
4187 #endif // #ifdef SS_ANSI
4191 #if defined(SS_WIN32) && !defined (SS_ANSI)
4192 // -------------------------------------------------------------------------
4193 // FUNCTION: WUSysMessage
4194 // CStdStringA WUSysMessageA(DWORD dwError, DWORD dwLangId=SS_DEFLANGID);
4195 // CStdStringW WUSysMessageW(DWORD dwError, DWORD dwLangId=SS_DEFLANGID);
4198 // This function simplifies the process of obtaining a string equivalent
4199 // of a system error code returned from GetLastError(). You simply
4200 // supply the value returned by GetLastError() to this function and the
4201 // corresponding system string is returned in the form of a CStdStringA.
4204 // dwError - a DWORD value representing the error code to be translated
4205 // dwLangId - the language id to use. defaults to english.
4208 // a CStdStringA equivalent of the error code. Currently, this function
4209 // only returns either English of the system default language strings.
4210 // -------------------------------------------------------------------------
4211 #define SS_DEFLANGID MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT)
4212 inline CStdStringA
WUSysMessageA(DWORD dwError
, DWORD dwLangId
=SS_DEFLANGID
)
4216 if ( 0 != ::FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM
, NULL
, dwError
,
4217 dwLangId
, szBuf
, 511, NULL
) )
4218 return WUFormatA("%s (0x%X)", szBuf
, dwError
);
4220 return WUFormatA("Unknown error (0x%X)", dwError
);
4222 inline CStdStringW
WUSysMessageW(DWORD dwError
, DWORD dwLangId
=SS_DEFLANGID
)
4226 if ( 0 != ::FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM
, NULL
, dwError
,
4227 dwLangId
, szBuf
, 511, NULL
) )
4228 return WUFormatW(L
"%s (0x%X)", szBuf
, dwError
);
4230 return WUFormatW(L
"Unknown error (0x%X)", dwError
);
4234 // Define TCHAR based friendly names for some of these functions
4237 //#define CStdString CStdStringW
4238 typedef CStdStringW CStdString
;
4239 #define WUSysMessage WUSysMessageW
4240 #define WUFormat WUFormatW
4242 //#define CStdString CStdStringA
4243 typedef CStdStringA CStdString
;
4244 #define WUSysMessage WUSysMessageA
4245 #define WUFormat WUFormatA
4248 // ...and some shorter names for the space-efficient
4250 #define WUSysMsg WUSysMessage
4251 #define WUSysMsgA WUSysMessageA
4252 #define WUSysMsgW WUSysMessageW
4253 #define WUFmtA WUFormatA
4254 #define WUFmtW WUFormatW
4255 #define WUFmt WUFormat
4256 #define WULastErrMsg() WUSysMessage(::GetLastError())
4257 #define WULastErrMsgA() WUSysMessageA(::GetLastError())
4258 #define WULastErrMsgW() WUSysMessageW(::GetLastError())
4261 // -----------------------------------------------------------------------------
4262 // FUNCTIONAL COMPARATORS:
4264 // These structs are derived from the std::binary_function template. They
4265 // give us functional classes (which may be used in Standard C++ Library
4266 // collections and algorithms) that perform case-insensitive comparisons of
4267 // CStdString objects. This is useful for maps in which the key may be the
4268 // proper string but in the wrong case.
4269 // -----------------------------------------------------------------------------
4270 #define StdStringLessNoCaseW SSLNCW // avoid VC compiler warning 4786
4271 #define StdStringEqualsNoCaseW SSENCW
4272 #define StdStringLessNoCaseA SSLNCA
4273 #define StdStringEqualsNoCaseA SSENCA
4276 #define StdStringLessNoCase SSLNCW
4277 #define StdStringEqualsNoCase SSENCW
4279 #define StdStringLessNoCase SSLNCA
4280 #define StdStringEqualsNoCase SSENCA
4283 struct StdStringLessNoCaseW
4284 : std::binary_function
<CStdStringW
, CStdStringW
, bool>
4287 bool operator()(const CStdStringW
& sLeft
, const CStdStringW
& sRight
) const
4288 { return ssicmp(sLeft
.c_str(), sRight
.c_str()) < 0; }
4290 struct StdStringEqualsNoCaseW
4291 : std::binary_function
<CStdStringW
, CStdStringW
, bool>
4294 bool operator()(const CStdStringW
& sLeft
, const CStdStringW
& sRight
) const
4295 { return ssicmp(sLeft
.c_str(), sRight
.c_str()) == 0; }
4297 struct StdStringLessNoCaseA
4298 : std::binary_function
<CStdStringA
, CStdStringA
, bool>
4301 bool operator()(const CStdStringA
& sLeft
, const CStdStringA
& sRight
) const
4302 { return ssicmp(sLeft
.c_str(), sRight
.c_str()) < 0; }
4304 struct StdStringEqualsNoCaseA
4305 : std::binary_function
<CStdStringA
, CStdStringA
, bool>
4308 bool operator()(const CStdStringA
& sLeft
, const CStdStringA
& sRight
) const
4309 { return ssicmp(sLeft
.c_str(), sRight
.c_str()) == 0; }
4312 // If we had to define our own version of TRACE above, get rid of it now
4314 #ifdef TRACE_DEFINED_HERE
4316 #undef TRACE_DEFINED_HERE
4320 // These std::swap specializations come courtesy of Mike Crusader.
4324 // inline void swap(CStdStringA& s1, CStdStringA& s2) throw()
4329 // inline void swap(CStdStringW& s1, CStdStringW& s2) throw()
4335 // Turn back on any Borland warnings we turned off.
4338 #pragma option pop // Turn back on inline function warnings
4339 // #pragma warn +inl // Turn back on inline function warnings
4342 typedef std::vector
<CStdString
> CStdStringArray
;
4344 #endif // #ifndef STDSTRING_H