1 // =============================================================================
\r
3 // AUTHOR: Joe O'Leary (with outside help noted in comments)
\r
5 // This header file declares the CStdStr template. This template derives
\r
6 // the Standard C++ Library basic_string<> template and add to it the
\r
7 // the following conveniences:
\r
8 // - The full MFC CString set of functions (including implicit cast)
\r
9 // - writing to/reading from COM IStream interfaces
\r
10 // - Functional objects for use in STL algorithms
\r
12 // From this template, we intstantiate two classes: CStdStringA and
\r
13 // CStdStringW. The name "CStdString" is just a #define of one of these,
\r
14 // based upone the _UNICODE macro setting
\r
16 // This header also declares our own version of the MFC/ATL UNICODE-MBCS
\r
17 // conversion macros. Our version looks exactly like the Microsoft's to
\r
18 // facilitate portability.
\r
21 // If you you use this in an MFC or ATL build, you should include either
\r
22 // afx.h or atlbase.h first, as appropriate.
\r
24 // PEOPLE WHO HAVE CONTRIBUTED TO THIS CLASS:
\r
26 // Several people have helped me iron out problems and othewise improve
\r
27 // this class. OK, this is a long list but in my own defense, this code
\r
28 // has undergone two major rewrites. Many of the improvements became
\r
29 // necessary after I rewrote the code as a template. Others helped me
\r
30 // improve the CString facade.
\r
32 // Anyway, these people are (in chronological order):
\r
34 // - Pete the Plumber (???)
\r
36 // - Chris (of Melbsys)
\r
42 // - Matthew Williams
\r
49 // - Baptiste Lepilleur
\r
54 // - Ullrich Pollähne
\r
57 // - Aaron (no last name)
\r
58 // - Joldakowski (???)
\r
62 // - Farrokh Nejadlotfi
\r
72 // - Bagira (full name?)
\r
74 // - Jakko Van Hunen
\r
78 // 2003-JUL-10 - Thanks to Charles G for making me realize my 'FmtArg' fixes
\r
79 // had inadvertently broken the DLL-export code (which is
\r
80 // normally commented out. I had to move it up higher. Also
\r
81 // this helped me catch a bug in ssicoll that would prevent
\r
82 // compilation, otherwise.
\r
84 // 2003-MAR-14 - Thanks to Jakko Van Hunen for pointing out a copy-and-paste
\r
85 // bug in one of the overloads of FmtArg.
\r
87 // 2003-MAR-10 - Thanks to Ronny Schulz for (twice!) sending me some changes
\r
88 // to help CStdString build on SGI and for pointing out an
\r
89 // error in placement of my preprocessor macros for ssfmtmsg.
\r
91 // 2002-NOV-26 - Thanks to Bagira for pointing out that my implementation of
\r
92 // SpanExcluding was not properly handling the case in which
\r
93 // the string did NOT contain any of the given characters
\r
95 // 2002-OCT-21 - Many thanks to Paul DeMarco who was invaluable in helping me
\r
96 // get this code working with Borland's free compiler as well
\r
97 // as the Dev-C++ compiler (available free at SourceForge).
\r
99 // 2002-SEP-13 - Thanks to Glen Maynard who helped me get rid of some loud
\r
100 // but harmless warnings that were showing up on g++. Glen
\r
101 // also pointed out that some pre-declarations of FmtArg<>
\r
102 // specializations were unnecessary (and no good on G++)
\r
104 // 2002-JUN-26 - Thanks to Arnt Witteveen for pointing out that I was using
\r
105 // static_cast<> in a place in which I should have been using
\r
106 // reinterpret_cast<> (the ctor for unsigned char strings).
\r
107 // That's what happens when I don't unit-test properly!
\r
108 // Arnt also noticed that CString was silently correcting the
\r
109 // 'nCount' argument to Left() and Right() where CStdString was
\r
110 // not (and crashing if it was bad). That is also now fixed!
\r
112 // 2002-FEB-25 - Thanks to Tim Dowty for pointing out (and giving me the fix
\r
113 // for) a conversion problem with non-ASCII MBCS characters.
\r
114 // CStdString is now used in my favorite commercial MP3 player!
\r
116 // 2001-DEC-06 - Thanks to Wang Haifeng for spotting a problem in one of the
\r
117 // assignment operators (for _bstr_t) that would cause compiler
\r
118 // errors when refcounting protection was turned off.
\r
120 // 2001-NOV-27 - Remove calls to operator!= which involve reverse_iterators
\r
121 // due to a conflict with the rel_ops operator!=. Thanks to
\r
122 // John James for pointing this out.
\r
124 // 2001-OCT-29 - Added a minor range checking fix for the Mid function to
\r
125 // make it as forgiving as CString's version is. Thanks to
\r
126 // Igor Kholodov for noticing this.
\r
127 // - Added a specialization of std::swap for CStdString. Thanks
\r
128 // to Mike Crusader for suggesting this! It's commented out
\r
129 // because you're not supposed to inject your own code into the
\r
130 // 'std' namespace. But if you don't care about that, it's
\r
131 // there if you want it
\r
132 // - Thanks to Jason Mills for catching a case where CString was
\r
133 // more forgiving in the Delete() function than I was.
\r
135 // 2001-JUN-06 - I was violating the Standard name lookup rules stated
\r
136 // in [14.6.2(3)]. None of the compilers I've tried so
\r
137 // far apparently caught this but HP-UX aCC 3.30 did. The
\r
138 // fix was to add 'this->' prefixes in many places.
\r
139 // Thanks to Farrokh Nejadlotfi for this!
\r
141 // 2001-APR-27 - StreamLoad was calculating the number of BYTES in one
\r
142 // case, not characters. Thanks to Pablo Presedo for this.
\r
144 // 2001-FEB-23 - Replace() had a bug which caused infinite loops if the
\r
145 // source string was empty. Fixed thanks to Eric Nitzsche.
\r
147 // 2001-FEB-23 - Scott Hathaway was a huge help in providing me with the
\r
148 // ability to build CStdString on Sun Unix systems. He
\r
149 // sent me detailed build reports about what works and what
\r
150 // does not. If CStdString compiles on your Unix box, you
\r
151 // can thank Scott for it.
\r
153 // 2000-DEC-29 - Joldakowski noticed one overload of Insert failed to do a
\r
154 // range check as CString's does. Now fixed -- thanks!
\r
156 // 2000-NOV-07 - Aaron pointed out that I was calling static member
\r
157 // functions of char_traits via a temporary. This was not
\r
158 // technically wrong, but it was unnecessary and caused
\r
159 // problems for poor old buggy VC5. Thanks Aaron!
\r
161 // 2000-JUL-11 - Joe Woodbury noted that the CString::Find docs don't match
\r
162 // what the CString::Find code really ends up doing. I was
\r
163 // trying to match the docs. Now I match the CString code
\r
164 // - Joe also caught me truncating strings for GetBuffer() calls
\r
165 // when the supplied length was less than the current length.
\r
167 // 2000-MAY-25 - Better support for STLPORT's Standard library distribution
\r
168 // - Got rid of the NSP macro - it interfered with Koenig lookup
\r
169 // - Thanks to Joe Woodbury for catching a TrimLeft() bug that
\r
170 // I introduced in January. Empty strings were not getting
\r
173 // 2000-APR-17 - Thanks to Joe Vitaterna for pointing out that ReverseFind
\r
174 // is supposed to be a const function.
\r
176 // 2000-MAR-07 - Thanks to Ullrich Pollähne for catching a range bug in one
\r
177 // of the overloads of assign.
\r
179 // 2000-FEB-01 - You can now use CStdString on the Mac with CodeWarrior!
\r
180 // Thanks to Todd Heckel for helping out with this.
\r
182 // 2000-JAN-23 - Thanks to Jim Cline for pointing out how I could make the
\r
183 // Trim() function more efficient.
\r
184 // - Thanks to Jeff Kohn for prompting me to find and fix a typo
\r
185 // in one of the addition operators that takes _bstr_t.
\r
186 // - Got rid of the .CPP file - you only need StdString.h now!
\r
188 // 1999-DEC-22 - Thanks to Greg Pickles for helping me identify a problem
\r
189 // with my implementation of CStdString::FormatV in which
\r
190 // resulting string might not be properly NULL terminated.
\r
192 // 1999-DEC-06 - Chris Conti pointed yet another basic_string<> assignment
\r
193 // bug that MS has not fixed. CStdString did nothing to fix
\r
194 // it either but it does now! The bug was: create a string
\r
195 // longer than 31 characters, get a pointer to it (via c_str())
\r
196 // and then assign that pointer to the original string object.
\r
197 // The resulting string would be empty. Not with CStdString!
\r
199 // 1999-OCT-06 - BufferSet was erasing the string even when it was merely
\r
200 // supposed to shrink it. Fixed. Thanks to Chris Conti.
\r
201 // - Some of the Q172398 fixes were not checking for assignment-
\r
202 // to-self. Fixed. Thanks to Baptiste Lepilleur.
\r
204 // 1999-AUG-20 - Improved Load() function to be more efficient by using
\r
205 // SizeOfResource(). Thanks to Rich Zuris for this.
\r
206 // - Corrected resource ID constructor, again thanks to Rich.
\r
207 // - Fixed a bug that occurred with UNICODE characters above
\r
208 // the first 255 ANSI ones. Thanks to Craig Watson.
\r
209 // - Added missing overloads of TrimLeft() and TrimRight().
\r
210 // Thanks to Karim Ratib for pointing them out
\r
212 // 1999-JUL-21 - Made all calls to GetBuf() with no args check length first.
\r
214 // 1999-JUL-10 - Improved MFC/ATL independence of conversion macros
\r
215 // - Added SS_NO_REFCOUNT macro to allow you to disable any
\r
216 // reference-counting your basic_string<> impl. may do.
\r
217 // - Improved ReleaseBuffer() to be as forgiving as CString.
\r
218 // Thanks for Fan Xia for helping me find this and to
\r
219 // Matthew Williams for pointing it out directly.
\r
221 // 1999-JUL-06 - Thanks to Nigel Nunn for catching a very sneaky bug in
\r
222 // ToLower/ToUpper. They should call GetBuf() instead of
\r
223 // data() in order to ensure the changed string buffer is not
\r
224 // reference-counted (in those implementations that refcount).
\r
226 // 1999-JUL-01 - Added a true CString facade. Now you can use CStdString as
\r
227 // a drop-in replacement for CString. If you find this useful,
\r
228 // you can thank Chris Sells for finally convincing me to give
\r
229 // in and implement it.
\r
230 // - Changed operators << and >> (for MFC CArchive) to serialize
\r
231 // EXACTLY as CString's do. So now you can send a CString out
\r
232 // to a CArchive and later read it in as a CStdString. I have
\r
233 // no idea why you would want to do this but you can.
\r
235 // 1999-JUN-21 - Changed the CStdString class into the CStdStr template.
\r
236 // - Fixed FormatV() to correctly decrement the loop counter.
\r
237 // This was harmless bug but a bug nevertheless. Thanks to
\r
238 // Chris (of Melbsys) for pointing it out
\r
239 // - Changed Format() to try a normal stack-based array before
\r
240 // using to _alloca().
\r
241 // - Updated the text conversion macros to properly use code
\r
242 // pages and to fit in better in MFC/ATL builds. In other
\r
243 // words, I copied Microsoft's conversion stuff again.
\r
244 // - Added equivalents of CString::GetBuffer, GetBufferSetLength
\r
245 // - new sscpy() replacement of CStdString::CopyString()
\r
246 // - a Trim() function that combines TrimRight() and TrimLeft().
\r
248 // 1999-MAR-13 - Corrected the "NotSpace" functional object to use _istpace()
\r
249 // instead of _isspace() Thanks to Dave Plummer for this.
\r
251 // 1999-FEB-26 - Removed errant line (left over from testing) that #defined
\r
252 // _MFC_VER. Thanks to John C Sipos for noticing this.
\r
254 // 1999-FEB-03 - Fixed a bug in a rarely-used overload of operator+() that
\r
255 // caused infinite recursion and stack overflow
\r
256 // - Added member functions to simplify the process of
\r
257 // persisting CStdStrings to/from DCOM IStream interfaces
\r
258 // - Added functional objects (e.g. StdStringLessNoCase) that
\r
259 // allow CStdStrings to be used as keys STL map objects with
\r
260 // case-insensitive comparison
\r
261 // - Added array indexing operators (i.e. operator[]). I
\r
262 // originally assumed that these were unnecessary and would be
\r
263 // inherited from basic_string. However, without them, Visual
\r
264 // C++ complains about ambiguous overloads when you try to use
\r
265 // them. Thanks to Julian Selman to pointing this out.
\r
267 // 1998-FEB-?? - Added overloads of assign() function to completely account
\r
268 // for Q172398 bug. Thanks to "Pete the Plumber" for this
\r
270 // 1998-FEB-?? - Initial submission
\r
273 // 2002 Joseph M. O'Leary. This code is 100% free. Use it anywhere you
\r
274 // want. Rewrite it, restructure it, whatever. If you can write software
\r
275 // that makes money off of it, good for you. I kinda like capitalism.
\r
276 // Please don't blame me if it causes your $30 billion dollar satellite
\r
277 // explode in orbit. If you redistribute it in any form, I'd appreciate it
\r
278 // if you would leave this notice here.
\r
280 // If you find any bugs, please let me know:
\r
282 // jmoleary@earthlink.net
\r
283 // http://www.joeo.net
\r
285 // The latest version of this code should always be available at the
\r
288 // http://www.joeo.net/code/StdString.zip
\r
289 // =============================================================================
\r
291 // Avoid multiple inclusion the VC++ way,
\r
292 // Turn off browser references
\r
293 // Turn off unavoidable compiler warnings
\r
295 #if defined(_MSC_VER) && (_MSC_VER > 1100)
\r
297 #pragma component(browser, off, references, "CStdString")
\r
298 #pragma warning (disable : 4290) // C++ Exception Specification ignored
\r
299 #pragma warning (disable : 4127) // Conditional expression is constant
\r
300 #pragma warning (disable : 4097) // typedef name used as synonym for class name
\r
303 // Borland warnings to turn off
\r
304 #ifdef __BORLANDC__
\r
305 #pragma option push -w-inl
\r
306 // #pragma warn -inl // Turn off inline function warnings
\r
309 #ifndef STDSTRING_H
\r
310 #define STDSTRING_H
\r
312 // MACRO: SS_UNSIGNED
\r
313 // ------------------
\r
314 // This macro causes the addition of a constructor and assignment operator
\r
315 // which take unsigned characters. CString has such functions and in order
\r
316 // to provide maximum CString-compatability, this code needs them as well.
\r
317 // In practice you will likely never need these functions...
\r
319 //#define SS_UNSIGNED
\r
321 #ifdef SS_ALLOW_UNSIGNED_CHARS
\r
322 #define SS_UNSIGNED
\r
325 // MACRO: SS_SAFE_FORMAT
\r
326 // ---------------------
\r
327 // This macro provides limited compatability with a questionable CString
\r
328 // "feature". You can define it in order to avoid a common problem that
\r
329 // people encounter when switching from CString to CStdString.
\r
331 // To illustrate the problem -- With CString, you can do this:
\r
333 // CString sName("Joe");
\r
335 // sTmp.Format("My name is %s", sName); // WORKS!
\r
337 // However if you were to try this with CStdString, your program would
\r
340 // CStdString sName("Joe");
\r
341 // CStdString sTmp;
\r
342 // sTmp.Format("My name is %s", sName); // CRASHES!
\r
344 // You must explicitly call c_str() or cast the object to the proper type
\r
346 // sTmp.Format("My name is %s", sName.c_str()); // WORKS!
\r
347 // sTmp.Format("My name is %s", static_cast<PCSTR>(sName));// WORKS!
\r
348 // sTmp.Format("My name is %s", (PCSTR)sName);// WORKS!
\r
350 // This is because it is illegal to pass anything but a POD type as a
\r
351 // variadic argument to a variadic function (i.e. as one of the "..."
\r
352 // arguments). The type const char* is a POD type. The type CStdString
\r
353 // is not. Of course, neither is the type CString, but CString lets you do
\r
354 // it anyway due to the way they laid out the class in binary. I have no
\r
355 // control over this in CStdString since I derive from whatever
\r
356 // implementation of basic_string is available.
\r
358 // However if you have legacy code (which does this) that you want to take
\r
359 // out of the MFC world and you don't want to rewrite all your calls to
\r
360 // Format(), then you can define this flag and it will no longer crash.
\r
362 // Note however that this ONLY works for Format(), not sprintf, fprintf,
\r
363 // etc. If you pass a CStdString object to one of those functions, your
\r
364 // program will crash. Not much I can do to get around this, short of
\r
365 // writing substitutes for those functions as well.
\r
367 #define SS_SAFE_FORMAT // use new template style Format() function
\r
370 // MACRO: SS_NO_IMPLICIT_CAST
\r
371 // --------------------------
\r
372 // Some people don't like the implicit cast to const char* (or rather to
\r
373 // const CT*) that CStdString (and MFC's CString) provide. That was the
\r
374 // whole reason I created this class in the first place, but hey, whatever
\r
375 // bakes your cake. Just #define this macro to get rid of the the implicit
\r
378 //#define SS_NO_IMPLICIT_CAST // gets rid of operator const CT*()
\r
381 // MACRO: SS_NO_REFCOUNT
\r
382 // ---------------------
\r
383 // turns off reference counting at the assignment level. Only needed
\r
384 // for the version of basic_string<> that comes with Visual C++ versions
\r
385 // 6.0 or earlier, and only then in some heavily multithreaded scenarios.
\r
386 // Uncomment it if you feel you need it.
\r
388 //#define SS_NO_REFCOUNT
\r
392 // When this flag is set, we are building code for the Win32 platform and
\r
393 // may use Win32 specific functions (such as LoadString). This gives us
\r
394 // a couple of nice extras for the code.
\r
396 // Obviously, Microsoft's is not the only compiler available for Win32 out
\r
397 // there. So I can't just check to see if _MSC_VER is defined to detect
\r
398 // if I'm building on Win32. So for now, if you use MS Visual C++ or
\r
399 // Borland's compiler, I turn this on. Otherwise you may turn it on
\r
400 // yourself, if you prefer
\r
401 #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(_WIN32)
\r
407 // When this macro is defined, the code attempts only to use ANSI/ISO
\r
408 // standard library functions to do it's work. It will NOT attempt to use
\r
409 // any Win32 of Visual C++ specific functions -- even if they are
\r
410 // available. You may define this flag yourself to prevent any Win32
\r
411 // of VC++ specific functions from being called.
\r
413 // If we're not on Win32, we MUST use an ANSI build
\r
415 #if !defined(SS_NO_ANSI)
\r
420 // MACRO: SS_ALLOCA
\r
421 // ----------------
\r
422 // Some implementations of the Standard C Library have a non-standard
\r
423 // function known as alloca(). This functions allows one to allocate a
\r
424 // variable amount of memory on the stack. It comes in very useful for
\r
425 // the ASCII/MBCS conversion macros.
\r
427 // Here we attempt to determine automatically if alloca() is available on
\r
428 // this platform. If so we define SS_ALLOCA to be the name of the alloca
\r
429 // function. If SS_ALLOCA is undefined later on, then the conversion
\r
430 // macros will not be compiled.
\r
432 // You may prevent SS_ALLOCA
\r
436 // Avoid legacy code screw up: if _UNICODE is defined, UNICODE must be as well
\r
438 #if defined (_UNICODE) && !defined (UNICODE)
\r
441 #if defined (UNICODE) && !defined (_UNICODE)
\r
445 // -----------------------------------------------------------------------------
\r
446 // MIN and MAX. The Standard C++ template versions go by so many names (at
\r
447 // at least in the MS implementation) that you never know what's available
\r
448 // -----------------------------------------------------------------------------
\r
449 template<class Type>
\r
450 inline const Type& SSMIN(const Type& arg1, const Type& arg2)
\r
452 return arg2 < arg1 ? arg2 : arg1;
\r
454 template<class Type>
\r
455 inline const Type& SSMAX(const Type& arg1, const Type& arg2)
\r
457 return arg2 > arg1 ? arg2 : arg1;
\r
460 // If they have not #included W32Base.h (part of my W32 utility library) then
\r
461 // we need to define some stuff. Otherwise, this is all defined there.
\r
463 #if !defined(W32BASE_H)
\r
465 // If they want us to use only standard C++ stuff (no Win32 stuff)
\r
469 // On Win32 we have TCHAR.H so just include it. This is NOT violating
\r
470 // the spirit of SS_ANSI as we are not calling any Win32 functions here.
\r
475 #include <WTYPES.H>
\r
480 // ... but on non-Win32 platforms, we must #define the types we need.
\r
484 typedef const char* PCSTR;
\r
485 typedef char* PSTR;
\r
486 typedef const wchar_t* PCWSTR;
\r
487 typedef wchar_t* PWSTR;
\r
489 typedef wchar_t TCHAR;
\r
491 typedef char TCHAR;
\r
493 typedef wchar_t OLECHAR;
\r
495 #endif // #ifndef _WIN32
\r
498 // Make sure ASSERT and verify are defined using only ANSI stuff
\r
501 #include <assert.h>
\r
502 #define ASSERT(f) assert((f))
\r
506 #define VERIFY(x) ASSERT((x))
\r
508 #define VERIFY(x) x
\r
512 #else // ...else SS_ANSI is NOT defined
\r
515 #include <WTYPES.H>
\r
520 // Make sure ASSERT and verify are defined
\r
523 #include <crtdbg.h>
\r
524 #define ASSERT(f) _ASSERTE((f))
\r
528 #define VERIFY(x) ASSERT((x))
\r
530 #define VERIFY(x) x
\r
534 #endif // #ifdef SS_ANSI
\r
537 #define UNUSED(x) x
\r
540 #endif // #ifndef W32BASE_H
\r
542 // Standard headers needed
\r
544 #include <string> // basic_string
\r
545 #include <algorithm> // for_each, etc.
\r
546 #include <functional> // for StdStringLessNoCase, et al
\r
547 #include <locale> // for various facets
\r
549 // If this is a recent enough version of VC include comdef.h, so we can write
\r
550 // member functions to deal with COM types & compiler support classes e.g. _bstr_t
\r
552 #if defined (_MSC_VER) && (_MSC_VER >= 1100)
\r
553 #include <comdef.h>
\r
554 #define SS_INC_COMDEF // signal that we #included MS comdef.h file
\r
555 #define STDSTRING_INC_COMDEF
\r
556 #define SS_NOTHROW __declspec(nothrow)
\r
562 #define TRACE_DEFINED_HERE
\r
566 // Microsoft defines PCSTR, PCWSTR, etc, but no PCTSTR. I hate to use the
\r
567 // versions with the "L" in front of them because that's a leftover from Win 16
\r
568 // days, even though it evaluates to the same thing. Therefore, Define a PCSTR
\r
571 #if !defined(PCTSTR) && !defined(PCTSTR_DEFINED)
\r
572 typedef const TCHAR* PCTSTR;
\r
573 #define PCTSTR_DEFINED
\r
576 #if !defined(PCOLESTR) && !defined(PCOLESTR_DEFINED)
\r
577 typedef const OLECHAR* PCOLESTR;
\r
578 #define PCOLESTR_DEFINED
\r
581 #if !defined(POLESTR) && !defined(POLESTR_DEFINED)
\r
582 typedef OLECHAR* POLESTR;
\r
583 #define POLESTR_DEFINED
\r
586 #if !defined(PCUSTR) && !defined(PCUSTR_DEFINED)
\r
587 typedef const unsigned char* PCUSTR;
\r
588 typedef unsigned char* PUSTR;
\r
589 #define PCUSTR_DEFINED
\r
593 // SGI compiler 7.3 doesnt know these types - oh and btw, remember to use
\r
594 // -LANG:std in the CXX Flags
\r
596 typedef unsigned long DWORD;
\r
597 typedef void * LPCVOID;
\r
601 // SS_USE_FACET macro and why we need it:
\r
603 // Since I'm a good little Standard C++ programmer, I use locales. Thus, I
\r
604 // need to make use of the use_facet<> template function here. Unfortunately,
\r
605 // this need is complicated by the fact the MS' implementation of the Standard
\r
606 // C++ Library has a non-standard version of use_facet that takes more
\r
607 // arguments than the standard dictates. Since I'm trying to write CStdString
\r
608 // to work with any version of the Standard library, this presents a problem.
\r
610 // The upshot of this is that I can't do 'use_facet' directly. The MS' docs
\r
611 // tell me that I have to use a macro, _USE() instead. Since _USE obviously
\r
612 // won't be available in other implementations, this means that I have to write
\r
613 // my OWN macro -- SS_USE_FACET -- that evaluates either to _USE or to the
\r
614 // standard, use_facet.
\r
616 // If you are having trouble with the SS_USE_FACET macro, in your implementation
\r
617 // of the Standard C++ Library, you can define your own version of SS_USE_FACET.
\r
619 #define schSTR(x) #x
\r
620 #define schSTR2(x) schSTR(x)
\r
621 #define schMSG(desc) message(__FILE__ "(" schSTR2(__LINE__) "):" #desc)
\r
624 #ifndef SS_USE_FACET
\r
625 // STLPort #defines a macro (__STL_NO_EXPLICIT_FUNCTION_TMPL_ARGS) for
\r
626 // all MSVC builds, erroneously in my opinion. It causes problems for
\r
627 // my SS_ANSI builds. In my code, I always comment out that line. You'll
\r
628 // find it in \stlport\config\stl_msvc.h
\r
629 #if defined(__SGI_STL_PORT) && (__SGI_STL_PORT >= 0x400 )
\r
630 #if defined(__STL_NO_EXPLICIT_FUNCTION_TMPL_ARGS) && defined(_MSC_VER)
\r
632 #pragma schMSG(__STL_NO_EXPLICIT_FUNCTION_TMPL_ARGS defined!!)
\r
635 #define SS_USE_FACET(loc, fac) std::use_facet<fac >(loc)
\r
636 #elif defined(_MSC_VER )
\r
637 #define SS_USE_FACET(loc, fac) std::_USE(loc, fac)
\r
640 #elif defined(_RWSTD_NO_TEMPLATE_ON_RETURN_TYPE)
\r
641 #define SS_USE_FACET(loc, fac) std::use_facet(loc, (fac*)0)
\r
643 #define SS_USE_FACET(loc, fac) std::use_facet<fac >(loc)
\r
647 // =============================================================================
\r
648 // UNICODE/MBCS conversion macros. Made to work just like the MFC/ATL ones.
\r
649 // =============================================================================
\r
651 #include <wchar.h> // Added to Std Library with Amendment #1.
\r
653 // First define the conversion helper functions. We define these regardless of
\r
654 // any preprocessor macro settings since their names won't collide.
\r
656 // Not sure if we need all these headers. I believe ANSI says we do.
\r
659 #include <stdarg.h>
\r
660 #include <wctype.h>
\r
662 #include <stdlib.h>
\r
664 #include <varargs.h>
\r
667 // StdCodeCvt - made to look like Win32 functions WideCharToMultiByte
\r
668 // and MultiByteToWideChar but uses locales in SS_ANSI
\r
670 //typedef int mbstate_t;
\r
671 #if defined (SS_ANSI) || !defined (SS_WIN32)
\r
673 typedef std::codecvt<wchar_t, char, std::mbstate_t> SSCodeCvt;
\r
676 inline PWSTR StdCodeCvt(PWSTR pW, PCSTR pA, int nChars,
\r
677 const std::locale& loc=std::locale())
\r
684 SSCodeCvt::result res = SSCodeCvt::ok;
\r
685 const SSCodeCvt& conv = SS_USE_FACET(loc, SSCodeCvt);
\r
686 SSCodeCvt::state_type st= { 0 };
\r
688 pA, pA + nChars, pBadA,
\r
689 pW, pW + nChars, pBadW);
\r
690 ASSERT(SSCodeCvt::ok == res);
\r
693 inline PWSTR StdCodeCvt(PWSTR pW, PCUSTR pA, int nChars,
\r
694 const std::locale& loc=std::locale())
\r
696 return StdCodeCvt(pW, (PCSTR)pA, nChars, loc);
\r
699 inline PSTR StdCodeCvt(PSTR pA, PCWSTR pW, int nChars,
\r
700 const std::locale& loc=std::locale())
\r
707 SSCodeCvt::result res = SSCodeCvt::ok;
\r
708 const SSCodeCvt& conv = SS_USE_FACET(loc, SSCodeCvt);
\r
709 SSCodeCvt::state_type st= { 0 };
\r
711 pW, pW + nChars, pBadW,
\r
712 pA, pA + nChars, pBadA);
\r
713 ASSERT(SSCodeCvt::ok == res);
\r
716 inline PUSTR StdCodeCvt(PUSTR pA, PCWSTR pW, int nChars,
\r
717 const std::locale& loc=std::locale())
\r
719 return (PUSTR)StdCodeCvt((PSTR)pA, pW, nChars, loc);
\r
722 #else // ...or are we doing things assuming win32 and Visual C++?
\r
724 #include <malloc.h> // needed for _alloca
\r
726 inline PWSTR StdCodeCvt(PWSTR pW, PCSTR pA, int nChars, UINT acp=CP_ACP)
\r
731 MultiByteToWideChar(acp, 0, pA, -1, pW, nChars);
\r
734 inline PWSTR StdCodeCvt(PWSTR pW, PCUSTR pA, int nChars, UINT acp=CP_ACP)
\r
736 return StdCodeCvt(pW, (PCSTR)pA, nChars, acp);
\r
739 inline PSTR StdCodeCvt(PSTR pA, PCWSTR pW, int nChars, UINT acp=CP_ACP)
\r
744 WideCharToMultiByte(acp, 0, pW, -1, pA, nChars, 0, 0);
\r
747 inline PUSTR StdCodeCvt(PUSTR pA, PCWSTR pW, int nChars, UINT acp=CP_ACP)
\r
749 return (PUSTR)StdCodeCvt((PSTR)pA, pW, nChars, acp);
\r
753 // Unicode/MBCS conversion macros are only available on implementations of
\r
754 // the "C" library that have the non-standard _alloca function. As far as I
\r
755 // know that's only Microsoft's though I've hear that the function exits
\r
758 #if defined(SS_ALLOCA) && !defined SS_NO_CONVERSION
\r
760 #include <malloc.h> // needed for _alloca
\r
763 // Define our conversion macros to look exactly like Microsoft's to
\r
764 // facilitate using this stuff both with and without MFC/ATL
\r
766 #ifdef _CONVERSION_USES_THREAD_LOCALE
\r
768 #define SSCVT int _cvt; _cvt; UINT _acp=GetACP(); \
\r
769 _acp; PCWSTR _pw; _pw; PCSTR _pa; _pa
\r
771 #define SSCVT int _cvt = 0; _cvt; UINT _acp=GetACP();\
\r
772 _acp; PCWSTR _pw=0; _pw; PCSTR _pa=0; _pa
\r
776 #define SSCVT int _cvt; _cvt; UINT _acp=CP_ACP; _acp;\
\r
777 PCWSTR _pw; _pw; PCSTR _pa; _pa
\r
779 #define SSCVT int _cvt = 0; _cvt; UINT _acp=CP_ACP; \
\r
780 _acp; PCWSTR _pw=0; _pw; PCSTR _pa=0; _pa
\r
784 #ifdef _CONVERSION_USES_THREAD_LOCALE
\r
785 #define SSA2W(pa) (\
\r
786 ((_pa = pa) == 0) ? 0 : (\
\r
787 _cvt = (sslen(_pa)+1),\
\r
788 StdCodeCvt((PWSTR) _alloca(_cvt*2), _pa, _cvt, _acp)))
\r
789 #define SSW2A(pw) (\
\r
790 ((_pw = pw) == 0) ? 0 : (\
\r
791 _cvt = (sslen(_pw)+1)*2,\
\r
792 StdW2AHelper((LPSTR) _alloca(_cvt), _pw, _cvt, _acp)))
\r
794 #define SSA2W(pa) (\
\r
795 ((_pa = pa) == 0) ? 0 : (\
\r
796 _cvt = (sslen(_pa)+1),\
\r
797 StdCodeCvt((PWSTR) _alloca(_cvt*2), _pa, _cvt)))
\r
798 #define SSW2A(pw) (\
\r
799 ((_pw = pw) == 0) ? 0 : (\
\r
800 _cvt = (sslen(_pw)+1)*2,\
\r
801 StdCodeCvt((LPSTR) _alloca(_cvt), _pw, _cvt)))
\r
804 #define SSA2CW(pa) ((PCWSTR)SSA2W((pa)))
\r
805 #define SSW2CA(pw) ((PCSTR)SSW2A((pw)))
\r
808 #define SST2A SSW2A
\r
809 #define SSA2T SSA2W
\r
810 #define SST2CA SSW2CA
\r
811 #define SSA2CT SSA2CW
\r
812 inline PWSTR SST2W(PTSTR p) { return p; }
\r
813 inline PTSTR SSW2T(PWSTR p) { return p; }
\r
814 inline PCWSTR SST2CW(PCTSTR p) { return p; }
\r
815 inline PCTSTR SSW2CT(PCWSTR p) { return p; }
\r
817 #define SST2W SSA2W
\r
818 #define SSW2T SSW2A
\r
819 #define SST2CW SSA2CW
\r
820 #define SSW2CT SSW2CA
\r
821 inline PSTR SST2A(PTSTR p) { return p; }
\r
822 inline PTSTR SSA2T(PSTR p) { return p; }
\r
823 inline PCSTR SST2CA(PCTSTR p) { return p; }
\r
824 inline PCTSTR SSA2CT(PCSTR p) { return p; }
\r
825 #endif // #ifdef UNICODE
\r
827 #if defined(UNICODE)
\r
828 // in these cases the default (TCHAR) is the same as OLECHAR
\r
829 inline PCOLESTR SST2COLE(PCTSTR p) { return p; }
\r
830 inline PCTSTR SSOLE2CT(PCOLESTR p) { return p; }
\r
831 inline POLESTR SST2OLE(PTSTR p) { return p; }
\r
832 inline PTSTR SSOLE2T(POLESTR p) { return p; }
\r
833 #elif defined(OLE2ANSI)
\r
834 // in these cases the default (TCHAR) is the same as OLECHAR
\r
835 inline PCOLESTR SST2COLE(PCTSTR p) { return p; }
\r
836 inline PCTSTR SSOLE2CT(PCOLESTR p) { return p; }
\r
837 inline POLESTR SST2OLE(PTSTR p) { return p; }
\r
838 inline PTSTR SSOLE2T(POLESTR p) { return p; }
\r
840 //CharNextW doesn't work on Win95 so we use this
\r
841 #define SST2COLE(pa) SSA2CW((pa))
\r
842 #define SST2OLE(pa) SSA2W((pa))
\r
843 #define SSOLE2CT(po) SSW2CA((po))
\r
844 #define SSOLE2T(po) SSW2A((po))
\r
848 #define SSW2OLE SSW2A
\r
849 #define SSOLE2W SSA2W
\r
850 #define SSW2COLE SSW2CA
\r
851 #define SSOLE2CW SSA2CW
\r
852 inline POLESTR SSA2OLE(PSTR p) { return p; }
\r
853 inline PSTR SSOLE2A(POLESTR p) { return p; }
\r
854 inline PCOLESTR SSA2COLE(PCSTR p) { return p; }
\r
855 inline PCSTR SSOLE2CA(PCOLESTR p){ return p; }
\r
857 #define SSA2OLE SSA2W
\r
858 #define SSOLE2A SSW2A
\r
859 #define SSA2COLE SSA2CW
\r
860 #define SSOLE2CA SSW2CA
\r
861 inline POLESTR SSW2OLE(PWSTR p) { return p; }
\r
862 inline PWSTR SSOLE2W(POLESTR p) { return p; }
\r
863 inline PCOLESTR SSW2COLE(PCWSTR p) { return p; }
\r
864 inline PCWSTR SSOLE2CW(PCOLESTR p){ return p; }
\r
867 // Above we've defined macros that look like MS' but all have
\r
868 // an 'SS' prefix. Now we need the real macros. We'll either
\r
869 // get them from the macros above or from MFC/ATL.
\r
871 #if defined (USES_CONVERSION)
\r
873 #define _NO_STDCONVERSION // just to be consistent
\r
879 #include <afxconv.h>
\r
880 #define _NO_STDCONVERSION // just to be consistent
\r
884 #define USES_CONVERSION SSCVT
\r
885 #define A2CW SSA2CW
\r
886 #define W2CA SSW2CA
\r
891 #define T2CA SST2CA
\r
892 #define A2CT SSA2CT
\r
893 #define T2CW SST2CW
\r
894 #define W2CT SSW2CT
\r
895 #define ocslen sslen
\r
896 #define ocscpy sscpy
\r
897 #define T2COLE SST2COLE
\r
898 #define OLE2CT SSOLE2CT
\r
899 #define T2OLE SST2COLE
\r
900 #define OLE2T SSOLE2CT
\r
901 #define A2OLE SSA2OLE
\r
902 #define OLE2A SSOLE2A
\r
903 #define W2OLE SSW2OLE
\r
904 #define OLE2W SSOLE2W
\r
905 #define A2COLE SSA2COLE
\r
906 #define OLE2CA SSOLE2CA
\r
907 #define W2COLE SSW2COLE
\r
908 #define OLE2CW SSOLE2CW
\r
910 #endif // #ifdef _MFC_VER
\r
911 #endif // #ifndef USES_CONVERSION
\r
912 #endif // #ifndef SS_NO_CONVERSION
\r
914 // Define ostring - generic name for std::basic_string<OLECHAR>
\r
916 #if !defined(ostring) && !defined(OSTRING_DEFINED)
\r
917 typedef std::basic_string<OLECHAR> ostring;
\r
918 #define OSTRING_DEFINED
\r
921 // StdCodeCvt when there's no conversion to be done
\r
922 inline PSTR StdCodeCvt(PSTR pDst, PCSTR pSrc, int nChars)
\r
927 std::basic_string<char>::traits_type::copy(pDst, pSrc, nChars);
\r
928 // std::char_traits<char>::copy(pDst, pSrc, nChars);
\r
930 pDst[nChars] = '\0';
\r
935 inline PSTR StdCodeCvt(PSTR pDst, PCUSTR pSrc, int nChars)
\r
937 return StdCodeCvt(pDst, (PCSTR)pSrc, nChars);
\r
939 inline PUSTR StdCodeCvt(PUSTR pDst, PCSTR pSrc, int nChars)
\r
941 return (PUSTR)StdCodeCvt((PSTR)pDst, pSrc, nChars);
\r
944 inline PWSTR StdCodeCvt(PWSTR pDst, PCWSTR pSrc, int nChars)
\r
949 std::basic_string<wchar_t>::traits_type::copy(pDst, pSrc, nChars);
\r
950 // std::char_traits<wchar_t>::copy(pDst, pSrc, nChars);
\r
952 pDst[nChars] = '\0';
\r
959 // Define tstring -- generic name for std::basic_string<TCHAR>
\r
961 #if !defined(tstring) && !defined(TSTRING_DEFINED)
\r
962 typedef std::basic_string<TCHAR> tstring;
\r
963 #define TSTRING_DEFINED
\r
966 // a very shorthand way of applying the fix for KB problem Q172398
\r
967 // (basic_string assignment bug)
\r
969 #if defined ( _MSC_VER ) && ( _MSC_VER < 1200 )
\r
970 #define Q172398(x) (x).erase()
\r
975 // =============================================================================
\r
976 // INLINE FUNCTIONS ON WHICH CSTDSTRING RELIES
\r
978 // Usually for generic text mapping, we rely on preprocessor macro definitions
\r
979 // to map to string functions. However the CStdStr<> template cannot use
\r
980 // macro-based generic text mappings because its character types do not get
\r
981 // resolved until template processing which comes AFTER macro processing. In
\r
982 // other words, UNICODE is of little help to us in the CStdStr template
\r
984 // Therefore, to keep the CStdStr declaration simple, we have these inline
\r
985 // functions. The template calls them often. Since they are inline (and NOT
\r
986 // exported when this is built as a DLL), they will probably be resolved away
\r
989 // Without these functions, the CStdStr<> template would probably have to broken
\r
990 // out into two, almost identical classes. Either that or it would be a huge,
\r
991 // convoluted mess, with tons of "if" statements all over the place checking the
\r
992 // size of template parameter CT.
\r
994 // In several cases, you will see two versions of each function. One version is
\r
995 // the more portable, standard way of doing things, while the other is the
\r
996 // non-standard, but often significantly faster Visual C++ way.
\r
997 // =============================================================================
\r
999 // If they defined SS_NO_REFCOUNT, then we must convert all assignments
\r
1001 #ifdef SS_NO_REFCOUNT
\r
1002 #define SSREF(x) (x).c_str()
\r
1004 #define SSREF(x) (x)
\r
1007 // -----------------------------------------------------------------------------
\r
1008 // sslen: strlen/wcslen wrappers
\r
1009 // -----------------------------------------------------------------------------
\r
1010 template<typename CT> inline int sslen(const CT* pT)
\r
1012 return 0 == pT ? 0 : std::basic_string<CT>::traits_type::length(pT);
\r
1013 // return 0 == pT ? 0 : std::char_traits<CT>::length(pT);
\r
1015 inline SS_NOTHROW int sslen(const std::string& s)
\r
1017 return s.length();
\r
1019 inline SS_NOTHROW int sslen(const std::wstring& s)
\r
1021 return s.length();
\r
1024 // -----------------------------------------------------------------------------
\r
1025 // sstolower/sstoupper -- convert characters to upper/lower case
\r
1026 // -----------------------------------------------------------------------------
\r
1027 template<typename CT>
\r
1028 inline CT sstolower(const CT& t, const std::locale& loc = std::locale())
\r
1030 return std::tolower<CT>(t, loc);
\r
1032 template<typename CT>
\r
1033 inline CT sstoupper(const CT& t, const std::locale& loc = std::locale())
\r
1035 return std::toupper<CT>(t, loc);
\r
1038 // -----------------------------------------------------------------------------
\r
1039 // ssasn: assignment functions -- assign "sSrc" to "sDst"
\r
1040 // -----------------------------------------------------------------------------
\r
1041 typedef std::string::size_type SS_SIZETYPE; // just for shorthand, really
\r
1042 typedef std::string::pointer SS_PTRTYPE;
\r
1043 typedef std::wstring::size_type SW_SIZETYPE;
\r
1044 typedef std::wstring::pointer SW_PTRTYPE;
\r
1046 inline void ssasn(std::string& sDst, const std::string& sSrc)
\r
1048 if ( sDst.c_str() != sSrc.c_str() )
\r
1051 sDst.assign(SSREF(sSrc));
\r
1054 inline void ssasn(std::string& sDst, PCSTR pA)
\r
1056 // Watch out for NULLs, as always.
\r
1063 // If pA actually points to part of sDst, we must NOT erase(), but
\r
1064 // rather take a substring
\r
1066 else if ( pA >= sDst.c_str() && pA <= sDst.c_str() + sDst.size() )
\r
1068 sDst =sDst.substr(static_cast<SS_SIZETYPE>(pA-sDst.c_str()));
\r
1071 // Otherwise (most cases) apply the assignment bug fix, if applicable
\r
1072 // and do the assignment
\r
1080 inline void ssasn(std::string& sDst, const std::wstring& sSrc)
\r
1082 int nLen = sSrc.size();
\r
1083 sDst.resize(nLen * sizeof(wchar_t) + 1);
\r
1084 StdCodeCvt(const_cast<SS_PTRTYPE>(sDst.data()), sSrc.c_str(), nLen);
\r
1085 sDst.resize(nLen);
\r
1086 //sDst.resize(sslen(sDst.c_str()));
\r
1088 inline void ssasn(std::string& sDst, PCWSTR pW)
\r
1090 int nLen = sslen(pW);
\r
1091 sDst.resize(nLen * sizeof(wchar_t) + 1);
\r
1092 StdCodeCvt(const_cast<SS_PTRTYPE>(sDst.data()), pW, nLen);
\r
1093 sDst.resize(nLen);
\r
1094 //sDst.resize(sslen(sDst.c_str()));
\r
1096 inline void ssasn(std::string& sDst, const int nNull)
\r
1102 inline void ssasn(std::wstring& sDst, const std::wstring& sSrc)
\r
1104 if ( sDst.c_str() != sSrc.c_str() )
\r
1107 sDst.assign(SSREF(sSrc));
\r
1110 inline void ssasn(std::wstring& sDst, PCWSTR pW)
\r
1112 // Watch out for NULLs, as always.
\r
1119 // If pW actually points to part of sDst, we must NOT erase(), but
\r
1120 // rather take a substring
\r
1122 else if ( pW >= sDst.c_str() && pW <= sDst.c_str() + sDst.size() )
\r
1124 sDst = sDst.substr(static_cast<SW_SIZETYPE>(pW-sDst.c_str()));
\r
1127 // Otherwise (most cases) apply the assignment bug fix, if applicable
\r
1128 // and do the assignment
\r
1136 #undef StrSizeType
\r
1137 inline void ssasn(std::wstring& sDst, const std::string& sSrc)
\r
1139 int nLen = sSrc.size();
\r
1140 sDst.resize(nLen+1);
\r
1141 StdCodeCvt(const_cast<SW_PTRTYPE>(sDst.data()), sSrc.c_str(), nLen+1);
\r
1142 sDst.resize(sslen(sDst.c_str()));
\r
1144 inline void ssasn(std::wstring& sDst, PCSTR pA)
\r
1146 int nLen = sslen(pA);
\r
1147 sDst.resize(nLen+1);
\r
1148 StdCodeCvt(const_cast<SW_PTRTYPE>(sDst.data()), pA, nLen+1);
\r
1149 sDst.resize(sslen(sDst.c_str()));
\r
1151 inline void ssasn(std::wstring& sDst, const int nNull)
\r
1159 // -----------------------------------------------------------------------------
\r
1160 // ssadd: string object concatenation -- add second argument to first
\r
1161 // -----------------------------------------------------------------------------
\r
1162 inline void ssadd(std::string& sDst, const std::wstring& sSrc)
\r
1164 int nSrcLen = sSrc.size();
\r
1165 int nDstLen = sDst.size();
\r
1166 int nEndLen = nSrcLen + nDstLen;
\r
1167 sDst.resize(nEndLen + 1);
\r
1168 StdCodeCvt(const_cast<SS_PTRTYPE>(sDst.data()+nDstLen), sSrc.c_str(), nSrcLen);
\r
1169 sDst.resize(nEndLen);
\r
1171 inline void ssadd(std::string& sDst, const std::string& sSrc)
\r
1173 if ( &sDst == &sSrc )
\r
1174 sDst.reserve(2*sDst.size());
\r
1176 sDst.append(sSrc.c_str());
\r
1178 inline void ssadd(std::string& sDst, PCWSTR pW)
\r
1180 int nSrcLen = sslen(pW);
\r
1181 int nDstLen = sDst.size();
\r
1182 int nEndLen = nSrcLen + nDstLen;
\r
1183 sDst.resize(nEndLen + 1);
\r
1184 StdCodeCvt(const_cast<SS_PTRTYPE>(sDst.data()+nDstLen), pW, nSrcLen+1);
\r
1185 sDst.resize(nEndLen);
\r
1187 inline void ssadd(std::string& sDst, PCSTR pA)
\r
1191 // If the string being added is our internal string or a part of our
\r
1192 // internal string, then we must NOT do any reallocation without
\r
1193 // first copying that string to another object (since we're using a
\r
1194 // direct pointer)
\r
1196 if ( pA >= sDst.c_str() && pA <= sDst.c_str()+sDst.length())
\r
1198 if ( sDst.capacity() <= sDst.size()+sslen(pA) )
\r
1199 sDst.append(std::string(pA));
\r
1209 inline void ssadd(std::wstring& sDst, const std::wstring& sSrc)
\r
1211 if ( &sDst == &sSrc )
\r
1212 sDst.reserve(2*sDst.size());
\r
1214 sDst.append(sSrc.c_str());
\r
1216 inline void ssadd(std::wstring& sDst, const std::string& sSrc)
\r
1218 int nSrcLen = sSrc.size();
\r
1219 int nDstLen = sDst.size();
\r
1220 int nEndLen = nSrcLen + nDstLen;
\r
1221 sDst.resize(nEndLen+1);
\r
1222 StdCodeCvt(const_cast<SW_PTRTYPE>(sDst.data()+nDstLen), sSrc.c_str(), nSrcLen+1);
\r
1223 sDst.resize(nEndLen);
\r
1225 inline void ssadd(std::wstring& sDst, PCSTR pA)
\r
1227 int nSrcLen = sslen(pA);
\r
1228 int nDstLen = sDst.size();
\r
1229 int nEndLen = nSrcLen + nDstLen;
\r
1230 sDst.resize(nEndLen + 1);
\r
1231 StdCodeCvt(const_cast<SW_PTRTYPE>(sDst.data()+nDstLen), pA, nSrcLen+1);
\r
1232 sDst.resize(nEndLen);
\r
1234 inline void ssadd(std::wstring& sDst, PCWSTR pW)
\r
1238 // If the string being added is our internal string or a part of our
\r
1239 // internal string, then we must NOT do any reallocation without
\r
1240 // first copying that string to another object (since we're using a
\r
1241 // direct pointer)
\r
1243 if ( pW >= sDst.c_str() && pW <= sDst.c_str()+sDst.length())
\r
1245 if ( sDst.capacity() <= sDst.size()+sslen(pW) )
\r
1246 sDst.append(std::wstring(pW));
\r
1258 // -----------------------------------------------------------------------------
\r
1259 // ssicmp: comparison (case insensitive )
\r
1260 // -----------------------------------------------------------------------------
\r
1261 template<typename CT>
\r
1262 inline int ssicmp(const CT* pA1, const CT* pA2)
\r
1265 const std::ctype<CT>& ct = SS_USE_FACET(loc, std::ctype<CT>);
\r
1271 f = ct.tolower(*(pA1++));
\r
1272 l = ct.tolower(*(pA2++));
\r
1273 } while ( (f) && (f == l) );
\r
1275 return (int)(f - l);
\r
1278 // -----------------------------------------------------------------------------
\r
1279 // ssupr/sslwr: Uppercase/Lowercase conversion functions
\r
1280 // -----------------------------------------------------------------------------
\r
1282 template<typename CT>
\r
1283 inline void sslwr(CT* pT, size_t nLen)
\r
1285 SS_USE_FACET(std::locale(), std::ctype<CT>).tolower(pT, pT+nLen);
\r
1287 template<typename CT>
\r
1288 inline void ssupr(CT* pT, size_t nLen)
\r
1290 SS_USE_FACET(std::locale(), std::ctype<CT>).toupper(pT, pT+nLen);
\r
1294 // -----------------------------------------------------------------------------
\r
1295 // vsprintf/vswprintf or _vsnprintf/_vsnwprintf equivalents. In standard
\r
1296 // builds we can't use _vsnprintf/_vsnwsprintf because they're MS extensions.
\r
1297 // -----------------------------------------------------------------------------
\r
1298 #if defined(SS_ANSI) || !defined(_MSC_VER)
\r
1300 // Borland's headers put some ANSI "C" functions in the 'std' namespace.
\r
1301 // Promote them to the global namespace so we can use them here.
\r
1303 #if defined(__BORLANDC__)
\r
1304 using std::vsprintf;
\r
1305 using std::vswprintf;
\r
1307 inline int ssvsprintf(PSTR pA, size_t /*nCount*/, PCSTR pFmtA, va_list vl)
\r
1309 return vsprintf(pA, pFmtA, vl);
\r
1311 inline int ssvsprintf(PWSTR pW, size_t nCount, PCWSTR pFmtW, va_list vl)
\r
1313 // JMO: Some distributions of the "C" have a version of vswprintf that
\r
1314 // takes 3 arguments (e.g. Microsoft, Borland, GNU). Others have a
\r
1315 // version which takes 4 arguments (an extra "count" argument in the
\r
1316 // second position. The best stab I can take at this so far is that if
\r
1317 // you are NOT running with MS, Borland, or GNU, then I'll assume you
\r
1318 // have the version that takes 4 arguments.
\r
1320 // I'm sure that these checks don't catch every platform correctly so if
\r
1321 // you get compiler errors on one of the lines immediately below, it's
\r
1322 // probably because your implemntation takes a different number of
\r
1323 // arguments. You can comment out the offending line (and use the
\r
1324 // alternate version) or you can figure out what compiler flag to check
\r
1325 // and add that preprocessor check in. Regardless, if you get an error
\r
1326 // on these lines, I'd sure like to hear from you about it.
\r
1328 // Thanks to Ronny Schulz for the SGI-specific checks here.
\r
1330 // #if !defined(__MWERKS__) && !defined(__SUNPRO_CC_COMPAT) && !defined(__SUNPRO_CC)
\r
1331 #if !defined(_MSC_VER) \
\r
1332 && !defined (__BORLANDC__) \
\r
1333 && !defined(__GNUC__) \
\r
1334 && !defined(__sgi)
\r
1336 return vswprintf(pW, nCount, pFmtW, vl);
\r
1338 // suddenly with the current SGI 7.3 compiler there is no such function as
\r
1339 // vswprintf and the substitute needs explicit casts to compile
\r
1341 #elif defined(__sgi)
\r
1344 return vsprintf( (char *)pW, (char *)pFmtW, vl);
\r
1349 return vswprintf(pW, pFmtW, vl);
\r
1355 inline int ssnprintf(PSTR pA, size_t nCount, PCSTR pFmtA, va_list vl)
\r
1357 return _vsnprintf(pA, nCount, pFmtA, vl);
\r
1359 inline int ssnprintf(PWSTR pW, size_t nCount, PCWSTR pFmtW, va_list vl)
\r
1361 return _vsnwprintf(pW, nCount, pFmtW, vl);
\r
1367 // -----------------------------------------------------------------------------
\r
1368 // ssload: Type safe, overloaded ::LoadString wrappers
\r
1369 // There is no equivalent of these in non-Win32-specific builds. However, I'm
\r
1370 // thinking that with the message facet, there might eventually be one
\r
1371 // -----------------------------------------------------------------------------
\r
1372 #if defined (SS_WIN32) && !defined(SS_ANSI)
\r
1373 inline int ssload(HMODULE hInst, UINT uId, PSTR pBuf, int nMax)
\r
1375 return ::LoadStringA(hInst, uId, pBuf, nMax);
\r
1377 inline int ssload(HMODULE hInst, UINT uId, PWSTR pBuf, int nMax)
\r
1379 return ::LoadStringW(hInst, uId, pBuf, nMax);
\r
1384 // -----------------------------------------------------------------------------
\r
1385 // sscoll/ssicoll: Collation wrappers
\r
1386 // Note -- with MSVC I have reversed the arguments order here because the
\r
1387 // functions appear to return the opposite of what they should
\r
1388 // -----------------------------------------------------------------------------
\r
1389 template <typename CT>
\r
1390 inline int sscoll(const CT* sz1, int nLen1, const CT* sz2, int nLen2)
\r
1392 const std::collate<CT>& coll =
\r
1393 SS_USE_FACET(std::locale(), std::collate<CT>);
\r
1395 return coll.compare(sz2, sz2+nLen2, sz1, sz1+nLen1);
\r
1397 template <typename CT>
\r
1398 inline int ssicoll(const CT* sz1, int nLen1, const CT* sz2, int nLen2)
\r
1400 const std::locale loc;
\r
1401 const std::collate<CT>& coll = SS_USE_FACET(loc, std::collate<CT>);
\r
1403 // Some implementations seem to have trouble using the collate<>
\r
1404 // facet typedefs so we'll just default to basic_string and hope
\r
1405 // that's what the collate facet uses (which it generally should)
\r
1407 // std::collate<CT>::string_type s1(sz1);
\r
1408 // std::collate<CT>::string_type s2(sz2);
\r
1409 const std::basic_string<CT> sEmpty;
\r
1410 std::basic_string<CT> s1(sz1 ? sz1 : sEmpty.c_str());
\r
1411 std::basic_string<CT> s2(sz2 ? sz2 : sEmpty.c_str());
\r
1413 sslwr(const_cast<CT*>(s1.c_str()), nLen1);
\r
1414 sslwr(const_cast<CT*>(s2.c_str()), nLen2);
\r
1415 return coll.compare(s2.c_str(), s2.c_str()+nLen2,
\r
1416 s1.c_str(), s1.c_str()+nLen1);
\r
1420 // -----------------------------------------------------------------------------
\r
1421 // ssfmtmsg: FormatMessage equivalents. Needed because I added a CString facade
\r
1422 // Again -- no equivalent of these on non-Win32 builds but their might one day
\r
1423 // be one if the message facet gets implemented
\r
1424 // -----------------------------------------------------------------------------
\r
1425 #if defined (SS_WIN32) && !defined(SS_ANSI)
\r
1426 inline DWORD ssfmtmsg(DWORD dwFlags, LPCVOID pSrc, DWORD dwMsgId,
\r
1427 DWORD dwLangId, PSTR pBuf, DWORD nSize,
\r
1430 return FormatMessageA(dwFlags, pSrc, dwMsgId, dwLangId,
\r
1431 pBuf, nSize,vlArgs);
\r
1433 inline DWORD ssfmtmsg(DWORD dwFlags, LPCVOID pSrc, DWORD dwMsgId,
\r
1434 DWORD dwLangId, PWSTR pBuf, DWORD nSize,
\r
1437 return FormatMessageW(dwFlags, pSrc, dwMsgId, dwLangId,
\r
1438 pBuf, nSize,vlArgs);
\r
1445 // FUNCTION: sscpy. Copies up to 'nMax' characters from pSrc to pDst.
\r
1446 // -----------------------------------------------------------------------------
\r
1447 // FUNCTION: sscpy
\r
1448 // inline int sscpy(PSTR pDst, PCSTR pSrc, int nMax=-1);
\r
1449 // inline int sscpy(PUSTR pDst, PCSTR pSrc, int nMax=-1)
\r
1450 // inline int sscpy(PSTR pDst, PCWSTR pSrc, int nMax=-1);
\r
1451 // inline int sscpy(PWSTR pDst, PCWSTR pSrc, int nMax=-1);
\r
1452 // inline int sscpy(PWSTR pDst, PCSTR pSrc, int nMax=-1);
\r
1455 // This function is very much (but not exactly) like strcpy. These
\r
1456 // overloads simplify copying one C-style string into another by allowing
\r
1457 // the caller to specify two different types of strings if necessary.
\r
1459 // The strings must NOT overlap
\r
1461 // "Character" is expressed in terms of the destination string, not
\r
1462 // the source. If no 'nMax' argument is supplied, then the number of
\r
1463 // characters copied will be sslen(pSrc). A NULL terminator will
\r
1464 // also be added so pDst must actually be big enough to hold nMax+1
\r
1465 // characters. The return value is the number of characters copied,
\r
1466 // not including the NULL terminator.
\r
1469 // pSrc - the string to be copied FROM. May be a char based string, an
\r
1470 // MBCS string (in Win32 builds) or a wide string (wchar_t).
\r
1471 // pSrc - the string to be copied TO. Also may be either MBCS or wide
\r
1472 // nMax - the maximum number of characters to be copied into szDest. Note
\r
1473 // that this is expressed in whatever a "character" means to pDst.
\r
1474 // If pDst is a wchar_t type string than this will be the maximum
\r
1475 // number of wchar_ts that my be copied. The pDst string must be
\r
1476 // large enough to hold least nMaxChars+1 characters.
\r
1477 // If the caller supplies no argument for nMax this is a signal to
\r
1478 // the routine to copy all the characters in pSrc, regardless of
\r
1479 // how long it is.
\r
1481 // RETURN VALUE: none
\r
1482 // -----------------------------------------------------------------------------
\r
1483 template<typename CT1, typename CT2>
\r
1484 inline int sscpycvt(CT1* pDst, const CT2* pSrc, int nChars)
\r
1486 StdCodeCvt(pDst, pSrc, nChars);
\r
1487 pDst[SSMAX(nChars, 0)] = '\0';
\r
1491 template<typename CT1, typename CT2>
\r
1492 inline int sscpy(CT1* pDst, const CT2* pSrc, int nMax, int nLen)
\r
1494 return sscpycvt(pDst, pSrc, SSMIN(nMax, nLen));
\r
1496 template<typename CT1, typename CT2>
\r
1497 inline int sscpy(CT1* pDst, const CT2* pSrc, int nMax)
\r
1499 return sscpycvt(pDst, pSrc, SSMIN(nMax, sslen(pSrc)));
\r
1501 template<typename CT1, typename CT2>
\r
1502 inline int sscpy(CT1* pDst, const CT2* pSrc)
\r
1504 return sscpycvt(pDst, pSrc, sslen(pSrc));
\r
1506 template<typename CT1, typename CT2>
\r
1507 inline int sscpy(CT1* pDst, const std::basic_string<CT2>& sSrc, int nMax)
\r
1509 return sscpycvt(pDst, sSrc.c_str(), SSMIN(nMax, (int)sSrc.length()));
\r
1511 template<typename CT1, typename CT2>
\r
1512 inline int sscpy(CT1* pDst, const std::basic_string<CT2>& sSrc)
\r
1514 return sscpycvt(pDst, sSrc.c_str(), (int)sSrc.length());
\r
1517 #ifdef SS_INC_COMDEF
\r
1518 template<typename CT1>
\r
1519 inline int sscpy(CT1* pDst, const _bstr_t& bs, int nMax)
\r
1521 return sscpycvt(pDst, static_cast<PCOLESTR>(bs),
\r
1522 SSMIN(nMax, static_cast<int>(bs.length())));
\r
1524 template<typename CT1>
\r
1525 inline int sscpy(CT1* pDst, const _bstr_t& bs)
\r
1527 return sscpy(pDst, bs, static_cast<int>(bs.length()));
\r
1532 // -----------------------------------------------------------------------------
\r
1533 // Functional objects for changing case. They also let you pass locales
\r
1534 // -----------------------------------------------------------------------------
\r
1537 template<typename CT>
\r
1538 struct SSToUpper : public std::binary_function<CT, std::locale, CT>
\r
1540 inline CT operator()(const CT& t, const std::locale& loc) const
\r
1542 return sstoupper<CT>(t, loc);
\r
1545 template<typename CT>
\r
1546 struct SSToLower : public std::binary_function<CT, std::locale, CT>
\r
1548 inline CT operator()(const CT& t, const std::locale& loc) const
\r
1550 return sstolower<CT>(t, loc);
\r
1555 // This struct is used for TrimRight() and TrimLeft() function implementations.
\r
1556 //template<typename CT>
\r
1557 //struct NotSpace : public std::unary_function<CT, bool>
\r
1559 // const std::locale& loc;
\r
1560 // inline NotSpace(const std::locale& locArg) : loc(locArg) {}
\r
1561 // inline bool operator() (CT t) { return !std::isspace(t, loc); }
\r
1563 template<typename CT>
\r
1564 struct NotSpace : public std::unary_function<CT, bool>
\r
1567 // DINKUMWARE BUG:
\r
1568 // Note -- using std::isspace in a COM DLL gives us access violations
\r
1569 // because it causes the dynamic addition of a function to be called
\r
1570 // when the library shuts down. Unfortunately the list is maintained
\r
1571 // in DLL memory but the function is in static memory. So the COM DLL
\r
1572 // goes away along with the function that was supposed to be called,
\r
1573 // and then later when the DLL CRT shuts down it unloads the list and
\r
1574 // tries to call the long-gone function.
\r
1575 // This is DinkumWare's implementation problem. Until then, we will
\r
1576 // use good old isspace and iswspace from the CRT unless they
\r
1577 // specify SS_ANSI
\r
1579 const std::locale loc;
\r
1580 NotSpace(const std::locale& locArg=std::locale()) : loc(locArg) {}
\r
1581 bool operator() (CT t) const { return !std::isspace(t, loc); }
\r
1587 // Now we can define the template (finally!)
\r
1588 // =============================================================================
\r
1589 // TEMPLATE: CStdStr
\r
1590 // template<typename CT> class CStdStr : public std::basic_string<CT>
\r
1593 // This template derives from basic_string<CT> and adds some MFC CString-
\r
1594 // like functionality
\r
1596 // Basically, this is my attempt to make Standard C++ library strings as
\r
1597 // easy to use as the MFC CString class.
\r
1599 // Note that although this is a template, it makes the assumption that the
\r
1600 // template argument (CT, the character type) is either char or wchar_t.
\r
1601 // =============================================================================
\r
1603 //#define CStdStr _SS // avoid compiler warning 4786
\r
1605 // template<typename ARG> ARG& FmtArg(ARG& arg) { return arg; }
\r
1606 // PCSTR FmtArg(const std::string& arg) { return arg.c_str(); }
\r
1607 // PCWSTR FmtArg(const std::wstring& arg) { return arg.c_str(); }
\r
1609 template<typename ARG>
\r
1612 explicit FmtArg(const ARG& arg) : a_(arg) {}
\r
1613 const ARG& Val() const { return a_; }
\r
1616 FmtArg& operator=(const FmtArg&) { return *this; }
\r
1619 template<typename CT>
\r
1620 class CStdStr : public std::basic_string<CT>
\r
1622 // Typedefs for shorter names. Using these names also appears to help
\r
1623 // us avoid some ambiguities that otherwise arise on some platforms
\r
1625 typedef typename std::basic_string<CT> MYBASE; // my base class
\r
1626 typedef CStdStr<CT> MYTYPE; // myself
\r
1627 typedef typename MYBASE::const_pointer PCMYSTR; // PCSTR or PCWSTR
\r
1628 typedef typename MYBASE::pointer PMYSTR; // PSTR or PWSTR
\r
1629 typedef typename MYBASE::iterator MYITER; // my iterator type
\r
1630 typedef typename MYBASE::const_iterator MYCITER; // you get the idea...
\r
1631 typedef typename MYBASE::reverse_iterator MYRITER;
\r
1632 typedef typename MYBASE::size_type MYSIZE;
\r
1633 typedef typename MYBASE::value_type MYVAL;
\r
1634 typedef typename MYBASE::allocator_type MYALLOC;
\r
1638 // shorthand conversion from PCTSTR to string resource ID
\r
1639 #define _TRES(pctstr) (LOWORD((DWORD)(pctstr)))
\r
1641 // CStdStr inline constructors
\r
1646 CStdStr(const MYTYPE& str) : MYBASE(SSREF(str))
\r
1650 CStdStr(const std::string& str)
\r
1652 ssasn(*this, SSREF(str));
\r
1655 CStdStr(const std::wstring& str)
\r
1657 ssasn(*this, SSREF(str));
\r
1660 CStdStr(PCMYSTR pT, MYSIZE n) : MYBASE(pT, n)
\r
1664 #ifdef SS_UNSIGNED
\r
1665 CStdStr(PCUSTR pU)
\r
1667 *this = reinterpret_cast<PCSTR>(pU);
\r
1676 if ( 0 != HIWORD(pA) )
\r
1678 else if ( 0 != pA && !Load(_TRES(pA)) )
\r
1679 TRACE(_T("Can't load string %u\n"), _TRES(pA));
\r
1683 CStdStr(PCWSTR pW)
\r
1688 if ( 0 != HIWORD(pW) )
\r
1690 else if ( 0 != pW && !Load(_TRES(pW)) )
\r
1691 TRACE(_T("Can't load string %u\n"), _TRES(pW));
\r
1695 CStdStr(MYCITER first, MYCITER last)
\r
1696 : MYBASE(first, last)
\r
1700 CStdStr(MYSIZE nSize, MYVAL ch, const MYALLOC& al=MYALLOC())
\r
1701 : MYBASE(nSize, ch, al)
\r
1705 #ifdef SS_INC_COMDEF
\r
1706 CStdStr(const _bstr_t& bstr)
\r
1708 if ( bstr.length() > 0 )
\r
1709 this->append(static_cast<PCMYSTR>(bstr), bstr.length());
\r
1713 // CStdStr inline assignment operators -- the ssasn function now takes care
\r
1714 // of fixing the MSVC assignment bug (see knowledge base article Q172398).
\r
1715 MYTYPE& operator=(const MYTYPE& str)
\r
1717 ssasn(*this, str);
\r
1721 MYTYPE& operator=(const std::string& str)
\r
1723 ssasn(*this, str);
\r
1727 MYTYPE& operator=(const std::wstring& str)
\r
1729 ssasn(*this, str);
\r
1733 MYTYPE& operator=(PCSTR pA)
\r
1739 MYTYPE& operator=(PCWSTR pW)
\r
1745 #ifdef SS_UNSIGNED
\r
1746 MYTYPE& operator=(PCUSTR pU)
\r
1748 ssasn(*this, reinterpret_cast<PCSTR>(pU)):
\r
1753 MYTYPE& operator=(CT t)
\r
1756 this->assign(1, t);
\r
1760 #ifdef SS_INC_COMDEF
\r
1761 MYTYPE& operator=(const _bstr_t& bstr)
\r
1763 if ( bstr.length() > 0 )
\r
1765 this->assign(static_cast<PCMYSTR>(bstr), bstr.length());
\r
1777 // Overloads also needed to fix the MSVC assignment bug (KB: Q172398)
\r
1778 // *** Thanks to Pete The Plumber for catching this one ***
\r
1779 // They also are compiled if you have explicitly turned off refcounting
\r
1780 #if ( defined(_MSC_VER) && ( _MSC_VER < 1200 ) ) || defined(SS_NO_REFCOUNT)
\r
1782 MYTYPE& assign(const MYTYPE& str)
\r
1784 ssasn(*this, str);
\r
1788 MYTYPE& assign(const MYTYPE& str, MYSIZE nStart, MYSIZE nChars)
\r
1790 // This overload of basic_string::assign is supposed to assign up to
\r
1791 // <nChars> or the NULL terminator, whichever comes first. Since we
\r
1792 // are about to call a less forgiving overload (in which <nChars>
\r
1793 // must be a valid length), we must adjust the length here to a safe
\r
1794 // value. Thanks to Ullrich Pollähne for catching this bug
\r
1796 nChars = SSMIN(nChars, str.length() - nStart);
\r
1798 // Watch out for assignment to self
\r
1800 if ( this == &str )
\r
1802 MYTYPE strTemp(str.c_str()+nStart, nChars);
\r
1803 MYBASE::assign(strTemp);
\r
1808 MYBASE::assign(str.c_str()+nStart, nChars);
\r
1813 MYTYPE& assign(const MYBASE& str)
\r
1815 ssasn(*this, str);
\r
1819 MYTYPE& assign(const MYBASE& str, MYSIZE nStart, MYSIZE nChars)
\r
1821 // This overload of basic_string::assign is supposed to assign up to
\r
1822 // <nChars> or the NULL terminator, whichever comes first. Since we
\r
1823 // are about to call a less forgiving overload (in which <nChars>
\r
1824 // must be a valid length), we must adjust the length here to a safe
\r
1825 // value. Thanks to Ullrich Pollähne for catching this bug
\r
1827 nChars = SSMIN(nChars, str.length() - nStart);
\r
1829 // Watch out for assignment to self
\r
1831 if ( this == &str ) // watch out for assignment to self
\r
1833 MYTYPE strTemp(str.c_str() + nStart, nChars);
\r
1834 MYBASE::assign(strTemp);
\r
1839 MYBASE::assign(str.c_str()+nStart, nChars);
\r
1844 MYTYPE& assign(const CT* pC, MYSIZE nChars)
\r
1846 // Q172398 only fix -- erase before assigning, but not if we're
\r
1847 // assigning from our own buffer
\r
1849 #if defined ( _MSC_VER ) && ( _MSC_VER < 1200 )
\r
1850 if ( !this->empty() &&
\r
1851 ( pC < this->data() || pC > this->data() + this->capacity() ) )
\r
1857 MYBASE::assign(pC, nChars);
\r
1861 MYTYPE& assign(MYSIZE nChars, MYVAL val)
\r
1864 MYBASE::assign(nChars, val);
\r
1868 MYTYPE& assign(const CT* pT)
\r
1870 return this->assign(pT, MYBASE::traits_type::length(pT));
\r
1873 MYTYPE& assign(MYCITER iterFirst, MYCITER iterLast)
\r
1875 #if defined ( _MSC_VER ) && ( _MSC_VER < 1200 )
\r
1876 // Q172398 fix. don't call erase() if we're assigning from ourself
\r
1877 if ( iterFirst < this->begin() ||
\r
1878 iterFirst > this->begin() + this->size() )
\r
1883 this->replace(this->begin(), this->end(), iterFirst, iterLast);
\r
1889 // -------------------------------------------------------------------------
\r
1890 // CStdStr inline concatenation.
\r
1891 // -------------------------------------------------------------------------
\r
1892 MYTYPE& operator+=(const MYTYPE& str)
\r
1894 ssadd(*this, str);
\r
1898 MYTYPE& operator+=(const std::string& str)
\r
1900 ssadd(*this, str);
\r
1904 MYTYPE& operator+=(const std::wstring& str)
\r
1906 ssadd(*this, str);
\r
1910 MYTYPE& operator+=(PCSTR pA)
\r
1916 MYTYPE& operator+=(PCWSTR pW)
\r
1922 MYTYPE& operator+=(CT t)
\r
1924 this->append(1, t);
\r
1927 #ifdef SS_INC_COMDEF // if we have _bstr_t, define a += for it too.
\r
1928 MYTYPE& operator+=(const _bstr_t& bstr)
\r
1930 return this->operator+=(static_cast<PCMYSTR>(bstr));
\r
1935 // -------------------------------------------------------------------------
\r
1936 // Case changing functions
\r
1937 // -------------------------------------------------------------------------
\r
1941 // Strictly speaking, this would be about the most portable way
\r
1943 // std::transform(begin(),
\r
1946 // std::bind2nd(SSToUpper<CT>(), std::locale()));
\r
1948 // But practically speaking, this works faster
\r
1951 ssupr(GetBuf(), this->size());
\r
1960 // Strictly speaking, this would be about the most portable way
\r
1962 // std::transform(begin(),
\r
1965 // std::bind2nd(SSToLower<CT>(), std::locale()));
\r
1967 // But practically speaking, this works faster
\r
1970 sslwr(GetBuf(), this->size());
\r
1977 MYTYPE& Normalize()
\r
1979 return Trim().ToLower();
\r
1983 // -------------------------------------------------------------------------
\r
1984 // CStdStr -- Direct access to character buffer. In the MS' implementation,
\r
1985 // the at() function that we use here also calls _Freeze() providing us some
\r
1986 // protection from multithreading problems associated with ref-counting.
\r
1987 // In VC 7 and later, of course, the ref-counting stuff is gone.
\r
1988 // -------------------------------------------------------------------------
\r
1990 CT* GetBuf(int nMinLen=-1)
\r
1992 if ( static_cast<int>(size()) < nMinLen )
\r
1993 this->resize(static_cast<MYSIZE>(nMinLen));
\r
1995 return this->empty() ? const_cast<CT*>(this->data()) : &(this->at(0));
\r
1998 CT* SetBuf(int nLen)
\r
2000 nLen = ( nLen > 0 ? nLen : 0 );
\r
2001 if ( this->capacity() < 1 && nLen == 0 )
\r
2004 this->resize(static_cast<MYSIZE>(nLen));
\r
2005 return const_cast<CT*>(this->data());
\r
2007 void RelBuf(int nNewLen=-1)
\r
2009 this->resize(static_cast<MYSIZE>(nNewLen > -1 ? nNewLen :
\r
2010 sslen(this->c_str())));
\r
2013 void BufferRel() { RelBuf(); } // backwards compatability
\r
2014 CT* Buffer() { return GetBuf(); } // backwards compatability
\r
2015 CT* BufferSet(int nLen) { return SetBuf(nLen);}// backwards compatability
\r
2017 bool Equals(const CT* pT, bool bUseCase=false) const
\r
2018 { // get copy, THEN compare (thread safe)
\r
2019 return bUseCase ? this->compare(pT) == 0 :
\r
2020 ssicmp(MYTYPE(*this).c_str(), pT) == 0;
\r
2023 // -------------------------------------------------------------------------
\r
2024 // FUNCTION: CStdStr::Load
\r
2026 // Loads string from resource specified by nID
\r
2029 // nID - resource Identifier. Purely a Win32 thing in this case
\r
2032 // true if successful, false otherwise
\r
2033 // -------------------------------------------------------------------------
\r
2037 bool Load(UINT nId, HMODULE hModule=NULL)
\r
2039 bool bLoaded = false; // set to true of we succeed.
\r
2041 #ifdef _MFC_VER // When in Rome (or MFC land)...
\r
2044 bLoaded = FALSE != strRes.LoadString(nId);
\r
2048 #else // otherwise make our own hackneyed version of CString's Load
\r
2050 // Get the resource name and module handle
\r
2052 if ( NULL == hModule )
\r
2053 hModule = GetResourceHandle();
\r
2055 PCTSTR szName = MAKEINTRESOURCE((nId>>4)+1); // lifted
\r
2058 // No sense continuing if we can't find the resource
\r
2060 HRSRC hrsrc = ::FindResource(hModule, szName, RT_STRING);
\r
2062 if ( NULL == hrsrc )
\r
2064 TRACE(_T("Cannot find resource %d: 0x%X"), nId, ::GetLastError());
\r
2066 else if ( 0 == (dwSize = ::SizeofResource(hModule, hrsrc) / sizeof(CT)))
\r
2068 TRACE(_T("Cant get size of resource %d 0x%X\n"),nId,GetLastError());
\r
2072 bLoaded = 0 != ssload(hModule, nId, GetBuf(dwSize), dwSize);
\r
2076 #endif // #ifdef _MFC_VER
\r
2079 TRACE(_T("String not loaded 0x%X\n"), ::GetLastError());
\r
2084 #endif // #ifdef SS_ANSI
\r
2086 // -------------------------------------------------------------------------
\r
2087 // FUNCTION: CStdStr::Format
\r
2088 // void _cdecl Formst(CStdStringA& PCSTR szFormat, ...)
\r
2089 // void _cdecl Format(PCSTR szFormat);
\r
2092 // This function does sprintf/wsprintf style formatting on CStdStringA
\r
2093 // objects. It looks a lot like MFC's CString::Format. Some people
\r
2094 // might even call this identical. Fortunately, these people are now
\r
2095 // dead... heh heh.
\r
2098 // nId - ID of string resource holding the format string
\r
2099 // szFormat - a PCSTR holding the format specifiers
\r
2100 // argList - a va_list holding the arguments for the format specifiers.
\r
2102 // RETURN VALUE: None.
\r
2103 // -------------------------------------------------------------------------
\r
2104 // formatting (using wsprintf style formatting)
\r
2106 // If they want a Format() function that safely handles string objects
\r
2107 // without casting
\r
2109 #ifdef SS_SAFE_FORMAT
\r
2111 // Question: Joe, you wacky coder you, why do you have so many overloads
\r
2112 // of the Format() function
\r
2113 // Answer: One reason only - CString compatability. In short, by making
\r
2114 // the Format() function a template this way, I can do strong typing
\r
2115 // and allow people to pass CStdString arguments as fillers for
\r
2116 // "%s" format specifiers without crashing their program! The downside
\r
2117 // is that I need to overload on the number of arguments. If you are
\r
2118 // passing more arguments than I have listed below in any of my
\r
2119 // overloads, just add another one.
\r
2121 // Yes, yes, this is really ugly. In essence what I am doing here is
\r
2122 // protecting people from a bad (and incorrect) programming practice
\r
2123 // that they should not be doing anyway. I am protecting them from
\r
2124 // themselves. Why am I doing this? Well, if you had any idea the
\r
2125 // number of times I've been emailed by people about this
\r
2126 // "incompatability" in my code, you wouldn't ask.
\r
2128 void Fmt(const CT* szFmt, ...)
\r
2131 va_start(argList, szFmt);
\r
2132 FormatV(szFmt, argList);
\r
2138 void Format(UINT nId)
\r
2141 if ( strFmt.Load(nId) )
\r
2142 this->swap(strFmt);
\r
2144 template<class A1>
\r
2145 void Format(UINT nId, const A1& v)
\r
2148 if ( strFmt.Load(nId) )
\r
2149 Fmt(strFmt, FmtArg<A1>(v).Val());
\r
2151 template<class A1, class A2>
\r
2152 void Format(UINT nId, const A1& v1, const A2& v2)
\r
2155 if ( strFmt.Load(nId) )
\r
2156 Fmt(strFmt, FmtArg<A1>(v1).Val(), FmtArg<A2>(v2).Val());
\r
2158 template<class A1, class A2, class A3>
\r
2159 void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3)
\r
2162 if ( strFmt.Load(nId) )
\r
2164 Fmt(strFmt, FmtArg<A1>(v1).Val(), FmtArg<A2>(v2).Val(),
\r
2165 FmtArg<A3>(v3).Val());
\r
2168 template<class A1, class A2, class A3, class A4>
\r
2169 void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,
\r
2173 if ( strFmt.Load(nId) )
\r
2175 Fmt(strFmt, FmtArg<A1>(v1).Val(), FmtArg<A2>(v2).Val(),
\r
2176 FmtArg<A3>(v3).Val(), FmtArg<A4>(v4).Val());
\r
2179 template<class A1, class A2, class A3, class A4, class A5>
\r
2180 void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,
\r
2181 const A4& v4, const A5& v5)
\r
2184 if ( strFmt.Load(nId) )
\r
2186 Fmt(strFmt, FmtArg<A1>(v1).Val(), FmtArg<A2>(v2).Val(),
\r
2187 FmtArg<A3>(v3).Val(), FmtArg<A4>(v4).Val(), FmtArg<A5>(v5).Val());
\r
2190 template<class A1, class A2, class A3, class A4, class A5, class A6>
\r
2191 void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,
\r
2192 const A4& v4, const A5& v5, const A6& v6)
\r
2195 if ( strFmt.Load(nId) )
\r
2197 Fmt(strFmt, FmtArg<A1>(v1).Val(), FmtArg<A2>(v2).Val(),
\r
2198 FmtArg<A3>(v3).Val(), FmtArg<A4>(v4).Val(),FmtArg<A5>(v5).Val(),
\r
2199 FmtArg<A6>(v6).Val());
\r
2202 template<class A1, class A2, class A3, class A4, class A5, class A6,
\r
2204 void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,
\r
2205 const A4& v4, const A5& v5, const A6& v6, const A7& v7)
\r
2208 if ( strFmt.Load(nId) )
\r
2210 Fmt(strFmt, FmtArg<A1>(v1).Val(), FmtArg<A2>(v2).Val(),
\r
2211 FmtArg<A3>(v3).Val(), FmtArg<A4>(v4).Val(),FmtArg<A5>(v5).Val(),
\r
2212 FmtArg<A6>(v6).Val(), FmtArg<A7>(v7).Val());
\r
2215 template<class A1, class A2, class A3, class A4, class A5, class A6,
\r
2216 class A7, class A8>
\r
2217 void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,
\r
2218 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
\r
2222 if ( strFmt.Load(nId) )
\r
2224 Fmt(strFmt, FmtArg<A1>(v1).Val(), FmtArg<A2>(v2).Val(),
\r
2225 FmtArg<A3>(v3).Val(), FmtArg<A4>(v4).Val(), FmtArg<A5>(v5).Val(),
\r
2226 FmtArg<A6>(v6).Val(), FmtArg<A7>(v7).Val(), FmtArg<A8>(v8).Val());
\r
2229 template<class A1, class A2, class A3, class A4, class A5, class A6,
\r
2230 class A7, class A8, class A9>
\r
2231 void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,
\r
2232 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
\r
2233 const A8& v8, const A9& v9)
\r
2236 if ( strFmt.Load(nId) )
\r
2238 Fmt(strFmt, FmtArg<A1>(v1).Val(), FmtArg<A2>(v2).Val(),
\r
2239 FmtArg<A3>(v3).Val(), FmtArg<A4>(v4).Val(), FmtArg<A5>(v5).Val(),
\r
2240 FmtArg<A6>(v6).Val(), FmtArg<A7>(v7).Val(), FmtArg<A8>(v8).Val(),
\r
2241 FmtArg<A9>(v9).Val());
\r
2244 template<class A1, class A2, class A3, class A4, class A5, class A6,
\r
2245 class A7, class A8, class A9, class A10>
\r
2246 void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,
\r
2247 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
\r
2248 const A8& v8, const A9& v9, const A10& v10)
\r
2251 if ( strFmt.Load(nId) )
\r
2253 Fmt(strFmt, FmtArg<A1>(v1).Val(), FmtArg<A2>(v2).Val(),
\r
2254 FmtArg<A3>(v3).Val(), FmtArg<A4>(v4).Val(), FmtArg<A5>(v5).Val(),
\r
2255 FmtArg<A6>(v6).Val(), FmtArg<A7>(v7).Val(), FmtArg<A8>(v8).Val(),
\r
2256 FmtArg<A9>(v9).Val(), FmtArg<A10>(v10).Val());
\r
2259 template<class A1, class A2, class A3, class A4, class A5, class A6,
\r
2260 class A7, class A8, class A9, class A10, class A11>
\r
2261 void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,
\r
2262 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
\r
2263 const A8& v8, const A9& v9, const A10& v10, const A11& v11)
\r
2266 if ( strFmt.Load(nId) )
\r
2268 Fmt(strFmt, FmtArg<A1>(v1).Val(), FmtArg<A2>(v2).Val(),
\r
2269 FmtArg<A3>(v3).Val(), FmtArg<A4>(v4).Val(), FmtArg<A5>(v5).Val(),
\r
2270 FmtArg<A6>(v6).Val(), FmtArg<A7>(v7).Val(), FmtArg<A8>(v8).Val(),
\r
2271 FmtArg<A9>(v9).Val(),FmtArg<A10>(v10).Val(),FmtArg<A11>(v11).Val());
\r
2274 template<class A1, class A2, class A3, class A4, class A5, class A6,
\r
2275 class A7, class A8, class A9, class A10, class A11, class A12>
\r
2276 void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,
\r
2277 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
\r
2278 const A8& v8, const A9& v9, const A10& v10, const A11& v11,
\r
2282 if ( strFmt.Load(nId) )
\r
2284 Fmt(strFmt, FmtArg<A1>(v1).Val(), FmtArg<A2>(v2).Val(),
\r
2285 FmtArg<A3>(v3).Val(), FmtArg<A4>(v4).Val(), FmtArg<A5>(v5).Val(),
\r
2286 FmtArg<A6>(v6).Val(), FmtArg<A7>(v7).Val(), FmtArg<A8>(v8).Val(),
\r
2287 FmtArg<A9>(v9).Val(), FmtArg<A10>(v10).Val(),FmtArg<A11>(v11).Val(),
\r
2288 FmtArg<A12>(v12).Val());
\r
2291 template<class A1, class A2, class A3, class A4, class A5, class A6,
\r
2292 class A7, class A8, class A9, class A10, class A11, class A12,
\r
2294 void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,
\r
2295 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
\r
2296 const A8& v8, const A9& v9, const A10& v10, const A11& v11,
\r
2297 const A12& v12, const A13& v13)
\r
2300 if ( strFmt.Load(nId) )
\r
2302 Fmt(strFmt, FmtArg<A1>(v1).Val(), FmtArg<A2>(v2).Val(),
\r
2303 FmtArg<A3>(v3).Val(), FmtArg<A4>(v4).Val(), FmtArg<A5>(v5).Val(),
\r
2304 FmtArg<A6>(v6).Val(), FmtArg<A7>(v7).Val(), FmtArg<A8>(v8).Val(),
\r
2305 FmtArg<A9>(v9).Val(), FmtArg<A10>(v10).Val(),FmtArg<A11>(v11).Val(),
\r
2306 FmtArg<A12>(v12).Val(), FmtArg<A13>(v13).Val());
\r
2309 template<class A1, class A2, class A3, class A4, class A5, class A6,
\r
2310 class A7, class A8, class A9, class A10, class A11, class A12,
\r
2311 class A13, class A14>
\r
2312 void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,
\r
2313 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
\r
2314 const A8& v8, const A9& v9, const A10& v10, const A11& v11,
\r
2315 const A12& v12, const A13& v13, const A14& v14)
\r
2318 if ( strFmt.Load(nId) )
\r
2320 Fmt(strFmt, FmtArg<A1>(v1).Val(), FmtArg<A2>(v2).Val(),
\r
2321 FmtArg<A3>(v3).Val(), FmtArg<A4>(v4).Val(), FmtArg<A5>(v5).Val(),
\r
2322 FmtArg<A6>(v6).Val(), FmtArg<A7>(v7).Val(), FmtArg<A8>(v8).Val(),
\r
2323 FmtArg<A9>(v9).Val(), FmtArg<A10>(v10).Val(),FmtArg<A11>(v11).Val(),
\r
2324 FmtArg<A12>(v12).Val(), FmtArg<A13>(v13).Val(),FmtArg<A14>(v14).Val());
\r
2327 template<class A1, class A2, class A3, class A4, class A5, class A6,
\r
2328 class A7, class A8, class A9, class A10, class A11, class A12,
\r
2329 class A13, class A14, class A15>
\r
2330 void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,
\r
2331 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
\r
2332 const A8& v8, const A9& v9, const A10& v10, const A11& v11,
\r
2333 const A12& v12, const A13& v13, const A14& v14, const A15& v15)
\r
2336 if ( strFmt.Load(nId) )
\r
2338 Fmt(strFmt, FmtArg<A1>(v1).Val(), FmtArg<A2>(v2).Val(),
\r
2339 FmtArg<A3>(v3).Val(), FmtArg<A4>(v4).Val(), FmtArg<A5>(v5).Val(),
\r
2340 FmtArg<A6>(v6).Val(), FmtArg<A7>(v7).Val(), FmtArg<A8>(v8).Val(),
\r
2341 FmtArg<A9>(v9).Val(), FmtArg<A10>(v10).Val(),FmtArg<A11>(v11).Val(),
\r
2342 FmtArg<A12>(v12).Val(),FmtArg<A13>(v13).Val(),FmtArg<A14>(v14).Val(),
\r
2343 FmtArg<A15>(v15).Val());
\r
2346 template<class A1, class A2, class A3, class A4, class A5, class A6,
\r
2347 class A7, class A8, class A9, class A10, class A11, class A12,
\r
2348 class A13, class A14, class A15, class A16>
\r
2349 void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,
\r
2350 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
\r
2351 const A8& v8, const A9& v9, const A10& v10, const A11& v11,
\r
2352 const A12& v12, const A13& v13, const A14& v14, const A15& v15,
\r
2356 if ( strFmt.Load(nId) )
\r
2358 Fmt(strFmt, FmtArg<A1>(v1).Val(), FmtArg<A2>(v2).Val(),
\r
2359 FmtArg<A3>(v3).Val(), FmtArg<A4>(v4).Val(), FmtArg<A5>(v5).Val(),
\r
2360 FmtArg<A6>(v6).Val(), FmtArg<A7>(v7).Val(), FmtArg<A8>(v8).Val(),
\r
2361 FmtArg<A9>(v9).Val(), FmtArg<A10>(v10).Val(),FmtArg<A11>(v11).Val(),
\r
2362 FmtArg<A12>(v12).Val(),FmtArg<A13>(v13).Val(),FmtArg<A14>(v14).Val(),
\r
2363 FmtArg<A15>(v15).Val(), FmtArg<A16>(v16).Val());
\r
2366 template<class A1, class A2, class A3, class A4, class A5, class A6,
\r
2367 class A7, class A8, class A9, class A10, class A11, class A12,
\r
2368 class A13, class A14, class A15, class A16, class A17>
\r
2369 void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,
\r
2370 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
\r
2371 const A8& v8, const A9& v9, const A10& v10, const A11& v11,
\r
2372 const A12& v12, const A13& v13, const A14& v14, const A15& v15,
\r
2373 const A16& v16, const A17& v17)
\r
2376 if ( strFmt.Load(nId) )
\r
2378 Fmt(strFmt, FmtArg<A1>(v1).Val(), FmtArg<A2>(v2).Val(),
\r
2379 FmtArg<A3>(v3).Val(), FmtArg<A4>(v4).Val(), FmtArg<A5>(v5).Val(),
\r
2380 FmtArg<A6>(v6).Val(), FmtArg<A7>(v7).Val(), FmtArg<A8>(v8).Val(),
\r
2381 FmtArg<A9>(v9).Val(), FmtArg<A10>(v10).Val(),FmtArg<A11>(v11).Val(),
\r
2382 FmtArg<A12>(v12).Val(),FmtArg<A13>(v13).Val(),FmtArg<A14>(v14).Val(),
\r
2383 FmtArg<A15>(v15).Val(),FmtArg<A16>(v16).Val(),FmtArg<A17>(v17).Val());
\r
2387 #endif // #ifndef SS_ANSI
\r
2389 // ...now the other overload of Format: the one that takes a string literal
\r
2391 void Format(const CT* szFmt)
\r
2395 template<class A1>
\r
2396 void Format(const CT* szFmt, A1 v)
\r
2398 Fmt(szFmt, FmtArg<A1>(v).Val());
\r
2400 template<class A1, class A2>
\r
2401 void Format(const CT* szFmt, const A1& v1, const A2& v2)
\r
2403 Fmt(szFmt, FmtArg<A1>(v1).Val(), FmtArg<A2>(v2).Val());
\r
2405 template<class A1, class A2, class A3>
\r
2406 void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3)
\r
2408 Fmt(szFmt, FmtArg<A1>(v1).Val(), FmtArg<A2>(v2).Val(),
\r
2409 FmtArg<A3>(v3).Val());
\r
2411 template<class A1, class A2, class A3, class A4>
\r
2412 void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,
\r
2415 Fmt(szFmt, FmtArg<A1>(v1).Val(), FmtArg<A2>(v2).Val(),
\r
2416 FmtArg<A3>(v3).Val(), FmtArg<A4>(v4).Val());
\r
2418 template<class A1, class A2, class A3, class A4, class A5>
\r
2419 void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,
\r
2420 const A4& v4, const A5& v5)
\r
2422 Fmt(szFmt, FmtArg<A1>(v1).Val(), FmtArg<A2>(v2).Val(),
\r
2423 FmtArg<A3>(v3).Val(), FmtArg<A4>(v4).Val(), FmtArg<A5>(v5).Val());
\r
2425 template<class A1, class A2, class A3, class A4, class A5, class A6>
\r
2426 void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,
\r
2427 const A4& v4, const A5& v5, const A6& v6)
\r
2429 Fmt(szFmt, FmtArg<A1>(v1).Val(), FmtArg<A2>(v2).Val(),
\r
2430 FmtArg<A3>(v3).Val(), FmtArg<A4>(v4).Val(), FmtArg<A5>(v5).Val(),
\r
2431 FmtArg<A6>(v6).Val());
\r
2433 template<class A1, class A2, class A3, class A4, class A5, class A6,
\r
2435 void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,
\r
2436 const A4& v4, const A5& v5, const A6& v6, const A7& v7)
\r
2438 Fmt(szFmt, FmtArg<A1>(v1).Val(), FmtArg<A2>(v2).Val(),
\r
2439 FmtArg<A3>(v3).Val(), FmtArg<A4>(v4).Val(), FmtArg<A5>(v5).Val(),
\r
2440 FmtArg<A6>(v6).Val(), FmtArg<A7>(v7).Val());
\r
2442 template<class A1, class A2, class A3, class A4, class A5, class A6,
\r
2443 class A7, class A8>
\r
2444 void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,
\r
2445 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
\r
2448 Fmt(szFmt, FmtArg<A1>(v1).Val(), FmtArg<A2>(v2).Val(),
\r
2449 FmtArg<A3>(v3).Val(), FmtArg<A4>(v4).Val(), FmtArg<A5>(v5).Val(),
\r
2450 FmtArg<A6>(v6).Val(), FmtArg<A7>(v7).Val(), FmtArg<A8>(v8).Val());
\r
2452 template<class A1, class A2, class A3, class A4, class A5, class A6,
\r
2453 class A7, class A8, class A9>
\r
2454 void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,
\r
2455 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
\r
2456 const A8& v8, const A9& v9)
\r
2458 Fmt(szFmt, FmtArg<A1>(v1).Val(), FmtArg<A2>(v2).Val(),
\r
2459 FmtArg<A3>(v3).Val(), FmtArg<A4>(v4).Val(), FmtArg<A5>(v5).Val(),
\r
2460 FmtArg<A6>(v6).Val(), FmtArg<A7>(v7).Val(), FmtArg<A8>(v8).Val(),
\r
2461 FmtArg<A9>(v9).Val());
\r
2463 template<class A1, class A2, class A3, class A4, class A5, class A6,
\r
2464 class A7, class A8, class A9, class A10>
\r
2465 void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,
\r
2466 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
\r
2467 const A8& v8, const A9& v9, const A10& v10)
\r
2469 Fmt(szFmt, FmtArg<A1>(v1).Val(), FmtArg<A2>(v2).Val(),
\r
2470 FmtArg<A3>(v3).Val(), FmtArg<A4>(v4).Val(), FmtArg<A5>(v5).Val(),
\r
2471 FmtArg<A6>(v6).Val(), FmtArg<A7>(v7).Val(), FmtArg<A8>(v8).Val(),
\r
2472 FmtArg<A9>(v9).Val(), FmtArg<A10>(v10).Val());
\r
2474 template<class A1, class A2, class A3, class A4, class A5, class A6,
\r
2475 class A7, class A8, class A9, class A10, class A11>
\r
2476 void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,
\r
2477 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
\r
2478 const A8& v8, const A9& v9, const A10& v10, const A11& v11)
\r
2480 Fmt(szFmt, FmtArg<A1>(v1).Val(), FmtArg<A2>(v2).Val(),
\r
2481 FmtArg<A3>(v3).Val(), FmtArg<A4>(v4).Val(), FmtArg<A5>(v5).Val(),
\r
2482 FmtArg<A6>(v6).Val(), FmtArg<A7>(v7).Val(), FmtArg<A8>(v8).Val(),
\r
2483 FmtArg<A9>(v9).Val(),FmtArg<A10>(v10).Val(),FmtArg<A11>(v11).Val());
\r
2485 template<class A1, class A2, class A3, class A4, class A5, class A6,
\r
2486 class A7, class A8, class A9, class A10, class A11, class A12>
\r
2487 void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,
\r
2488 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
\r
2489 const A8& v8, const A9& v9, const A10& v10, const A11& v11,
\r
2492 Fmt(szFmt, FmtArg<A1>(v1).Val(), FmtArg<A2>(v2).Val(),
\r
2493 FmtArg<A3>(v3).Val(), FmtArg<A4>(v4).Val(), FmtArg<A5>(v5).Val(),
\r
2494 FmtArg<A6>(v6).Val(), FmtArg<A7>(v7).Val(), FmtArg<A8>(v8).Val(),
\r
2495 FmtArg<A9>(v9).Val(), FmtArg<A10>(v10).Val(),FmtArg<A11>(v11).Val(),
\r
2496 FmtArg<A12>(v12).Val());
\r
2498 template<class A1, class A2, class A3, class A4, class A5, class A6,
\r
2499 class A7, class A8, class A9, class A10, class A11, class A12,
\r
2501 void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,
\r
2502 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
\r
2503 const A8& v8, const A9& v9, const A10& v10, const A11& v11,
\r
2504 const A12& v12, const A13& v13)
\r
2506 Fmt(szFmt, FmtArg<A1>(v1).Val(), FmtArg<A2>(v2).Val(),
\r
2507 FmtArg<A3>(v3).Val(), FmtArg<A4>(v4).Val(), FmtArg<A5>(v5).Val(),
\r
2508 FmtArg<A6>(v6).Val(), FmtArg<A7>(v7).Val(), FmtArg<A8>(v8).Val(),
\r
2509 FmtArg<A9>(v9).Val(), FmtArg<A10>(v10).Val(),FmtArg<A11>(v11).Val(),
\r
2510 FmtArg<A12>(v12).Val(), FmtArg<A13>(v13).Val());
\r
2512 template<class A1, class A2, class A3, class A4, class A5, class A6,
\r
2513 class A7, class A8, class A9, class A10, class A11, class A12,
\r
2514 class A13, class A14>
\r
2515 void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,
\r
2516 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
\r
2517 const A8& v8, const A9& v9, const A10& v10, const A11& v11,
\r
2518 const A12& v12, const A13& v13, const A14& v14)
\r
2520 Fmt(szFmt, FmtArg<A1>(v1).Val(), FmtArg<A2>(v2).Val(),
\r
2521 FmtArg<A3>(v3).Val(), FmtArg<A4>(v4).Val(), FmtArg<A5>(v5).Val(),
\r
2522 FmtArg<A6>(v6).Val(), FmtArg<A7>(v7).Val(), FmtArg<A8>(v8).Val(),
\r
2523 FmtArg<A9>(v9).Val(), FmtArg<A10>(v10).Val(),FmtArg<A11>(v11).Val(),
\r
2524 FmtArg<A12>(v12).Val(), FmtArg<A13>(v13).Val(),FmtArg<A14>(v14).Val());
\r
2526 template<class A1, class A2, class A3, class A4, class A5, class A6,
\r
2527 class A7, class A8, class A9, class A10, class A11, class A12,
\r
2528 class A13, class A14, class A15>
\r
2529 void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,
\r
2530 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
\r
2531 const A8& v8, const A9& v9, const A10& v10, const A11& v11,
\r
2532 const A12& v12, const A13& v13, const A14& v14, const A15& v15)
\r
2534 Fmt(szFmt, FmtArg<A1>(v1).Val(), FmtArg<A2>(v2).Val(),
\r
2535 FmtArg<A3>(v3).Val(), FmtArg<A4>(v4).Val(), FmtArg<A5>(v5).Val(),
\r
2536 FmtArg<A6>(v6).Val(), FmtArg<A7>(v7).Val(), FmtArg<A8>(v8).Val(),
\r
2537 FmtArg<A9>(v9).Val(), FmtArg<A10>(v10).Val(),FmtArg<A11>(v11).Val(),
\r
2538 FmtArg<A12>(v12).Val(),FmtArg<A13>(v13).Val(),FmtArg<A14>(v14).Val(),
\r
2539 FmtArg<A15>(v15).Val());
\r
2541 template<class A1, class A2, class A3, class A4, class A5, class A6,
\r
2542 class A7, class A8, class A9, class A10, class A11, class A12,
\r
2543 class A13, class A14, class A15, class A16>
\r
2544 void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,
\r
2545 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
\r
2546 const A8& v8, const A9& v9, const A10& v10, const A11& v11,
\r
2547 const A12& v12, const A13& v13, const A14& v14, const A15& v15,
\r
2550 Fmt(szFmt, FmtArg<A1>(v1).Val(), FmtArg<A2>(v2).Val(),
\r
2551 FmtArg<A3>(v3).Val(), FmtArg<A4>(v4).Val(), FmtArg<A5>(v5).Val(),
\r
2552 FmtArg<A6>(v6).Val(), FmtArg<A7>(v7).Val(), FmtArg<A8>(v8).Val(),
\r
2553 FmtArg<A9>(v9).Val(), FmtArg<A10>(v10).Val(),FmtArg<A11>(v11).Val(),
\r
2554 FmtArg<A12>(v12).Val(),FmtArg<A13>(v13).Val(),FmtArg<A14>(v14).Val(),
\r
2555 FmtArg<A15>(v15).Val(), FmtArg<A16>(v16).Val());
\r
2557 template<class A1, class A2, class A3, class A4, class A5, class A6,
\r
2558 class A7, class A8, class A9, class A10, class A11, class A12,
\r
2559 class A13, class A14, class A15, class A16, class A17>
\r
2560 void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,
\r
2561 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
\r
2562 const A8& v8, const A9& v9, const A10& v10, const A11& v11,
\r
2563 const A12& v12, const A13& v13, const A14& v14, const A15& v15,
\r
2564 const A16& v16, const A17& v17)
\r
2566 Fmt(szFmt, FmtArg<A1>(v1).Val(), FmtArg<A2>(v2).Val(),
\r
2567 FmtArg<A3>(v3).Val(), FmtArg<A4>(v4).Val(), FmtArg<A5>(v5).Val(),
\r
2568 FmtArg<A6>(v6).Val(), FmtArg<A7>(v7).Val(), FmtArg<A8>(v8).Val(),
\r
2569 FmtArg<A9>(v9).Val(), FmtArg<A10>(v10).Val(),FmtArg<A11>(v11).Val(),
\r
2570 FmtArg<A12>(v12).Val(),FmtArg<A13>(v13).Val(),FmtArg<A14>(v14).Val(),
\r
2571 FmtArg<A15>(v15).Val(),FmtArg<A16>(v16).Val(),FmtArg<A17>(v17).Val());
\r
2574 #else // #ifdef SS_SAFE_FORMAT
\r
2579 void Format(UINT nId, ...)
\r
2582 va_start(argList, nId);
\r
2583 va_start(argList, nId);
\r
2586 if ( strFmt.Load(nId) )
\r
2587 FormatV(strFmt, argList);
\r
2592 #endif // #ifdef SS_ANSI
\r
2594 void Format(const CT* szFmt, ...)
\r
2597 va_start(argList, szFmt);
\r
2598 FormatV(szFmt, argList);
\r
2602 #endif // #ifdef SS_SAFE_FORMAT
\r
2604 void AppendFormat(const CT* szFmt, ...)
\r
2607 va_start(argList, szFmt);
\r
2608 AppendFormatV(szFmt, argList);
\r
2612 #define MAX_FMT_TRIES 5 // #of times we try
\r
2613 #define FMT_BLOCK_SIZE 2048 // # of bytes to increment per try
\r
2614 #define BUFSIZE_1ST 256
\r
2615 #define BUFSIZE_2ND 512
\r
2616 #define STD_BUF_SIZE 1024
\r
2618 // an efficient way to add formatted characters to the string. You may only
\r
2619 // add up to STD_BUF_SIZE characters at a time, though
\r
2620 void AppendFormatV(const CT* szFmt, va_list argList)
\r
2622 CT szBuf[STD_BUF_SIZE];
\r
2623 #if defined(SS_ANSI) || !defined(_MSC_VER)
\r
2624 int nLen = ssvsprintf(szBuf, STD_BUF_SIZE-1, szFmt, argList);
\r
2626 int nLen = ssnprintf(szBuf, STD_BUF_SIZE-1, szFmt, argList);
\r
2629 this->append(szBuf, nLen);
\r
2632 // -------------------------------------------------------------------------
\r
2633 // FUNCTION: FormatV
\r
2634 // void FormatV(PCSTR szFormat, va_list, argList);
\r
2637 // This function formats the string with sprintf style format-specs.
\r
2638 // It makes a general guess at required buffer size and then tries
\r
2639 // successively larger buffers until it finds one big enough or a
\r
2640 // threshold (MAX_FMT_TRIES) is exceeded.
\r
2643 // szFormat - a PCSTR holding the format of the output
\r
2644 // argList - a Microsoft specific va_list for variable argument lists
\r
2647 // -------------------------------------------------------------------------
\r
2649 void FormatV(const CT* szFormat, va_list argList)
\r
2651 #if defined(SS_ANSI) || !defined(_MSC_VER)
\r
2652 int nLen = sslen(szFormat) + STD_BUF_SIZE;
\r
2653 ssvsprintf(GetBuffer(nLen), nLen-1, szFormat, argList);
\r
2661 size_type nActual = 0;
\r
2666 // Grow more than linearly (e.g. 512, 1536, 3072, etc)
\r
2668 nChars += ((nTry+1) * FMT_BLOCK_SIZE);
\r
2669 pBuf = reinterpret_cast<CT*>(_alloca(sizeof(CT)*nChars));
\r
2670 nUsed = ssnprintf(pBuf, nChars-1, szFormat, argList);
\r
2672 // Ensure proper NULL termination.
\r
2674 nActual = nUsed == -1 ? nChars-1 : SSMIN(nUsed, nChars-1);
\r
2675 pBuf[nActual+1]= '\0';
\r
2678 } while ( nUsed < 0 && nTry++ < MAX_FMT_TRIES );
\r
2680 // assign whatever we managed to format
\r
2682 this->assign(pBuf, nActual);
\r
2688 // -------------------------------------------------------------------------
\r
2689 // CString Facade Functions:
\r
2691 // The following methods are intended to allow you to use this class as a
\r
2692 // drop-in replacement for CString.
\r
2693 // -------------------------------------------------------------------------
\r
2695 BSTR AllocSysString() const
\r
2699 return ::SysAllocString(os.c_str());
\r
2703 int Collate(PCMYSTR szThat) const
\r
2705 return sscoll(this->c_str(), this->length(), szThat, sslen(szThat));
\r
2708 int CollateNoCase(PCMYSTR szThat) const
\r
2710 return ssicoll(this->c_str(), this->length(), szThat, sslen(szThat));
\r
2713 int Compare(PCMYSTR szThat) const
\r
2715 return this->compare(szThat);
\r
2718 int CompareNoCase(PCMYSTR szThat) const
\r
2720 return ssicmp(this->c_str(), szThat);
\r
2723 int Delete(int nIdx, int nCount=1)
\r
2728 if ( nIdx < GetLength() )
\r
2729 this->erase(static_cast<MYSIZE>(nIdx), static_cast<MYSIZE>(nCount));
\r
2731 return GetLength();
\r
2739 int Find(CT ch) const
\r
2741 MYSIZE nIdx = this->find_first_of(ch);
\r
2742 return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);
\r
2745 int Find(PCMYSTR szSub) const
\r
2747 MYSIZE nIdx = this->find(szSub);
\r
2748 return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);
\r
2751 int Find(CT ch, int nStart) const
\r
2753 // CString::Find docs say add 1 to nStart when it's not zero
\r
2754 // CString::Find code doesn't do that however. We'll stick
\r
2755 // with what the code does
\r
2757 MYSIZE nIdx = this->find_first_of(ch, static_cast<MYSIZE>(nStart));
\r
2758 return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);
\r
2761 int Find(PCMYSTR szSub, int nStart) const
\r
2763 // CString::Find docs say add 1 to nStart when it's not zero
\r
2764 // CString::Find code doesn't do that however. We'll stick
\r
2765 // with what the code does
\r
2767 MYSIZE nIdx = this->find(szSub, static_cast<MYSIZE>(nStart));
\r
2768 return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);
\r
2771 int FindOneOf(PCMYSTR szCharSet) const
\r
2773 MYSIZE nIdx = this->find_first_of(szCharSet);
\r
2774 return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);
\r
2778 void FormatMessage(PCMYSTR szFormat, ...) throw(std::exception)
\r
2781 va_start(argList, szFormat);
\r
2783 if ( ssfmtmsg(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ALLOCATE_BUFFER,
\r
2785 reinterpret_cast<PMYSTR>(&szTemp), 0, &argList) == 0 ||
\r
2788 throw std::runtime_error("out of memory");
\r
2791 LocalFree(szTemp);
\r
2795 void FormatMessage(UINT nFormatId, ...) throw(std::exception)
\r
2798 VERIFY(sFormat.LoadString(nFormatId) != 0);
\r
2800 va_start(argList, nFormatId);
\r
2802 if ( ssfmtmsg(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ALLOCATE_BUFFER,
\r
2804 reinterpret_cast<PMYSTR>(&szTemp), 0, &argList) == 0 ||
\r
2807 throw std::runtime_error("out of memory");
\r
2810 LocalFree(szTemp);
\r
2816 // -------------------------------------------------------------------------
\r
2817 // GetXXXX -- Direct access to character buffer
\r
2818 // -------------------------------------------------------------------------
\r
2819 CT GetAt(int nIdx) const
\r
2821 return this->at(static_cast<MYSIZE>(nIdx));
\r
2824 CT* GetBuffer(int nMinLen=-1)
\r
2826 return GetBuf(nMinLen);
\r
2829 CT* GetBufferSetLength(int nLen)
\r
2831 return BufferSet(nLen);
\r
2834 // GetLength() -- MFC docs say this is the # of BYTES but
\r
2835 // in truth it is the number of CHARACTERs (chars or wchar_ts)
\r
2836 int GetLength() const
\r
2838 return static_cast<int>(this->length());
\r
2842 int Insert(int nIdx, CT ch)
\r
2844 if ( static_cast<MYSIZE>(nIdx) > this->size() -1 )
\r
2845 this->append(1, ch);
\r
2847 this->insert(static_cast<MYSIZE>(nIdx), 1, ch);
\r
2849 return GetLength();
\r
2851 int Insert(int nIdx, PCMYSTR sz)
\r
2853 if ( nIdx >= this->size() )
\r
2854 this->append(sz, sslen(sz));
\r
2856 this->insert(static_cast<MYSIZE>(nIdx), sz);
\r
2858 return GetLength();
\r
2861 bool IsEmpty() const
\r
2863 return this->empty();
\r
2866 MYTYPE Left(int nCount) const
\r
2868 // Range check the count.
\r
2870 nCount = SSMAX(0, SSMIN(nCount, static_cast<int>(this->size())));
\r
2871 return this->substr(0, static_cast<MYSIZE>(nCount));
\r
2875 bool LoadString(UINT nId)
\r
2877 return this->Load(nId);
\r
2886 void MakeReverse()
\r
2888 std::reverse(this->begin(), this->end());
\r
2896 MYTYPE Mid(int nFirst ) const
\r
2898 return Mid(nFirst, size()-nFirst);
\r
2901 MYTYPE Mid(int nFirst, int nCount) const
\r
2903 // CString does range checking here. Since we're trying to emulate it,
\r
2904 // we must check too.
\r
2911 if ( nFirst + nCount > size() )
\r
2912 nCount = size() - nFirst;
\r
2914 if ( nFirst > size() )
\r
2917 ASSERT(nFirst >= 0);
\r
2918 ASSERT(nFirst + nCount <= size());
\r
2920 return this->substr(static_cast<MYSIZE>(nFirst),
\r
2921 static_cast<MYSIZE>(nCount));
\r
2924 void ReleaseBuffer(int nNewLen=-1)
\r
2933 while ( (nIdx=this->find_first_of(ch)) != MYBASE::npos )
\r
2935 this->erase(nIdx, 1);
\r
2941 int Replace(CT chOld, CT chNew)
\r
2943 int nReplaced = 0;
\r
2944 for ( MYITER iter=this->begin(); iter != this->end(); iter++ )
\r
2946 if ( *iter == chOld )
\r
2955 int Replace(PCMYSTR szOld, PCMYSTR szNew)
\r
2957 int nReplaced = 0;
\r
2959 MYSIZE nOldLen = sslen(szOld);
\r
2960 if ( 0 == nOldLen )
\r
2963 static const CT ch = CT(0);
\r
2964 MYSIZE nNewLen = sslen(szNew);
\r
2965 PCMYSTR szRealNew = szNew == 0 ? &ch : szNew;
\r
2967 while ( (nIdx=this->find(szOld, nIdx)) != MYBASE::npos )
\r
2969 replace(this->begin()+nIdx, this->begin()+nIdx+nOldLen, szRealNew);
\r
2976 int ReverseFind(CT ch) const
\r
2978 MYSIZE nIdx = this->find_last_of(ch);
\r
2979 return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);
\r
2982 // ReverseFind overload that's not in CString but might be useful
\r
2983 int ReverseFind(PCMYSTR szFind, MYSIZE pos=MYBASE::npos) const
\r
2985 MYSIZE nIdx = this->rfind(0 == szFind ? MYTYPE() : szFind, pos);
\r
2986 return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);
\r
2989 MYTYPE Right(int nCount) const
\r
2991 // Range check the count.
\r
2993 nCount = SSMAX(0, SSMIN(nCount, static_cast<int>(this->size())));
\r
2994 return this->substr(this->size()-static_cast<MYSIZE>(nCount));
\r
2997 void SetAt(int nIndex, CT ch)
\r
2999 ASSERT(this->size() > static_cast<MYSIZE>(nIndex));
\r
3000 this->at(static_cast<MYSIZE>(nIndex)) = ch;
\r
3004 BSTR SetSysString(BSTR* pbstr) const
\r
3008 if ( !::SysReAllocStringLen(pbstr, os.c_str(), os.length()) )
\r
3009 throw std::runtime_error("out of memory");
\r
3011 ASSERT(*pbstr != 0);
\r
3016 MYTYPE SpanExcluding(PCMYSTR szCharSet) const
\r
3018 MYSIZE pos = this->find_first_of(szCharSet);
\r
3019 return pos == MYBASE::npos ? *this : Left(pos);
\r
3022 MYTYPE SpanIncluding(PCMYSTR szCharSet) const
\r
3024 MYSIZE pos = this->find_first_not_of(szCharSet);
\r
3025 return pos == MYBASE::npos ? *this : Left(pos);
\r
3028 #if !defined(UNICODE) && !defined(SS_ANSI)
\r
3030 // CString's OemToAnsi and AnsiToOem functions are available only in
\r
3031 // Unicode builds. However since we're a template we also need a
\r
3032 // runtime check of CT and a reinterpret_cast to account for the fact
\r
3033 // that CStdStringW gets instantiated even in non-Unicode builds.
\r
3037 if ( sizeof(CT) == sizeof(char) && !empty() )
\r
3039 ::CharToOem(reinterpret_cast<PCSTR>(this->c_str()),
\r
3040 reinterpret_cast<PSTR>(GetBuf()));
\r
3050 if ( sizeof(CT) == sizeof(char) && !empty() )
\r
3052 ::OemToChar(reinterpret_cast<PCSTR>(this->c_str()),
\r
3053 reinterpret_cast<PSTR>(GetBuf()));
\r
3064 // -------------------------------------------------------------------------
\r
3065 // Trim and its variants
\r
3066 // -------------------------------------------------------------------------
\r
3069 return TrimLeft().TrimRight();
\r
3072 MYTYPE& TrimLeft()
\r
3074 this->erase(this->begin(),
\r
3075 std::find_if(this->begin(), this->end(), NotSpace<CT>()));
\r
3080 MYTYPE& TrimLeft(CT tTrim)
\r
3082 this->erase(0, this->find_first_not_of(tTrim));
\r
3086 MYTYPE& TrimLeft(PCMYSTR szTrimChars)
\r
3088 this->erase(0, this->find_first_not_of(szTrimChars));
\r
3092 MYTYPE& TrimRight()
\r
3094 // NOTE: When comparing reverse_iterators here (MYRITER), I avoid using
\r
3095 // operator!=. This is because namespace rel_ops also has a template
\r
3096 // operator!= which conflicts with the global operator!= already defined
\r
3097 // for reverse_iterator in the header <utility>.
\r
3098 // Thanks to John James for alerting me to this.
\r
3100 MYRITER it = std::find_if(this->rbegin(), this->rend(), NotSpace<CT>());
\r
3101 if ( !(this->rend() == it) )
\r
3102 this->erase(this->rend() - it);
\r
3104 this->erase(!(it == this->rend()) ? this->find_last_of(*it) + 1 : 0);
\r
3108 MYTYPE& TrimRight(CT tTrim)
\r
3110 MYSIZE nIdx = this->find_last_not_of(tTrim);
\r
3111 this->erase(MYBASE::npos == nIdx ? 0 : ++nIdx);
\r
3115 MYTYPE& TrimRight(PCMYSTR szTrimChars)
\r
3117 MYSIZE nIdx = this->find_last_not_of(szTrimChars);
\r
3118 this->erase(MYBASE::npos == nIdx ? 0 : ++nIdx);
\r
3126 if ( !mt.empty() )
\r
3127 this->assign(mt.c_str(), mt.size());
\r
3130 // I have intentionally not implemented the following CString
\r
3131 // functions. You cannot make them work without taking advantage
\r
3132 // of implementation specific behavior. However if you absolutely
\r
3133 // MUST have them, uncomment out these lines for "sort-of-like"
\r
3134 // their behavior. You're on your own.
\r
3136 // CT* LockBuffer() { return GetBuf(); }// won't really lock
\r
3137 // void UnlockBuffer(); { } // why have UnlockBuffer w/o LockBuffer?
\r
3139 // Array-indexing operators. Required because we defined an implicit cast
\r
3140 // to operator const CT* (Thanks to Julian Selman for pointing this out)
\r
3141 CT& operator[](int nIdx)
\r
3143 return MYBASE::operator[](static_cast<MYSIZE>(nIdx));
\r
3146 const CT& operator[](int nIdx) const
\r
3148 return MYBASE::operator[](static_cast<MYSIZE>(nIdx));
\r
3151 CT& operator[](unsigned int nIdx)
\r
3153 return MYBASE::operator[](static_cast<MYSIZE>(nIdx));
\r
3156 const CT& operator[](unsigned int nIdx) const
\r
3158 return MYBASE::operator[](static_cast<MYSIZE>(nIdx));
\r
3161 #ifndef SS_NO_IMPLICIT_CAST
\r
3162 operator const CT*() const
\r
3164 return this->c_str();
\r
3168 // IStream related functions. Useful in IPersistStream implementations
\r
3170 #ifdef SS_INC_COMDEF
\r
3172 // struct SSSHDR - useful for non Std C++ persistence schemes.
\r
3173 typedef struct SSSHDR
\r
3177 } SSSHDR; // as in "Standard String Stream Header"
\r
3179 #define SSSO_UNICODE 0x01 // the string is a wide string
\r
3180 #define SSSO_COMPRESS 0x02 // the string is compressed
\r
3182 // -------------------------------------------------------------------------
\r
3183 // FUNCTION: StreamSize
\r
3185 // Returns how many bytes it will take to StreamSave() this CStdString
\r
3186 // object to an IStream.
\r
3187 // -------------------------------------------------------------------------
\r
3188 ULONG StreamSize() const
\r
3190 // Control header plus string
\r
3191 ASSERT(this->size()*sizeof(CT) < 0xffffffffUL - sizeof(SSSHDR));
\r
3192 return (this->size() * sizeof(CT)) + sizeof(SSSHDR);
\r
3195 // -------------------------------------------------------------------------
\r
3196 // FUNCTION: StreamSave
\r
3198 // Saves this CStdString object to a COM IStream.
\r
3199 // -------------------------------------------------------------------------
\r
3200 HRESULT StreamSave(IStream* pStream) const
\r
3202 ASSERT(size()*sizeof(CT) < 0xffffffffUL - sizeof(SSSHDR));
\r
3203 HRESULT hr = E_FAIL;
\r
3204 ASSERT(pStream != 0);
\r
3206 hdr.byCtrl = sizeof(CT) == 2 ? SSSO_UNICODE : 0;
\r
3207 hdr.nChars = this->size();
\r
3210 if ( FAILED(hr=pStream->Write(&hdr, sizeof(SSSHDR), 0)) )
\r
3211 TRACE(_T("StreamSave: Cannot write control header, ERR=0x%X\n"),hr);
\r
3212 else if ( empty() )
\r
3213 ; // nothing to write
\r
3214 else if ( FAILED(hr=pStream->Write(this->c_str(), this->size()*sizeof(CT), 0)) )
\r
3215 TRACE(_T("StreamSave: Cannot write string to stream 0x%X\n"), hr);
\r
3221 // -------------------------------------------------------------------------
\r
3222 // FUNCTION: StreamLoad
\r
3224 // This method loads the object from an IStream.
\r
3225 // -------------------------------------------------------------------------
\r
3226 HRESULT StreamLoad(IStream* pStream)
\r
3228 ASSERT(pStream != 0);
\r
3230 HRESULT hr = E_FAIL;
\r
3232 if ( FAILED(hr=pStream->Read(&hdr, sizeof(SSSHDR), 0)) )
\r
3234 TRACE(_T("StreamLoad: Cant read control header, ERR=0x%X\n"), hr);
\r
3236 else if ( hdr.nChars > 0 )
\r
3239 PMYSTR pMyBuf = BufferSet(hdr.nChars);
\r
3241 // If our character size matches the character size of the string
\r
3242 // we're trying to read, then we can read it directly into our
\r
3243 // buffer. Otherwise, we have to read into an intermediate buffer
\r
3246 if ( (hdr.byCtrl & SSSO_UNICODE) != 0 )
\r
3248 ULONG nBytes = hdr.nChars * sizeof(wchar_t);
\r
3249 if ( sizeof(CT) == sizeof(wchar_t) )
\r
3251 if ( FAILED(hr=pStream->Read(pMyBuf, nBytes, &nRead)) )
\r
3252 TRACE(_T("StreamLoad: Cannot read string: 0x%X\n"), hr);
\r
3256 PWSTR pBufW = reinterpret_cast<PWSTR>(_alloca((nBytes)+1));
\r
3257 if ( FAILED(hr=pStream->Read(pBufW, nBytes, &nRead)) )
\r
3258 TRACE(_T("StreamLoad: Cannot read string: 0x%X\n"), hr);
\r
3260 sscpy(pMyBuf, pBufW, hdr.nChars);
\r
3265 ULONG nBytes = hdr.nChars * sizeof(char);
\r
3266 if ( sizeof(CT) == sizeof(char) )
\r
3268 if ( FAILED(hr=pStream->Read(pMyBuf, nBytes, &nRead)) )
\r
3269 TRACE(_T("StreamLoad: Cannot read string: 0x%X\n"), hr);
\r
3273 PSTR pBufA = reinterpret_cast<PSTR>(_alloca(nBytes));
\r
3274 if ( FAILED(hr=pStream->Read(pBufA, hdr.nChars, &nRead)) )
\r
3275 TRACE(_T("StreamLoad: Cannot read string: 0x%X\n"), hr);
\r
3277 sscpy(pMyBuf, pBufA, hdr.nChars);
\r
3287 #endif // #ifdef SS_INC_COMDEF
\r
3291 // SetResourceHandle/GetResourceHandle. In MFC builds, these map directly
\r
3292 // to AfxSetResourceHandle and AfxGetResourceHandle. In non-MFC builds they
\r
3293 // point to a single static HINST so that those who call the member
\r
3294 // functions that take resource IDs can provide an alternate HINST of a DLL
\r
3295 // to search. This is not exactly the list of HMODULES that MFC provides
\r
3296 // but it's better than nothing.
\r
3299 static void SetResourceHandle(HMODULE hNew)
\r
3301 AfxSetResourceHandle(hNew);
\r
3303 static HMODULE GetResourceHandle()
\r
3305 return AfxGetResourceHandle();
\r
3308 static void SetResourceHandle(HMODULE hNew)
\r
3310 SSResourceHandle() = hNew;
\r
3312 static HMODULE GetResourceHandle()
\r
3314 return SSResourceHandle();
\r
3319 template<typename CT2>
\r
3320 MYTYPE operator+(const CStdStr<CT2>& s2)
\r
3322 MYTYPE strRet(SSREF(*this));
\r
3323 strRet += s2.c_str();
\r
3333 // -----------------------------------------------------------------------------
\r
3334 // CStdStr friend addition functions defined as inline
\r
3335 // -----------------------------------------------------------------------------
\r
3336 template<typename CT>
\r
3338 CStdStr<CT> operator+(const CStdStr<CT>& str1, const CStdStr<CT>& str2)
\r
3340 CStdStr<CT> strRet(SSREF(str1));
\r
3341 strRet.append(str2);
\r
3345 template<typename CT>
\r
3347 CStdStr<CT> operator+(const CStdStr<CT>& str, CT t)
\r
3349 // this particular overload is needed for disabling reference counting
\r
3350 // though it's only an issue from line 1 to line 2
\r
3352 CStdStr<CT> strRet(SSREF(str)); // 1
\r
3353 strRet.append(1, t); // 2
\r
3357 template<typename CT>
\r
3359 CStdStr<CT> operator+(const CStdStr<CT>& str, PCSTR pA)
\r
3361 return CStdStr<CT>(str) + CStdStr<CT>(pA);
\r
3364 template<typename CT>
\r
3366 CStdStr<CT> operator+(PCSTR pA, const CStdStr<CT>& str)
\r
3368 CStdStr<CT> strRet(pA);
\r
3369 strRet.append(str);
\r
3373 template<typename CT>
\r
3375 CStdStr<CT> operator+(const CStdStr<CT>& str, PCWSTR pW)
\r
3377 return CStdStr<CT>(SSREF(str)) + CStdStr<CT>(pW);
\r
3380 template<typename CT>
\r
3382 CStdStr<CT> operator+(PCWSTR pW, const CStdStr<CT>& str)
\r
3384 CStdStr<CT> strRet(pW);
\r
3385 strRet.append(str);
\r
3389 #ifdef SS_INC_COMDEF
\r
3390 template<typename CT>
\r
3392 CStdStr<CT> operator+(const _bstr_t& bstr, const CStdStr<CT>& str)
\r
3394 return static_cast<const CT*>(bstr) + str;
\r
3397 template<typename CT>
\r
3399 CStdStr<CT> operator+(const CStdStr<CT>& str, const _bstr_t& bstr)
\r
3401 return str + static_cast<const CT*>(bstr);
\r
3405 // -----------------------------------------------------------------------------
\r
3406 // HOW TO EXPORT CSTDSTRING FROM A DLL
\r
3408 // If you want to export CStdStringA and CStdStringW from a DLL, then all you
\r
3410 // 1. make sure that all components link to the same DLL version
\r
3411 // of the CRT (not the static one).
\r
3412 // 2. Uncomment the 3 lines of code below
\r
3413 // 3. #define 2 macros per the instructions in MS KnowledgeBase
\r
3414 // article Q168958. The macros are:
\r
3416 // MACRO DEFINTION WHEN EXPORTING DEFINITION WHEN IMPORTING
\r
3417 // ----- ------------------------ -------------------------
\r
3418 // SSDLLEXP (nothing, just #define it) extern
\r
3419 // SSDLLSPEC __declspec(dllexport) __declspec(dllimport)
\r
3421 // Note that these macros must be available to ALL clients who want to
\r
3422 // link to the DLL and use the class. If they
\r
3423 // -----------------------------------------------------------------------------
\r
3424 //#pragma warning(disable:4231) // non-standard extension ("extern template")
\r
3425 // SSDLLEXP template class SSDLLSPEC CStdStr<char>;
\r
3426 // SSDLLEXP template class SSDLLSPEC CStdStr<wchar_t>;
\r
3428 // =============================================================================
\r
3429 // END OF CStdStr INLINE FUNCTION DEFINITIONS
\r
3430 // =============================================================================
\r
3432 // Now typedef our class names based upon this humongous template
\r
3434 typedef CStdStr<char> CStdStringA; // a better std::string
\r
3435 typedef CStdStr<wchar_t> CStdStringW; // a better std::wstring
\r
3436 typedef CStdStr<OLECHAR> CStdStringO; // almost always CStdStringW
\r
3439 // New-style format function is a template
\r
3441 #ifdef SS_SAFE_FORMAT
\r
3444 struct FmtArg<CStdStringA>
\r
3446 explicit FmtArg(const CStdStringA& arg) : a_(arg) {}
\r
3447 PCSTR Val() const { return a_.c_str(); }
\r
3448 const CStdStringA& a_;
\r
3450 FmtArg<CStdStringA>& operator=(const FmtArg<CStdStringA>&) { return *this; }
\r
3453 struct FmtArg<CStdStringW>
\r
3455 explicit FmtArg(const CStdStringW& arg) : a_(arg) {}
\r
3456 PCWSTR Val() const { return a_.c_str(); }
\r
3457 const CStdStringW& a_;
\r
3459 FmtArg<CStdStringW>& operator=(const FmtArg<CStdStringW>&) { return *this; }
\r
3463 struct FmtArg<std::string>
\r
3465 explicit FmtArg(const std::string& arg) : a_(arg) {}
\r
3466 PCSTR Val() const { return a_.c_str(); }
\r
3467 const std::string& a_;
\r
3469 FmtArg<std::string>& operator=(const FmtArg<std::string>&) { return *this; }
\r
3472 struct FmtArg<std::wstring>
\r
3474 explicit FmtArg(const std::wstring& arg) : a_(arg) {}
\r
3475 PCWSTR Val() const { return a_.c_str(); }
\r
3476 const std::wstring& a_;
\r
3478 FmtArg<std::wstring>& operator=(const FmtArg<std::wstring>&) {return *this;}
\r
3480 #endif // #ifdef SS_SAFEFORMAT
\r
3483 // SSResourceHandle: our MFC-like resource handle
\r
3484 inline HMODULE& SSResourceHandle()
\r
3486 static HMODULE hModuleSS = GetModuleHandle(0);
\r
3494 // In MFC builds, define some global serialization operators
\r
3495 // Special operators that allow us to serialize CStdStrings to CArchives.
\r
3496 // Note that we use an intermediate CString object in order to ensure that
\r
3497 // we use the exact same format.
\r
3500 inline CArchive& AFXAPI operator<<(CArchive& ar, const CStdStringA& strA)
\r
3502 CString strTemp = strA;
\r
3503 return ar << strTemp;
\r
3505 inline CArchive& AFXAPI operator<<(CArchive& ar, const CStdStringW& strW)
\r
3507 CString strTemp = strW;
\r
3508 return ar << strTemp;
\r
3511 inline CArchive& AFXAPI operator>>(CArchive& ar, CStdStringA& strA)
\r
3518 inline CArchive& AFXAPI operator>>(CArchive& ar, CStdStringW& strW)
\r
3525 #endif // #ifdef _MFC_VER -- (i.e. is this MFC?)
\r
3529 // -----------------------------------------------------------------------------
\r
3530 // GLOBAL FUNCTION: WUFormat
\r
3531 // CStdStringA WUFormat(UINT nId, ...);
\r
3532 // CStdStringA WUFormat(PCSTR szFormat, ...);
\r
3535 // This function allows the caller for format and return a CStdStringA
\r
3536 // object with a single line of code.
\r
3537 // -----------------------------------------------------------------------------
\r
3541 inline CStdStringA WUFormatA(UINT nId, ...)
\r
3544 va_start(argList, nId);
\r
3546 CStdStringA strFmt;
\r
3547 CStdStringA strOut;
\r
3548 if ( strFmt.Load(nId) )
\r
3549 strOut.FormatV(strFmt, argList);
\r
3554 inline CStdStringA WUFormatA(PCSTR szFormat, ...)
\r
3557 va_start(argList, szFormat);
\r
3558 CStdStringA strOut;
\r
3559 strOut.FormatV(szFormat, argList);
\r
3564 inline CStdStringW WUFormatW(UINT nId, ...)
\r
3567 va_start(argList, nId);
\r
3569 CStdStringW strFmt;
\r
3570 CStdStringW strOut;
\r
3571 if ( strFmt.Load(nId) )
\r
3572 strOut.FormatV(strFmt, argList);
\r
3577 inline CStdStringW WUFormatW(PCWSTR szwFormat, ...)
\r
3580 va_start(argList, szwFormat);
\r
3581 CStdStringW strOut;
\r
3582 strOut.FormatV(szwFormat, argList);
\r
3586 #endif // #ifdef SS_ANSI
\r
3589 // -------------------------------------------------------------------------
\r
3590 // FUNCTION: WUSysMessage
\r
3591 // CStdStringA WUSysMessageA(DWORD dwError, DWORD dwLangId=SS_DEFLANGID);
\r
3592 // CStdStringW WUSysMessageW(DWORD dwError, DWORD dwLangId=SS_DEFLANGID);
\r
3595 // This function simplifies the process of obtaining a string equivalent
\r
3596 // of a system error code returned from GetLastError(). You simply
\r
3597 // supply the value returned by GetLastError() to this function and the
\r
3598 // corresponding system string is returned in the form of a CStdStringA.
\r
3601 // dwError - a DWORD value representing the error code to be translated
\r
3602 // dwLangId - the language id to use. defaults to english.
\r
3605 // a CStdStringA equivalent of the error code. Currently, this function
\r
3606 // only returns either English of the system default language strings.
\r
3607 // -------------------------------------------------------------------------
\r
3608 #define SS_DEFLANGID MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT)
\r
3609 inline CStdStringA WUSysMessageA(DWORD dwError, DWORD dwLangId=SS_DEFLANGID)
\r
3613 if ( 0 != ::FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError,
\r
3614 dwLangId, szBuf, 511, NULL) )
\r
3615 return WUFormatA("%s (0x%X)", szBuf, dwError);
\r
3617 return WUFormatA("Unknown error (0x%X)", dwError);
\r
3619 inline CStdStringW WUSysMessageW(DWORD dwError, DWORD dwLangId=SS_DEFLANGID)
\r
3623 if ( 0 != ::FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError,
\r
3624 dwLangId, szBuf, 511, NULL) )
\r
3625 return WUFormatW(L"%s (0x%X)", szBuf, dwError);
\r
3627 return WUFormatW(L"Unknown error (0x%X)", dwError);
\r
3631 // Define TCHAR based friendly names for some of these functions
\r
3634 #define CStdString CStdStringW
\r
3635 #define WUSysMessage WUSysMessageW
\r
3636 #define WUFormat WUFormatW
\r
3638 #define CStdString CStdStringA
\r
3639 #define WUSysMessage WUSysMessageA
\r
3640 #define WUFormat WUFormatA
\r
3643 // ...and some shorter names for the space-efficient
\r
3645 #define WUSysMsg WUSysMessage
\r
3646 #define WUSysMsgA WUSysMessageA
\r
3647 #define WUSysMsgW WUSysMessageW
\r
3648 #define WUFmtA WUFormatA
\r
3649 #define WUFmtW WUFormatW
\r
3650 #define WUFmt WUFormat
\r
3651 #define WULastErrMsg() WUSysMessage(::GetLastError())
\r
3652 #define WULastErrMsgA() WUSysMessageA(::GetLastError())
\r
3653 #define WULastErrMsgW() WUSysMessageW(::GetLastError())
\r
3656 // -----------------------------------------------------------------------------
\r
3657 // FUNCTIONAL COMPARATORS:
\r
3659 // These structs are derived from the std::binary_function template. They
\r
3660 // give us functional classes (which may be used in Standard C++ Library
\r
3661 // collections and algorithms) that perform case-insensitive comparisons of
\r
3662 // CStdString objects. This is useful for maps in which the key may be the
\r
3663 // proper string but in the wrong case.
\r
3664 // -----------------------------------------------------------------------------
\r
3665 #define StdStringLessNoCaseW SSLNCW // avoid VC compiler warning 4786
\r
3666 #define StdStringEqualsNoCaseW SSENCW
\r
3667 #define StdStringLessNoCaseA SSLNCA
\r
3668 #define StdStringEqualsNoCaseA SSENCA
\r
3671 #define StdStringLessNoCase SSLNCW
\r
3672 #define StdStringEqualsNoCase SSENCW
\r
3674 #define StdStringLessNoCase SSLNCA
\r
3675 #define StdStringEqualsNoCase SSENCA
\r
3678 struct StdStringLessNoCaseW
\r
3679 : std::binary_function<CStdStringW, CStdStringW, bool>
\r
3682 bool operator()(const CStdStringW& sLeft, const CStdStringW& sRight) const
\r
3683 { return ssicmp(sLeft.c_str(), sRight.c_str()) < 0; }
\r
3685 struct StdStringEqualsNoCaseW
\r
3686 : std::binary_function<CStdStringW, CStdStringW, bool>
\r
3689 bool operator()(const CStdStringW& sLeft, const CStdStringW& sRight) const
\r
3690 { return ssicmp(sLeft.c_str(), sRight.c_str()) == 0; }
\r
3692 struct StdStringLessNoCaseA
\r
3693 : std::binary_function<CStdStringA, CStdStringA, bool>
\r
3696 bool operator()(const CStdStringA& sLeft, const CStdStringA& sRight) const
\r
3697 { return ssicmp(sLeft.c_str(), sRight.c_str()) < 0; }
\r
3699 struct StdStringEqualsNoCaseA
\r
3700 : std::binary_function<CStdStringA, CStdStringA, bool>
\r
3703 bool operator()(const CStdStringA& sLeft, const CStdStringA& sRight) const
\r
3704 { return ssicmp(sLeft.c_str(), sRight.c_str()) == 0; }
\r
3707 // If we had to define our own version of TRACE above, get rid of it now
\r
3709 #ifdef TRACE_DEFINED_HERE
\r
3711 #undef TRACE_DEFINED_HERE
\r
3715 // These std::swap specializations come courtesy of Mike Crusader.
\r
3719 // inline void swap(CStdStringA& s1, CStdStringA& s2) throw()
\r
3724 // inline void swap(CStdStringW& s1, CStdStringW& s2) throw()
\r
3730 // Turn back on any Borland warnings we turned off.
\r
3732 #ifdef __BORLANDC__
\r
3733 #pragma option pop // Turn back on inline function warnings
\r
3734 // #pragma warn +inl // Turn back on inline function warnings
\r
3737 #endif // #ifndef STDSTRING_H