Imported Upstream version 2.2.0
[deb_libcec.git] / src / lib / platform / util / StdString.h
CommitLineData
cbbe90dd
JB
1#pragma once
2#include <string>
3#include <stdint.h>
4#include <vector>
5
6#if defined(_WIN32) && !defined(va_copy)
7#define va_copy(dst, src) ((dst) = (src))
8#endif
9
10// =============================================================================
11// FILE: StdString.h
12// AUTHOR: Joe O'Leary (with outside help noted in comments)
13//
14// If you find any bugs in this code, please let me know:
15//
16// jmoleary@earthlink.net
17// http://www.joeo.net/stdstring.htm (a bit outdated)
18//
19// The latest version of this code should always be available at the
20// following link:
21//
22// http://www.joeo.net/code/StdString.zip (Dec 6, 2003)
23//
24//
25// REMARKS:
26// This header file declares the CStdStr template. This template derives
27// the Standard C++ Library basic_string<> template and add to it the
28// the following conveniences:
29// - The full MFC CString set of functions (including implicit cast)
30// - writing to/reading from COM IStream interfaces
31// - Functional objects for use in STL algorithms
32//
33// From this template, we intstantiate two classes: CStdStringA and
34// CStdStringW. The name "CStdString" is just a #define of one of these,
35// based upone the UNICODE macro setting
36//
37// This header also declares our own version of the MFC/ATL UNICODE-MBCS
38// conversion macros. Our version looks exactly like the Microsoft's to
39// facilitate portability.
40//
41// NOTE:
42// If you you use this in an MFC or ATL build, you should include either
43// afx.h or atlbase.h first, as appropriate.
44//
45// PEOPLE WHO HAVE CONTRIBUTED TO THIS CLASS:
46//
47// Several people have helped me iron out problems and othewise improve
48// this class. OK, this is a long list but in my own defense, this code
49// has undergone two major rewrites. Many of the improvements became
50// necessary after I rewrote the code as a template. Others helped me
51// improve the CString facade.
52//
53// Anyway, these people are (in chronological order):
54//
55// - Pete the Plumber (???)
56// - Julian Selman
57// - Chris (of Melbsys)
58// - Dave Plummer
59// - John C Sipos
60// - Chris Sells
61// - Nigel Nunn
62// - Fan Xia
63// - Matthew Williams
64// - Carl Engman
65// - Mark Zeren
66// - Craig Watson
67// - Rich Zuris
68// - Karim Ratib
69// - Chris Conti
70// - Baptiste Lepilleur
71// - Greg Pickles
72// - Jim Cline
73// - Jeff Kohn
74// - Todd Heckel
75// - Ullrich Poll�hne
76// - Joe Vitaterna
77// - Joe Woodbury
78// - Aaron (no last name)
79// - Joldakowski (???)
80// - Scott Hathaway
81// - Eric Nitzche
82// - Pablo Presedo
83// - Farrokh Nejadlotfi
84// - Jason Mills
85// - Igor Kholodov
86// - Mike Crusader
87// - John James
88// - Wang Haifeng
89// - Tim Dowty
90// - Arnt Witteveen
91// - Glen Maynard
92// - Paul DeMarco
93// - Bagira (full name?)
94// - Ronny Schulz
95// - Jakko Van Hunen
96// - Charles Godwin
97// - Henk Demper
98// - Greg Marr
99// - Bill Carducci
100// - Brian Groose
101// - MKingman
102// - Don Beusee
103//
104// REVISION HISTORY
105//
106// 2005-JAN-10 - Thanks to Don Beusee for pointing out the danger in mapping
107// length-checked formatting functions to non-length-checked
108// CRT equivalents. Also thanks to him for motivating me to
109// optimize my implementation of Replace()
110//
111// 2004-APR-22 - A big, big thank you to "MKingman" (whoever you are) for
112// finally spotting a silly little error in StdCodeCvt that
113// has been causing me (and users of CStdString) problems for
114// years in some relatively rare conversions. I had reversed
115// two length arguments.
116//
117// 2003-NOV-24 - Thanks to a bunch of people for helping me clean up many
118// compiler warnings (and yes, even a couple of actual compiler
119// errors). These include Henk Demper for figuring out how
120// to make the Intellisense work on with CStdString on VC6,
121// something I was never able to do. Greg Marr pointed out
122// a compiler warning about an unreferenced symbol and a
123// problem with my version of Load in MFC builds. Bill
124// Carducci took a lot of time with me to help me figure out
125// why some implementations of the Standard C++ Library were
126// returning error codes for apparently successful conversions
127// between ASCII and UNICODE. Finally thanks to Brian Groose
128// for helping me fix compiler signed unsigned warnings in
129// several functions.
130//
131// 2003-JUL-10 - Thanks to Charles Godwin for making me realize my 'FmtArg'
132// fixes had inadvertently broken the DLL-export code (which is
133// normally commented out. I had to move it up higher. Also
134// this helped me catch a bug in ssicoll that would prevent
135// compilation, otherwise.
136//
137// 2003-MAR-14 - Thanks to Jakko Van Hunen for pointing out a copy-and-paste
138// bug in one of the overloads of FmtArg.
139//
140// 2003-MAR-10 - Thanks to Ronny Schulz for (twice!) sending me some changes
141// to help CStdString build on SGI and for pointing out an
142// error in placement of my preprocessor macros for ssfmtmsg.
143//
144// 2002-NOV-26 - Thanks to Bagira for pointing out that my implementation of
145// SpanExcluding was not properly handling the case in which
146// the string did NOT contain any of the given characters
147//
148// 2002-OCT-21 - Many thanks to Paul DeMarco who was invaluable in helping me
149// get this code working with Borland's free compiler as well
150// as the Dev-C++ compiler (available free at SourceForge).
151//
152// 2002-SEP-13 - Thanks to Glen Maynard who helped me get rid of some loud
153// but harmless warnings that were showing up on g++. Glen
154// also pointed out that some pre-declarations of FmtArg<>
155// specializations were unnecessary (and no good on G++)
156//
157// 2002-JUN-26 - Thanks to Arnt Witteveen for pointing out that I was using
158// static_cast<> in a place in which I should have been using
159// reinterpret_cast<> (the ctor for unsigned char strings).
160// That's what happens when I don't unit-test properly!
161// Arnt also noticed that CString was silently correcting the
162// 'nCount' argument to Left() and Right() where CStdString was
163// not (and crashing if it was bad). That is also now fixed!
164//
165// 2002-FEB-25 - Thanks to Tim Dowty for pointing out (and giving me the fix
166// for) a conversion problem with non-ASCII MBCS characters.
167// CStdString is now used in my favorite commercial MP3 player!
168//
169// 2001-DEC-06 - Thanks to Wang Haifeng for spotting a problem in one of the
170// assignment operators (for _bstr_t) that would cause compiler
171// errors when refcounting protection was turned off.
172//
173// 2001-NOV-27 - Remove calls to operator!= which involve reverse_iterators
174// due to a conflict with the rel_ops operator!=. Thanks to
175// John James for pointing this out.
176//
177// 2001-OCT-29 - Added a minor range checking fix for the Mid function to
178// make it as forgiving as CString's version is. Thanks to
179// Igor Kholodov for noticing this.
180// - Added a specialization of std::swap for CStdString. Thanks
181// to Mike Crusader for suggesting this! It's commented out
182// because you're not supposed to inject your own code into the
183// 'std' namespace. But if you don't care about that, it's
184// there if you want it
185// - Thanks to Jason Mills for catching a case where CString was
186// more forgiving in the Delete() function than I was.
187//
188// 2001-JUN-06 - I was violating the Standard name lookup rules stated
189// in [14.6.2(3)]. None of the compilers I've tried so
190// far apparently caught this but HP-UX aCC 3.30 did. The
191// fix was to add 'this->' prefixes in many places.
192// Thanks to Farrokh Nejadlotfi for this!
193//
194// 2001-APR-27 - StreamLoad was calculating the number of BYTES in one
195// case, not characters. Thanks to Pablo Presedo for this.
196//
197// 2001-FEB-23 - Replace() had a bug which caused infinite loops if the
198// source string was empty. Fixed thanks to Eric Nitzsche.
199//
200// 2001-FEB-23 - Scott Hathaway was a huge help in providing me with the
201// ability to build CStdString on Sun Unix systems. He
202// sent me detailed build reports about what works and what
203// does not. If CStdString compiles on your Unix box, you
204// can thank Scott for it.
205//
206// 2000-DEC-29 - Joldakowski noticed one overload of Insert failed to do a
207// range check as CString's does. Now fixed -- thanks!
208//
209// 2000-NOV-07 - Aaron pointed out that I was calling static member
210// functions of char_traits via a temporary. This was not
211// technically wrong, but it was unnecessary and caused
212// problems for poor old buggy VC5. Thanks Aaron!
213//
214// 2000-JUL-11 - Joe Woodbury noted that the CString::Find docs don't match
215// what the CString::Find code really ends up doing. I was
216// trying to match the docs. Now I match the CString code
217// - Joe also caught me truncating strings for GetBuffer() calls
218// when the supplied length was less than the current length.
219//
220// 2000-MAY-25 - Better support for STLPORT's Standard library distribution
221// - Got rid of the NSP macro - it interfered with Koenig lookup
222// - Thanks to Joe Woodbury for catching a TrimLeft() bug that
223// I introduced in January. Empty strings were not getting
224// trimmed
225//
226// 2000-APR-17 - Thanks to Joe Vitaterna for pointing out that ReverseFind
227// is supposed to be a const function.
228//
229// 2000-MAR-07 - Thanks to Ullrich Poll�hne for catching a range bug in one
230// of the overloads of assign.
231//
232// 2000-FEB-01 - You can now use CStdString on the Mac with CodeWarrior!
233// Thanks to Todd Heckel for helping out with this.
234//
235// 2000-JAN-23 - Thanks to Jim Cline for pointing out how I could make the
236// Trim() function more efficient.
237// - Thanks to Jeff Kohn for prompting me to find and fix a typo
238// in one of the addition operators that takes _bstr_t.
239// - Got rid of the .CPP file - you only need StdString.h now!
240//
241// 1999-DEC-22 - Thanks to Greg Pickles for helping me identify a problem
242// with my implementation of CStdString::FormatV in which
243// resulting string might not be properly NULL terminated.
244//
245// 1999-DEC-06 - Chris Conti pointed yet another basic_string<> assignment
246// bug that MS has not fixed. CStdString did nothing to fix
247// it either but it does now! The bug was: create a string
248// longer than 31 characters, get a pointer to it (via c_str())
249// and then assign that pointer to the original string object.
250// The resulting string would be empty. Not with CStdString!
251//
252// 1999-OCT-06 - BufferSet was erasing the string even when it was merely
253// supposed to shrink it. Fixed. Thanks to Chris Conti.
254// - Some of the Q172398 fixes were not checking for assignment-
255// to-self. Fixed. Thanks to Baptiste Lepilleur.
256//
257// 1999-AUG-20 - Improved Load() function to be more efficient by using
258// SizeOfResource(). Thanks to Rich Zuris for this.
259// - Corrected resource ID constructor, again thanks to Rich.
260// - Fixed a bug that occurred with UNICODE characters above
261// the first 255 ANSI ones. Thanks to Craig Watson.
262// - Added missing overloads of TrimLeft() and TrimRight().
263// Thanks to Karim Ratib for pointing them out
264//
265// 1999-JUL-21 - Made all calls to GetBuf() with no args check length first.
266//
267// 1999-JUL-10 - Improved MFC/ATL independence of conversion macros
268// - Added SS_NO_REFCOUNT macro to allow you to disable any
269// reference-counting your basic_string<> impl. may do.
270// - Improved ReleaseBuffer() to be as forgiving as CString.
271// Thanks for Fan Xia for helping me find this and to
272// Matthew Williams for pointing it out directly.
273//
274// 1999-JUL-06 - Thanks to Nigel Nunn for catching a very sneaky bug in
275// ToLower/ToUpper. They should call GetBuf() instead of
276// data() in order to ensure the changed string buffer is not
277// reference-counted (in those implementations that refcount).
278//
279// 1999-JUL-01 - Added a true CString facade. Now you can use CStdString as
280// a drop-in replacement for CString. If you find this useful,
281// you can thank Chris Sells for finally convincing me to give
282// in and implement it.
283// - Changed operators << and >> (for MFC CArchive) to serialize
284// EXACTLY as CString's do. So now you can send a CString out
285// to a CArchive and later read it in as a CStdString. I have
286// no idea why you would want to do this but you can.
287//
288// 1999-JUN-21 - Changed the CStdString class into the CStdStr template.
289// - Fixed FormatV() to correctly decrement the loop counter.
290// This was harmless bug but a bug nevertheless. Thanks to
291// Chris (of Melbsys) for pointing it out
292// - Changed Format() to try a normal stack-based array before
293// using to _alloca().
294// - Updated the text conversion macros to properly use code
295// pages and to fit in better in MFC/ATL builds. In other
296// words, I copied Microsoft's conversion stuff again.
297// - Added equivalents of CString::GetBuffer, GetBufferSetLength
298// - new sscpy() replacement of CStdString::CopyString()
299// - a Trim() function that combines TrimRight() and TrimLeft().
300//
301// 1999-MAR-13 - Corrected the "NotSpace" functional object to use _istpace()
302// instead of _isspace() Thanks to Dave Plummer for this.
303//
304// 1999-FEB-26 - Removed errant line (left over from testing) that #defined
305// _MFC_VER. Thanks to John C Sipos for noticing this.
306//
307// 1999-FEB-03 - Fixed a bug in a rarely-used overload of operator+() that
308// caused infinite recursion and stack overflow
309// - Added member functions to simplify the process of
310// persisting CStdStrings to/from DCOM IStream interfaces
311// - Added functional objects (e.g. StdStringLessNoCase) that
312// allow CStdStrings to be used as keys STL map objects with
313// case-insensitive comparison
314// - Added array indexing operators (i.e. operator[]). I
315// originally assumed that these were unnecessary and would be
316// inherited from basic_string. However, without them, Visual
317// C++ complains about ambiguous overloads when you try to use
318// them. Thanks to Julian Selman to pointing this out.
319//
320// 1998-FEB-?? - Added overloads of assign() function to completely account
321// for Q172398 bug. Thanks to "Pete the Plumber" for this
322//
323// 1998-FEB-?? - Initial submission
324//
325// COPYRIGHT:
326// 2002 Joseph M. O'Leary. This code is 100% free. Use it anywhere you
327// want. Rewrite it, restructure it, whatever. If you can write software
328// that makes money off of it, good for you. I kinda like capitalism.
329// Please don't blame me if it causes your $30 billion dollar satellite
330// explode in orbit. If you redistribute it in any form, I'd appreciate it
331// if you would leave this notice here.
332// =============================================================================
333
334// Avoid multiple inclusion
335
336#ifndef STDSTRING_H
337#define STDSTRING_H
338
339// When using VC, turn off browser references
340// Turn off unavoidable compiler warnings
341
342#if defined(_MSC_VER) && (_MSC_VER > 1100)
343 #pragma component(browser, off, references, "CStdString")
344 #pragma warning (disable : 4290) // C++ Exception Specification ignored
345 #pragma warning (disable : 4127) // Conditional expression is constant
346 #pragma warning (disable : 4097) // typedef name used as synonym for class name
347#endif
348
349// Borland warnings to turn off
350
351#ifdef __BORLANDC__
352 #pragma option push -w-inl
353// #pragma warn -inl // Turn off inline function warnings
354#endif
355
356// SS_IS_INTRESOURCE
357// -----------------
358// A copy of IS_INTRESOURCE from VC7. Because old VC6 version of winuser.h
359// doesn't have this.
360
361#define SS_IS_INTRESOURCE(_r) (false)
362
363#if !defined (SS_ANSI) && defined(_MSC_VER)
364 #undef SS_IS_INTRESOURCE
365 #if defined(_WIN64)
366 #define SS_IS_INTRESOURCE(_r) (((uint64_t)(_r) >> 16) == 0)
367 #else
368 #define SS_IS_INTRESOURCE(_r) (((unsigned long)(_r) >> 16) == 0)
369 #endif
370#endif
371
372
373// MACRO: SS_UNSIGNED
374// ------------------
375// This macro causes the addition of a constructor and assignment operator
376// which take unsigned characters. CString has such functions and in order
377// to provide maximum CString-compatability, this code needs them as well.
378// In practice you will likely never need these functions...
379
380//#define SS_UNSIGNED
381
382#ifdef SS_ALLOW_UNSIGNED_CHARS
383 #define SS_UNSIGNED
384#endif
385
386// MACRO: SS_SAFE_FORMAT
387// ---------------------
388// This macro provides limited compatability with a questionable CString
389// "feature". You can define it in order to avoid a common problem that
390// people encounter when switching from CString to CStdString.
391//
392// To illustrate the problem -- With CString, you can do this:
393//
394// CString sName("Joe");
395// CString sTmp;
396// sTmp.Format("My name is %s", sName); // WORKS!
397//
398// However if you were to try this with CStdString, your program would
399// crash.
400//
401// CStdString sName("Joe");
402// CStdString sTmp;
403// sTmp.Format("My name is %s", sName); // CRASHES!
404//
405// You must explicitly call c_str() or cast the object to the proper type
406//
407// sTmp.Format("My name is %s", sName.c_str()); // WORKS!
408// sTmp.Format("My name is %s", static_cast<PCSTR>(sName));// WORKS!
409// sTmp.Format("My name is %s", (PCSTR)sName); // WORKS!
410//
411// This is because it is illegal to pass anything but a POD type as a
412// variadic argument to a variadic function (i.e. as one of the "..."
413// arguments). The type const char* is a POD type. The type CStdString
414// is not. Of course, neither is the type CString, but CString lets you do
415// it anyway due to the way they laid out the class in binary. I have no
416// control over this in CStdString since I derive from whatever
417// implementation of basic_string is available.
418//
419// However if you have legacy code (which does this) that you want to take
420// out of the MFC world and you don't want to rewrite all your calls to
421// Format(), then you can define this flag and it will no longer crash.
422//
423// Note however that this ONLY works for Format(), not sprintf, fprintf,
424// etc. If you pass a CStdString object to one of those functions, your
425// program will crash. Not much I can do to get around this, short of
426// writing substitutes for those functions as well.
427
428#define SS_SAFE_FORMAT // use new template style Format() function
429
430
431// MACRO: SS_NO_IMPLICIT_CAST
432// --------------------------
433// Some people don't like the implicit cast to const char* (or rather to
434// const CT*) that CStdString (and MFC's CString) provide. That was the
435// whole reason I created this class in the first place, but hey, whatever
436// bakes your cake. Just #define this macro to get rid of the the implicit
437// cast.
438
439//#define SS_NO_IMPLICIT_CAST // gets rid of operator const CT*()
440
441
442// MACRO: SS_NO_REFCOUNT
443// ---------------------
444// turns off reference counting at the assignment level. Only needed
445// for the version of basic_string<> that comes with Visual C++ versions
446// 6.0 or earlier, and only then in some heavily multithreaded scenarios.
447// Uncomment it if you feel you need it.
448
449//#define SS_NO_REFCOUNT
450
451// MACRO: SS_WIN32
452// ---------------
453// When this flag is set, we are building code for the Win32 platform and
454// may use Win32 specific functions (such as LoadString). This gives us
455// a couple of nice extras for the code.
456//
457// Obviously, Microsoft's is not the only compiler available for Win32 out
458// there. So I can't just check to see if _MSC_VER is defined to detect
459// if I'm building on Win32. So for now, if you use MS Visual C++ or
460// Borland's compiler, I turn this on. Otherwise you may turn it on
461// yourself, if you prefer
462
463#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(_WIN32)
464 #define SS_WIN32
465#endif
466
467// MACRO: SS_ANSI
468// --------------
469// When this macro is defined, the code attempts only to use ANSI/ISO
470// standard library functions to do it's work. It will NOT attempt to use
471// any Win32 of Visual C++ specific functions -- even if they are
472// available. You may define this flag yourself to prevent any Win32
473// of VC++ specific functions from being called.
474
475// If we're not on Win32, we MUST use an ANSI build
476
477#ifndef SS_WIN32
478 #if !defined(SS_NO_ANSI)
479 #define SS_ANSI
480 #endif
481#endif
482
483// MACRO: SS_ALLOCA
484// ----------------
485// Some implementations of the Standard C Library have a non-standard
486// function known as alloca(). This functions allows one to allocate a
487// variable amount of memory on the stack. It is needed to implement
488// the ASCII/MBCS conversion macros.
489//
490// I wanted to find some way to determine automatically if alloca() is
491// available on this platform via compiler flags but that is asking for
492// trouble. The crude test presented here will likely need fixing on
493// other platforms. Therefore I'll leave it up to you to fiddle with
494// this test to determine if it exists. Just make sure SS_ALLOCA is or
495// is not defined as appropriate and you control this feature.
496
497#if defined(_MSC_VER) && !defined(SS_ANSI)
498 #define SS_ALLOCA
499#endif
500
501
502// MACRO: SS_MBCS
503// --------------
504// Setting this macro means you are using MBCS characters. In MSVC builds,
505// this macro gets set automatically by detection of the preprocessor flag
506// _MBCS. For other platforms you may set it manually if you wish. The
507// only effect it currently has is to cause the allocation of more space
508// for wchar_t --> char conversions.
509// Note that MBCS does not mean UNICODE.
510//
511// #define SS_MBCS
512//
513
514#ifdef _MBCS
515 #define SS_MBCS
516#endif
517
518
519// MACRO SS_NO_LOCALE
520// ------------------
521// If your implementation of the Standard C++ Library lacks the <locale> header,
522// you can #define this macro to make your code build properly. Note that this
523// is some of my newest code and frankly I'm not very sure of it, though it does
524// pass my unit tests.
525
526// #define SS_NO_LOCALE
527
528
529// Compiler Error regarding _UNICODE and UNICODE
530// -----------------------------------------------
531// Microsoft header files are screwy. Sometimes they depend on a preprocessor
532// flag named "_UNICODE". Other times they check "UNICODE" (note the lack of
533// leading underscore in the second version". In several places, they silently
534// "synchronize" these two flags this by defining one of the other was defined.
535// In older version of this header, I used to try to do the same thing.
536//
537// However experience has taught me that this is a bad idea. You get weird
538// compiler errors that seem to indicate things like LPWSTR and LPTSTR not being
539// equivalent in UNICODE builds, stuff like that (when they MUST be in a proper
540// UNICODE build). You end up scratching your head and saying, "But that HAS
541// to compile!".
542//
543// So what should you do if you get this error?
544//
545// Make sure that both macros (_UNICODE and UNICODE) are defined before this
546// file is included. You can do that by either
547//
548// a) defining both yourself before any files get included
549// b) including the proper MS headers in the proper order
550// c) including this file before any other file, uncommenting
551// the #defines below, and commenting out the #errors
552//
553// Personally I recommend solution a) but it's your call.
554
555#ifdef _MSC_VER
556 #if defined (_UNICODE) && !defined (UNICODE)
557 #error UNICODE defined but not UNICODE
558 // #define UNICODE // no longer silently fix this
559 #endif
560 #if defined (UNICODE) && !defined (_UNICODE)
561 #error Warning, UNICODE defined but not _UNICODE
562 // #define _UNICODE // no longer silently fix this
563 #endif
564#endif
565
566
567// -----------------------------------------------------------------------------
568// MIN and MAX. The Standard C++ template versions go by so many names (at
569// at least in the MS implementation) that you never know what's available
570// -----------------------------------------------------------------------------
571template<class Type>
572inline const Type& SSMIN(const Type& arg1, const Type& arg2)
573{
574 return arg2 < arg1 ? arg2 : arg1;
575}
576template<class Type>
577inline const Type& SSMAX(const Type& arg1, const Type& arg2)
578{
579 return arg2 > arg1 ? arg2 : arg1;
580}
581
582// If they have not #included W32Base.h (part of my W32 utility library) then
583// we need to define some stuff. Otherwise, this is all defined there.
584
585#if !defined(W32BASE_H)
586
587 // If they want us to use only standard C++ stuff (no Win32 stuff)
588
589 #ifdef SS_ANSI
590
591 // On Win32 we have TCHAR.H so just include it. This is NOT violating
592 // the spirit of SS_ANSI as we are not calling any Win32 functions here.
593
594 #ifdef SS_WIN32
595
596 #include <TCHAR.H>
597 #include <WTYPES.H>
598 #ifndef STRICT
599 #define STRICT
600 #endif
601
602 // ... but on non-Win32 platforms, we must #define the types we need.
603
604 #else
605
606 typedef const char* PCSTR;
607 typedef char* PSTR;
608 typedef const wchar_t* PCWSTR;
609 typedef wchar_t* PWSTR;
610 #ifdef UNICODE
611 typedef wchar_t TCHAR;
612 #else
613 typedef char TCHAR;
614 #endif
615 typedef wchar_t OLECHAR;
616
617 #endif // #ifndef _WIN32
618
619
620 // Make sure ASSERT and verify are defined using only ANSI stuff
621
622 #ifndef ASSERT
623 #include <assert.h>
624 #define ASSERT(f) assert((f))
625 #endif
626 #ifndef VERIFY
627 #ifdef _DEBUG
628 #define VERIFY(x) ASSERT((x))
629 #else
630 #define VERIFY(x) x
631 #endif
632 #endif
633
634 #else // ...else SS_ANSI is NOT defined
635
636 #include <TCHAR.H>
637 #include <WTYPES.H>
638 #ifndef STRICT
639 #define STRICT
640 #endif
641
642 // Make sure ASSERT and verify are defined
643
644 #ifndef ASSERT
645 #include <crtdbg.h>
646 #define ASSERT(f) _ASSERTE((f))
647 #endif
648 #ifndef VERIFY
649 #ifdef _DEBUG
650 #define VERIFY(x) ASSERT((x))
651 #else
652 #define VERIFY(x) x
653 #endif
654 #endif
655
656 #endif // #ifdef SS_ANSI
657
658 #ifndef UNUSED
659 #define UNUSED(x) x
660 #endif
661
662#endif // #ifndef W32BASE_H
663
664// Standard headers needed
665
666#include <string> // basic_string
667#include <algorithm> // for_each, etc.
668#include <functional> // for StdStringLessNoCase, et al
669#ifndef SS_NO_LOCALE
670 #include <locale> // for various facets
671#endif
672
673// If this is a recent enough version of VC include comdef.h, so we can write
674// member functions to deal with COM types & compiler support classes e.g.
675// _bstr_t
676
677#if defined (_MSC_VER) && (_MSC_VER >= 1100)
678 #include <comdef.h>
679 #define SS_INC_COMDEF // signal that we #included MS comdef.h file
680 #define STDSTRING_INC_COMDEF
681 #define SS_NOTHROW __declspec(nothrow)
682#else
683 #define SS_NOTHROW
684#endif
685
686#ifndef TRACE
687 #define TRACE_DEFINED_HERE
688 #define TRACE
689#endif
690
691// Microsoft defines PCSTR, PCWSTR, etc, but no PCTSTR. I hate to use the
692// versions with the "L" in front of them because that's a leftover from Win 16
693// days, even though it evaluates to the same thing. Therefore, Define a PCSTR
694// as an LPCTSTR.
695
696#if !defined(PCTSTR) && !defined(PCTSTR_DEFINED)
697 typedef const TCHAR* PCTSTR;
698 #define PCTSTR_DEFINED
699#endif
700
701#if !defined(PCOLESTR) && !defined(PCOLESTR_DEFINED)
702 typedef const OLECHAR* PCOLESTR;
703 #define PCOLESTR_DEFINED
704#endif
705
706#if !defined(POLESTR) && !defined(POLESTR_DEFINED)
707 typedef OLECHAR* POLESTR;
708 #define POLESTR_DEFINED
709#endif
710
711#if !defined(PCUSTR) && !defined(PCUSTR_DEFINED)
712 typedef const unsigned char* PCUSTR;
713 typedef unsigned char* PUSTR;
714 #define PCUSTR_DEFINED
715#endif
716
717
718// SGI compiler 7.3 doesnt know these types - oh and btw, remember to use
719// -LANG:std in the CXX Flags
720#if defined(__sgi)
721 typedef unsigned long DWORD;
722 typedef void * LPCVOID;
723#endif
724
725
726// SS_USE_FACET macro and why we need it:
727//
728// Since I'm a good little Standard C++ programmer, I use locales. Thus, I
729// need to make use of the use_facet<> template function here. Unfortunately,
730// this need is complicated by the fact the MS' implementation of the Standard
731// C++ Library has a non-standard version of use_facet that takes more
732// arguments than the standard dictates. Since I'm trying to write CStdString
733// to work with any version of the Standard library, this presents a problem.
734//
735// The upshot of this is that I can't do 'use_facet' directly. The MS' docs
736// tell me that I have to use a macro, _USE() instead. Since _USE obviously
737// won't be available in other implementations, this means that I have to write
738// my OWN macro -- SS_USE_FACET -- that evaluates either to _USE or to the
739// standard, use_facet.
740//
741// If you are having trouble with the SS_USE_FACET macro, in your implementation
742// of the Standard C++ Library, you can define your own version of SS_USE_FACET.
743
744#ifndef schMSG
745 #define schSTR(x) #x
746 #define schSTR2(x) schSTR(x)
747 #define schMSG(desc) message(__FILE__ "(" schSTR2(__LINE__) "):" #desc)
748#endif
749
750#ifndef SS_USE_FACET
751
752 // STLPort #defines a macro (__STL_NO_EXPLICIT_FUNCTION_TMPL_ARGS) for
753 // all MSVC builds, erroneously in my opinion. It causes problems for
754 // my SS_ANSI builds. In my code, I always comment out that line. You'll
755 // find it in \stlport\config\stl_msvc.h
756
757 #if defined(__SGI_STL_PORT) && (__SGI_STL_PORT >= 0x400 )
758
759 #if defined(__STL_NO_EXPLICIT_FUNCTION_TMPL_ARGS) && defined(_MSC_VER)
760 #ifdef SS_ANSI
761 #pragma schMSG(__STL_NO_EXPLICIT_FUNCTION_TMPL_ARGS defined!!)
762 #endif
763 #endif
764 #define SS_USE_FACET(loc, fac) std::use_facet<fac >(loc)
765
766 #elif defined(_MSC_VER )
767
768 #define SS_USE_FACET(loc, fac) std::_USE(loc, fac)
769
770 // ...and
771 #elif defined(_RWSTD_NO_TEMPLATE_ON_RETURN_TYPE)
772
773 #define SS_USE_FACET(loc, fac) std::use_facet(loc, (fac*)0)
774
775 #else
776
777 #define SS_USE_FACET(loc, fac) std::use_facet<fac >(loc)
778
779 #endif
780
781#endif
782
783// =============================================================================
784// UNICODE/MBCS conversion macros. Made to work just like the MFC/ATL ones.
785// =============================================================================
786
787#include <wchar.h> // Added to Std Library with Amendment #1.
788
789// First define the conversion helper functions. We define these regardless of
790// any preprocessor macro settings since their names won't collide.
791
792// Not sure if we need all these headers. I believe ANSI says we do.
793
794#include <stdio.h>
795#include <stdarg.h>
796#include <wctype.h>
797#include <ctype.h>
798#include <stdlib.h>
799#ifndef va_start
800 #include <varargs.h>
801#endif
802
803
804#ifdef SS_NO_LOCALE
805
806 #if defined(_WIN32) || defined (_WIN32_WCE)
807
808 inline PWSTR StdCodeCvt(PWSTR pDstW, int nDst, PCSTR pSrcA, int nSrc,
809 UINT acp=CP_ACP)
810 {
811 ASSERT(0 != pSrcA);
812 ASSERT(0 != pDstW);
813 pDstW[0] = '\0';
814 MultiByteToWideChar(acp, 0, pSrcA, nSrc, pDstW, nDst);
815 return pDstW;
816 }
817 inline PWSTR StdCodeCvt(PWSTR pDstW, int nDst, PCUSTR pSrcA, int nSrc,
818 UINT acp=CP_ACP)
819 {
820 return StdCodeCvt(pDstW, nDst, (PCSTR)pSrcA, nSrc, acp);
821 }
822
823 inline PSTR StdCodeCvt(PSTR pDstA, int nDst, PCWSTR pSrcW, int nSrc,
824 UINT acp=CP_ACP)
825 {
826 ASSERT(0 != pDstA);
827 ASSERT(0 != pSrcW);
828 pDstA[0] = '\0';
829 WideCharToMultiByte(acp, 0, pSrcW, nSrc, pDstA, nDst, 0, 0);
830 return pDstA;
831 }
832 inline PUSTR StdCodeCvt(PUSTR pDstA, int nDst, PCWSTR pSrcW, int nSrc,
833 UINT acp=CP_ACP)
834 {
835 return (PUSTR)StdCodeCvt((PSTR)pDstA, nDst, pSrcW, nSrc, acp);
836 }
837 #else
838 #endif
839
840#else
841
842 // StdCodeCvt - made to look like Win32 functions WideCharToMultiByte
843 // and MultiByteToWideChar but uses locales in SS_ANSI
844 // builds. There are a number of overloads.
845 // First argument is the destination buffer.
846 // Second argument is the source buffer
847 //#if defined (SS_ANSI) || !defined (SS_WIN32)
848
849 // 'SSCodeCvt' - shorthand name for the codecvt facet we use
850
851 typedef std::codecvt<wchar_t, char, mbstate_t> SSCodeCvt;
852
853 inline PWSTR StdCodeCvt(PWSTR pDstW, int nDst, PCSTR pSrcA, int nSrc,
854 const std::locale& loc=std::locale())
855 {
856 ASSERT(0 != pSrcA);
857 ASSERT(0 != pDstW);
858
859 pDstW[0] = '\0';
860
861 if ( nSrc > 0 )
862 {
863 PCSTR pNextSrcA = pSrcA;
864 PWSTR pNextDstW = pDstW;
865 SSCodeCvt::result res = SSCodeCvt::ok;
866 const SSCodeCvt& conv = SS_USE_FACET(loc, SSCodeCvt);
867#if defined(TARGET_DARWIN) || defined(__FreeBSD__) || defined(TARGET_ANDROID)
868 SSCodeCvt::state_type st= { { 0 } };
869#else
870 SSCodeCvt::state_type st= { 0 };
871#endif
872 res = conv.in(st,
873 pSrcA, pSrcA + nSrc, pNextSrcA,
874 pDstW, pDstW + nDst, pNextDstW);
875#ifdef _LINUX
876#define ASSERT2(a) if (!(a)) {fprintf(stderr, "StdString: Assertion Failed on line %d\n", __LINE__);}
877#else
878#define ASSERT2 ASSERT
879#endif
880 ASSERT2(SSCodeCvt::ok == res);
881 ASSERT2(SSCodeCvt::error != res);
882 ASSERT2(pNextDstW >= pDstW);
883 ASSERT2(pNextSrcA >= pSrcA);
884#undef ASSERT2
885 // Null terminate the converted string
886
887 if ( pNextDstW - pDstW > nDst )
888 *(pDstW + nDst) = '\0';
889 else
890 *pNextDstW = '\0';
891 }
892 return pDstW;
893 }
894 inline PWSTR StdCodeCvt(PWSTR pDstW, int nDst, PCUSTR pSrcA, int nSrc,
895 const std::locale& loc=std::locale())
896 {
897 return StdCodeCvt(pDstW, nDst, (PCSTR)pSrcA, nSrc, loc);
898 }
899
900 inline PSTR StdCodeCvt(PSTR pDstA, int nDst, PCWSTR pSrcW, int nSrc,
901 const std::locale& loc=std::locale())
902 {
903 ASSERT(0 != pDstA);
904 ASSERT(0 != pSrcW);
905
906 pDstA[0] = '\0';
907
908 if ( nSrc > 0 )
909 {
910 PSTR pNextDstA = pDstA;
911 PCWSTR pNextSrcW = pSrcW;
912 SSCodeCvt::result res = SSCodeCvt::ok;
913 const SSCodeCvt& conv = SS_USE_FACET(loc, SSCodeCvt);
914#if defined(TARGET_DARWIN) || defined(__FreeBSD__) || defined(TARGET_ANDROID)
915 SSCodeCvt::state_type st= { { 0 } };
916#else
917 SSCodeCvt::state_type st= { 0 };
918#endif
919 res = conv.out(st,
920 pSrcW, pSrcW + nSrc, pNextSrcW,
921 pDstA, pDstA + nDst, pNextDstA);
922#ifdef _LINUX
923#define ASSERT2(a) if (!(a)) {fprintf(stderr, "StdString: Assertion Failed on line %d\n", __LINE__);}
924#else
925#define ASSERT2 ASSERT
926#endif
927 ASSERT2(SSCodeCvt::error != res);
928 ASSERT2(SSCodeCvt::ok == res); // strict, comment out for sanity
929 ASSERT2(pNextDstA >= pDstA);
930 ASSERT2(pNextSrcW >= pSrcW);
931#undef ASSERT2
932
933 // Null terminate the converted string
934
935 if ( pNextDstA - pDstA > nDst )
936 *(pDstA + nDst) = '\0';
937 else
938 *pNextDstA = '\0';
939 }
940 return pDstA;
941 }
942
943 inline PUSTR StdCodeCvt(PUSTR pDstA, int nDst, PCWSTR pSrcW, int nSrc,
944 const std::locale& loc=std::locale())
945 {
946 return (PUSTR)StdCodeCvt((PSTR)pDstA, nDst, pSrcW, nSrc, loc);
947 }
948
949#endif
950
951
952
953// Unicode/MBCS conversion macros are only available on implementations of
954// the "C" library that have the non-standard _alloca function. As far as I
955// know that's only Microsoft's though I've heard that the function exists
956// elsewhere.
957
958#if defined(SS_ALLOCA) && !defined SS_NO_CONVERSION
959
960 #include <malloc.h> // needed for _alloca
961
962 // Define our conversion macros to look exactly like Microsoft's to
963 // facilitate using this stuff both with and without MFC/ATL
964
965 #ifdef _CONVERSION_USES_THREAD_LOCALE
966
967 #ifndef _DEBUG
968 #define SSCVT int _cvt; _cvt; UINT _acp=GetACP(); \
969 _acp; PCWSTR _pw; _pw; PCSTR _pa; _pa
970 #else
971 #define SSCVT int _cvt = 0; _cvt; UINT _acp=GetACP();\
972 _acp; PCWSTR _pw=0; _pw; PCSTR _pa=0; _pa
973 #endif
974 #define SSA2W(pa) (\
975 ((_pa = pa) == 0) ? 0 : (\
976 _cvt = (sslen(_pa)),\
977 StdCodeCvt((PWSTR) _alloca((_cvt+1)*2), (_cvt+1)*2, \
978 _pa, _cvt, _acp)))
979 #define SSW2A(pw) (\
980 ((_pw = pw) == 0) ? 0 : (\
981 _cvt = sslen(_pw), \
982 StdCodeCvt((LPSTR) _alloca((_cvt+1)*2), (_cvt+1)*2, \
983 _pw, _cvt, _acp)))
984 #else
985
986 #ifndef _DEBUG
987 #define SSCVT int _cvt; _cvt; UINT _acp=CP_ACP; _acp;\
988 PCWSTR _pw; _pw; PCSTR _pa; _pa
989 #else
990 #define SSCVT int _cvt = 0; _cvt; UINT _acp=CP_ACP; \
991 _acp; PCWSTR _pw=0; _pw; PCSTR _pa=0; _pa
992 #endif
993 #define SSA2W(pa) (\
994 ((_pa = pa) == 0) ? 0 : (\
995 _cvt = (sslen(_pa)),\
996 StdCodeCvt((PWSTR) _alloca((_cvt+1)*2), (_cvt+1)*2, \
997 _pa, _cvt)))
998 #define SSW2A(pw) (\
999 ((_pw = pw) == 0) ? 0 : (\
1000 _cvt = (sslen(_pw)),\
1001 StdCodeCvt((LPSTR) _alloca((_cvt+1)*2), (_cvt+1)*2, \
1002 _pw, _cvt)))
1003 #endif
1004
1005 #define SSA2CW(pa) ((PCWSTR)SSA2W((pa)))
1006 #define SSW2CA(pw) ((PCSTR)SSW2A((pw)))
1007
1008 #ifdef UNICODE
1009 #define SST2A SSW2A
1010 #define SSA2T SSA2W
1011 #define SST2CA SSW2CA
1012 #define SSA2CT SSA2CW
1013 // (Did you get a compiler error here about not being able to convert
1014 // PTSTR into PWSTR? Then your _UNICODE and UNICODE flags are messed
1015 // up. Best bet: #define BOTH macros before including any MS headers.)
1016 inline PWSTR SST2W(PTSTR p) { return p; }
1017 inline PTSTR SSW2T(PWSTR p) { return p; }
1018 inline PCWSTR SST2CW(PCTSTR p) { return p; }
1019 inline PCTSTR SSW2CT(PCWSTR p) { return p; }
1020 #else
1021 #define SST2W SSA2W
1022 #define SSW2T SSW2A
1023 #define SST2CW SSA2CW
1024 #define SSW2CT SSW2CA
1025 inline PSTR SST2A(PTSTR p) { return p; }
1026 inline PTSTR SSA2T(PSTR p) { return p; }
1027 inline PCSTR SST2CA(PCTSTR p) { return p; }
1028 inline PCTSTR SSA2CT(PCSTR p) { return p; }
1029 #endif // #ifdef UNICODE
1030
1031 #if defined(UNICODE)
1032 // in these cases the default (TCHAR) is the same as OLECHAR
1033 inline PCOLESTR SST2COLE(PCTSTR p) { return p; }
1034 inline PCTSTR SSOLE2CT(PCOLESTR p) { return p; }
1035 inline POLESTR SST2OLE(PTSTR p) { return p; }
1036 inline PTSTR SSOLE2T(POLESTR p) { return p; }
1037 #elif defined(OLE2ANSI)
1038 // in these cases the default (TCHAR) is the same as OLECHAR
1039 inline PCOLESTR SST2COLE(PCTSTR p) { return p; }
1040 inline PCTSTR SSOLE2CT(PCOLESTR p) { return p; }
1041 inline POLESTR SST2OLE(PTSTR p) { return p; }
1042 inline PTSTR SSOLE2T(POLESTR p) { return p; }
1043 #else
1044 //CharNextW doesn't work on Win95 so we use this
1045 #define SST2COLE(pa) SSA2CW((pa))
1046 #define SST2OLE(pa) SSA2W((pa))
1047 #define SSOLE2CT(po) SSW2CA((po))
1048 #define SSOLE2T(po) SSW2A((po))
1049 #endif
1050
1051 #ifdef OLE2ANSI
1052 #define SSW2OLE SSW2A
1053 #define SSOLE2W SSA2W
1054 #define SSW2COLE SSW2CA
1055 #define SSOLE2CW SSA2CW
1056 inline POLESTR SSA2OLE(PSTR p) { return p; }
1057 inline PSTR SSOLE2A(POLESTR p) { return p; }
1058 inline PCOLESTR SSA2COLE(PCSTR p) { return p; }
1059 inline PCSTR SSOLE2CA(PCOLESTR p){ return p; }
1060 #else
1061 #define SSA2OLE SSA2W
1062 #define SSOLE2A SSW2A
1063 #define SSA2COLE SSA2CW
1064 #define SSOLE2CA SSW2CA
1065 inline POLESTR SSW2OLE(PWSTR p) { return p; }
1066 inline PWSTR SSOLE2W(POLESTR p) { return p; }
1067 inline PCOLESTR SSW2COLE(PCWSTR p) { return p; }
1068 inline PCWSTR SSOLE2CW(PCOLESTR p){ return p; }
1069 #endif
1070
1071 // Above we've defined macros that look like MS' but all have
1072 // an 'SS' prefix. Now we need the real macros. We'll either
1073 // get them from the macros above or from MFC/ATL.
1074
1075 #if defined (USES_CONVERSION)
1076
1077 #define _NO_STDCONVERSION // just to be consistent
1078
1079 #else
1080
1081 #ifdef _MFC_VER
1082
1083 #include <afxconv.h>
1084 #define _NO_STDCONVERSION // just to be consistent
1085
1086 #else
1087
1088 #define USES_CONVERSION SSCVT
1089 #define A2CW SSA2CW
1090 #define W2CA SSW2CA
1091 #define T2A SST2A
1092 #define A2T SSA2T
1093 #define T2W SST2W
1094 #define W2T SSW2T
1095 #define T2CA SST2CA
1096 #define A2CT SSA2CT
1097 #define T2CW SST2CW
1098 #define W2CT SSW2CT
1099 #define ocslen sslen
1100 #define ocscpy sscpy
1101 #define T2COLE SST2COLE
1102 #define OLE2CT SSOLE2CT
1103 #define T2OLE SST2COLE
1104 #define OLE2T SSOLE2CT
1105 #define A2OLE SSA2OLE
1106 #define OLE2A SSOLE2A
1107 #define W2OLE SSW2OLE
1108 #define OLE2W SSOLE2W
1109 #define A2COLE SSA2COLE
1110 #define OLE2CA SSOLE2CA
1111 #define W2COLE SSW2COLE
1112 #define OLE2CW SSOLE2CW
1113
1114 #endif // #ifdef _MFC_VER
1115 #endif // #ifndef USES_CONVERSION
1116#endif // #ifndef SS_NO_CONVERSION
1117
1118// Define ostring - generic name for std::basic_string<OLECHAR>
1119
1120#if !defined(ostring) && !defined(OSTRING_DEFINED)
1121 typedef std::basic_string<OLECHAR> ostring;
1122 #define OSTRING_DEFINED
1123#endif
1124
1125// StdCodeCvt when there's no conversion to be done
1126template <typename T>
1127inline T* StdCodeCvt(T* pDst, int nDst, const T* pSrc, int nSrc)
1128{
1129 int nChars = SSMIN(nSrc, nDst);
1130
1131 if ( nChars > 0 )
1132 {
1133 pDst[0] = '\0';
1134 std::basic_string<T>::traits_type::copy(pDst, pSrc, nChars);
1135// std::char_traits<T>::copy(pDst, pSrc, nChars);
1136 pDst[nChars] = '\0';
1137 }
1138
1139 return pDst;
1140}
1141inline PSTR StdCodeCvt(PSTR pDst, int nDst, PCUSTR pSrc, int nSrc)
1142{
1143 return StdCodeCvt(pDst, nDst, (PCSTR)pSrc, nSrc);
1144}
1145inline PUSTR StdCodeCvt(PUSTR pDst, int nDst, PCSTR pSrc, int nSrc)
1146{
1147 return (PUSTR)StdCodeCvt((PSTR)pDst, nDst, pSrc, nSrc);
1148}
1149
1150// Define tstring -- generic name for std::basic_string<TCHAR>
1151
1152#if !defined(tstring) && !defined(TSTRING_DEFINED)
1153 typedef std::basic_string<TCHAR> tstring;
1154 #define TSTRING_DEFINED
1155#endif
1156
1157// a very shorthand way of applying the fix for KB problem Q172398
1158// (basic_string assignment bug)
1159
1160#if defined ( _MSC_VER ) && ( _MSC_VER < 1200 )
1161 #define Q172398(x) (x).erase()
1162#else
1163 #define Q172398(x)
1164#endif
1165
1166// =============================================================================
1167// INLINE FUNCTIONS ON WHICH CSTDSTRING RELIES
1168//
1169// Usually for generic text mapping, we rely on preprocessor macro definitions
1170// to map to string functions. However the CStdStr<> template cannot use
1171// macro-based generic text mappings because its character types do not get
1172// resolved until template processing which comes AFTER macro processing. In
1173// other words, the preprocessor macro UNICODE is of little help to us in the
1174// CStdStr template
1175//
1176// Therefore, to keep the CStdStr declaration simple, we have these inline
1177// functions. The template calls them often. Since they are inline (and NOT
1178// exported when this is built as a DLL), they will probably be resolved away
1179// to nothing.
1180//
1181// Without these functions, the CStdStr<> template would probably have to broken
1182// out into two, almost identical classes. Either that or it would be a huge,
1183// convoluted mess, with tons of "if" statements all over the place checking the
1184// size of template parameter CT.
1185// =============================================================================
1186
1187#ifdef SS_NO_LOCALE
1188
1189 // --------------------------------------------------------------------------
1190 // Win32 GetStringTypeEx wrappers
1191 // --------------------------------------------------------------------------
1192 inline bool wsGetStringType(LCID lc, DWORD dwT, PCSTR pS, int nSize,
1193 WORD* pWd)
1194 {
1195 return FALSE != GetStringTypeExA(lc, dwT, pS, nSize, pWd);
1196 }
1197 inline bool wsGetStringType(LCID lc, DWORD dwT, PCWSTR pS, int nSize,
1198 WORD* pWd)
1199 {
1200 return FALSE != GetStringTypeExW(lc, dwT, pS, nSize, pWd);
1201 }
1202
1203
1204 template<typename CT>
1205 inline bool ssisspace (CT t)
1206 {
1207 WORD toYourMother;
1208 return wsGetStringType(GetThreadLocale(), CT_CTYPE1, &t, 1, &toYourMother)
1209 && 0 != (C1_BLANK & toYourMother);
1210 }
1211
1212#endif
1213
1214// If they defined SS_NO_REFCOUNT, then we must convert all assignments
1215
1216#if defined (_MSC_VER) && (_MSC_VER < 1300)
1217 #ifdef SS_NO_REFCOUNT
1218 #define SSREF(x) (x).c_str()
1219 #else
1220 #define SSREF(x) (x)
1221 #endif
1222#else
1223 #define SSREF(x) (x)
1224#endif
1225
1226// -----------------------------------------------------------------------------
1227// sslen: strlen/wcslen wrappers
1228// -----------------------------------------------------------------------------
1229template<typename CT> inline int sslen(const CT* pT)
1230{
1231 return 0 == pT ? 0 : (int)std::basic_string<CT>::traits_type::length(pT);
1232// return 0 == pT ? 0 : std::char_traits<CT>::length(pT);
1233}
1234inline SS_NOTHROW int sslen(const std::string& s)
1235{
1236 return static_cast<int>(s.length());
1237}
1238inline SS_NOTHROW int sslen(const std::wstring& s)
1239{
1240 return static_cast<int>(s.length());
1241}
1242
1243// -----------------------------------------------------------------------------
1244// sstolower/sstoupper -- convert characters to upper/lower case
1245// -----------------------------------------------------------------------------
1246
1247#ifdef SS_NO_LOCALE
1248 inline char sstoupper(char ch) { return (char)::toupper(ch); }
1249 inline wchar_t sstoupper(wchar_t ch){ return (wchar_t)::towupper(ch); }
1250 inline char sstolower(char ch) { return (char)::tolower(ch); }
1251 inline wchar_t sstolower(wchar_t ch){ return (wchar_t)::tolower(ch); }
1252#else
1253 template<typename CT>
1254 inline CT sstolower(const CT& t, const std::locale& loc = std::locale())
1255 {
1256 return std::tolower<CT>(t, loc);
1257 }
1258 template<typename CT>
1259 inline CT sstoupper(const CT& t, const std::locale& loc = std::locale())
1260 {
1261 return std::toupper<CT>(t, loc);
1262 }
1263#endif
1264
1265// -----------------------------------------------------------------------------
1266// ssasn: assignment functions -- assign "sSrc" to "sDst"
1267// -----------------------------------------------------------------------------
1268typedef std::string::size_type SS_SIZETYPE; // just for shorthand, really
1269typedef std::string::pointer SS_PTRTYPE;
1270typedef std::wstring::size_type SW_SIZETYPE;
1271typedef std::wstring::pointer SW_PTRTYPE;
1272
1273
1274template <typename T>
1275inline void ssasn(std::basic_string<T>& sDst, const std::basic_string<T>& sSrc)
1276{
1277 if ( sDst.c_str() != sSrc.c_str() )
1278 {
1279 sDst.erase();
1280 sDst.assign(SSREF(sSrc));
1281 }
1282}
1283template <typename T>
1284inline void ssasn(std::basic_string<T>& sDst, const T *pA)
1285{
1286 // Watch out for NULLs, as always.
1287
1288 if ( 0 == pA )
1289 {
1290 sDst.erase();
1291 }
1292
1293 // If pA actually points to part of sDst, we must NOT erase(), but
1294 // rather take a substring
1295
1296 else if ( pA >= sDst.c_str() && pA <= sDst.c_str() + sDst.size() )
1297 {
1298 sDst =sDst.substr(static_cast<typename std::basic_string<T>::size_type>(pA-sDst.c_str()));
1299 }
1300
1301 // Otherwise (most cases) apply the assignment bug fix, if applicable
1302 // and do the assignment
1303
1304 else
1305 {
1306 Q172398(sDst);
1307 sDst.assign(pA);
1308 }
1309}
1310inline void ssasn(std::string& sDst, const std::wstring& sSrc)
1311{
1312 if ( sSrc.empty() )
1313 {
1314 sDst.erase();
1315 }
1316 else
1317 {
1318 int nDst = static_cast<int>(sSrc.size());
1319
1320 // In MBCS builds, pad the buffer to account for the possibility of
1321 // some 3 byte characters. Not perfect but should get most cases.
1322
1323#ifdef SS_MBCS
1324 // In MBCS builds, we don't know how long the destination string will be.
1325 nDst = static_cast<int>(static_cast<double>(nDst) * 1.3);
1326 sDst.resize(nDst+1);
1327 PCSTR szCvt = StdCodeCvt(const_cast<SS_PTRTYPE>(sDst.data()), nDst,
1328 sSrc.c_str(), static_cast<int>(sSrc.size()));
1329 sDst.resize(sslen(szCvt));
1330#else
1331 sDst.resize(nDst+1);
1332 StdCodeCvt(const_cast<SS_PTRTYPE>(sDst.data()), nDst,
1333 sSrc.c_str(), static_cast<int>(sSrc.size()));
1334 sDst.resize(sSrc.size());
1335#endif
1336 }
1337}
1338inline void ssasn(std::string& sDst, PCWSTR pW)
1339{
1340 int nSrc = sslen(pW);
1341 if ( nSrc > 0 )
1342 {
1343 int nSrc = sslen(pW);
1344 int nDst = nSrc;
1345
1346 // In MBCS builds, pad the buffer to account for the possibility of
1347 // some 3 byte characters. Not perfect but should get most cases.
1348
1349#ifdef SS_MBCS
1350 nDst = static_cast<int>(static_cast<double>(nDst) * 1.3);
1351 // In MBCS builds, we don't know how long the destination string will be.
1352 sDst.resize(nDst + 1);
1353 PCSTR szCvt = StdCodeCvt(const_cast<SS_PTRTYPE>(sDst.data()), nDst,
1354 pW, nSrc);
1355 sDst.resize(sslen(szCvt));
1356#else
1357 sDst.resize(nDst + 1);
1358 StdCodeCvt(const_cast<SS_PTRTYPE>(sDst.data()), nDst, pW, nSrc);
1359 sDst.resize(nDst);
1360#endif
1361 }
1362 else
1363 {
1364 sDst.erase();
1365 }
1366}
1367inline void ssasn(std::string& sDst, const int nNull)
1368{
1369 //UNUSED(nNull);
1370 ASSERT(nNull==0);
1371 sDst.assign("");
1372}
1373#undef StrSizeType
1374inline void ssasn(std::wstring& sDst, const std::string& sSrc)
1375{
1376 if ( sSrc.empty() )
1377 {
1378 sDst.erase();
1379 }
1380 else
1381 {
1382 int nSrc = static_cast<int>(sSrc.size());
1383 int nDst = nSrc;
1384
1385 sDst.resize(nSrc+1);
1386 PCWSTR szCvt = StdCodeCvt(const_cast<SW_PTRTYPE>(sDst.data()), nDst,
1387 sSrc.c_str(), nSrc);
1388
1389 sDst.resize(sslen(szCvt));
1390 }
1391}
1392inline void ssasn(std::wstring& sDst, PCSTR pA)
1393{
1394 int nSrc = sslen(pA);
1395
1396 if ( 0 == nSrc )
1397 {
1398 sDst.erase();
1399 }
1400 else
1401 {
1402 int nDst = nSrc;
1403 sDst.resize(nDst+1);
1404 PCWSTR szCvt = StdCodeCvt(const_cast<SW_PTRTYPE>(sDst.data()), nDst, pA,
1405 nSrc);
1406
1407 sDst.resize(sslen(szCvt));
1408 }
1409}
1410inline void ssasn(std::wstring& sDst, const int nNull)
1411{
1412 //UNUSED(nNull);
1413 ASSERT(nNull==0);
1414 sDst.assign(L"");
1415}
1416
1417// -----------------------------------------------------------------------------
1418// ssadd: string object concatenation -- add second argument to first
1419// -----------------------------------------------------------------------------
1420inline void ssadd(std::string& sDst, const std::wstring& sSrc)
1421{
1422 int nSrc = static_cast<int>(sSrc.size());
1423
1424 if ( nSrc > 0 )
1425 {
1426 int nDst = static_cast<int>(sDst.size());
1427 int nAdd = nSrc;
1428
1429 // In MBCS builds, pad the buffer to account for the possibility of
1430 // some 3 byte characters. Not perfect but should get most cases.
1431
1432#ifdef SS_MBCS
1433 nAdd = static_cast<int>(static_cast<double>(nAdd) * 1.3);
1434 sDst.resize(nDst+nAdd+1);
1435 PCSTR szCvt = StdCodeCvt(const_cast<SS_PTRTYPE>(sDst.data()+nDst),
1436 nAdd, sSrc.c_str(), nSrc);
1437 sDst.resize(nDst + sslen(szCvt));
1438#else
1439 sDst.resize(nDst+nAdd+1);
1440 StdCodeCvt(const_cast<SS_PTRTYPE>(sDst.data()+nDst), nAdd, sSrc.c_str(), nSrc);
1441 sDst.resize(nDst + nAdd);
1442#endif
1443 }
1444}
1445template <typename T>
1446inline void ssadd(typename std::basic_string<T>& sDst, const typename std::basic_string<T>& sSrc)
1447{
1448 sDst += sSrc;
1449}
1450inline void ssadd(std::string& sDst, PCWSTR pW)
1451{
1452 int nSrc = sslen(pW);
1453 if ( nSrc > 0 )
1454 {
1455 int nDst = static_cast<int>(sDst.size());
1456 int nAdd = nSrc;
1457
1458#ifdef SS_MBCS
1459 nAdd = static_cast<int>(static_cast<double>(nAdd) * 1.3);
1460 sDst.resize(nDst + nAdd + 1);
1461 PCSTR szCvt = StdCodeCvt(const_cast<SS_PTRTYPE>(sDst.data()+nDst),
1462 nAdd, pW, nSrc);
1463 sDst.resize(nDst + sslen(szCvt));
1464#else
1465 sDst.resize(nDst + nAdd + 1);
1466 StdCodeCvt(const_cast<SS_PTRTYPE>(sDst.data()+nDst), nAdd, pW, nSrc);
1467 sDst.resize(nDst + nSrc);
1468#endif
1469 }
1470}
1471template <typename T>
1472inline void ssadd(typename std::basic_string<T>& sDst, const T *pA)
1473{
1474 if ( pA )
1475 {
1476 // If the string being added is our internal string or a part of our
1477 // internal string, then we must NOT do any reallocation without
1478 // first copying that string to another object (since we're using a
1479 // direct pointer)
1480
1481 if ( pA >= sDst.c_str() && pA <= sDst.c_str()+sDst.length())
1482 {
1483 if ( sDst.capacity() <= sDst.size()+sslen(pA) )
1484 sDst.append(std::basic_string<T>(pA));
1485 else
1486 sDst.append(pA);
1487 }
1488 else
1489 {
1490 sDst.append(pA);
1491 }
1492 }
1493}
1494inline void ssadd(std::wstring& sDst, const std::string& sSrc)
1495{
1496 if ( !sSrc.empty() )
1497 {
1498 int nSrc = static_cast<int>(sSrc.size());
1499 int nDst = static_cast<int>(sDst.size());
1500
1501 sDst.resize(nDst + nSrc + 1);
1502#ifdef SS_MBCS
1503 PCWSTR szCvt = StdCodeCvt(const_cast<SW_PTRTYPE>(sDst.data()+nDst),
1504 nSrc, sSrc.c_str(), nSrc+1);
1505 sDst.resize(nDst + sslen(szCvt));
1506#else
1507 StdCodeCvt(const_cast<SW_PTRTYPE>(sDst.data()+nDst), nSrc, sSrc.c_str(), nSrc+1);
1508 sDst.resize(nDst + nSrc);
1509#endif
1510 }
1511}
1512inline void ssadd(std::wstring& sDst, PCSTR pA)
1513{
1514 int nSrc = sslen(pA);
1515
1516 if ( nSrc > 0 )
1517 {
1518 int nDst = static_cast<int>(sDst.size());
1519
1520 sDst.resize(nDst + nSrc + 1);
1521#ifdef SS_MBCS
1522 PCWSTR szCvt = StdCodeCvt(const_cast<SW_PTRTYPE>(sDst.data()+nDst),
1523 nSrc, pA, nSrc+1);
1524 sDst.resize(nDst + sslen(szCvt));
1525#else
1526 StdCodeCvt(const_cast<SW_PTRTYPE>(sDst.data()+nDst), nSrc, pA, nSrc+1);
1527 sDst.resize(nDst + nSrc);
1528#endif
1529 }
1530}
1531
1532// -----------------------------------------------------------------------------
1533// sscmp: comparison (case sensitive, not affected by locale)
1534// -----------------------------------------------------------------------------
1535template<typename CT>
1536inline int sscmp(const CT* pA1, const CT* pA2)
1537{
1538 CT f;
1539 CT l;
1540
1541 do
1542 {
1543 f = *(pA1++);
1544 l = *(pA2++);
1545 } while ( (f) && (f == l) );
1546
1547 return (int)(f - l);
1548}
1549
1550// -----------------------------------------------------------------------------
1551// ssicmp: comparison (case INsensitive, not affected by locale)
1552// -----------------------------------------------------------------------------
1553template<typename CT>
1554inline int ssicmp(const CT* pA1, const CT* pA2)
1555{
1556 // Using the "C" locale = "not affected by locale"
1557
1558 std::locale loc = std::locale::classic();
1559 const std::ctype<CT>& ct = SS_USE_FACET(loc, std::ctype<CT>);
1560 CT f;
1561 CT l;
1562
1563 do
1564 {
1565 f = ct.tolower(*(pA1++));
1566 l = ct.tolower(*(pA2++));
1567 } while ( (f) && (f == l) );
1568
1569 return (int)(f - l);
1570}
1571
1572// -----------------------------------------------------------------------------
1573// ssupr/sslwr: Uppercase/Lowercase conversion functions
1574// -----------------------------------------------------------------------------
1575
1576template<typename CT>
1577inline void sslwr(CT* pT, size_t nLen, const std::locale& loc=std::locale())
1578{
1579 SS_USE_FACET(loc, std::ctype<CT>).tolower(pT, pT+nLen);
1580}
1581template<typename CT>
1582inline void ssupr(CT* pT, size_t nLen, const std::locale& loc=std::locale())
1583{
1584 SS_USE_FACET(loc, std::ctype<CT>).toupper(pT, pT+nLen);
1585}
1586
1587// -----------------------------------------------------------------------------
1588// vsprintf/vswprintf or _vsnprintf/_vsnwprintf equivalents. In standard
1589// builds we can't use _vsnprintf/_vsnwsprintf because they're MS extensions.
1590//
1591// -----------------------------------------------------------------------------
1592// Borland's headers put some ANSI "C" functions in the 'std' namespace.
1593// Promote them to the global namespace so we can use them here.
1594
1595#if defined(__BORLANDC__)
1596 using std::vsprintf;
1597 using std::vswprintf;
1598#endif
1599
1600 // GNU is supposed to have vsnprintf and vsnwprintf. But only the newer
1601 // distributions do.
1602
1603#if defined(__GNUC__)
1604
1605 inline int ssvsprintf(PSTR pA, size_t nCount, PCSTR pFmtA, va_list vl)
1606 {
1607 return vsnprintf(pA, nCount, pFmtA, vl);
1608 }
1609 inline int ssvsprintf(PWSTR pW, size_t nCount, PCWSTR pFmtW, va_list vl)
1610 {
1611 return vswprintf(pW, nCount, pFmtW, vl);
1612 }
1613
1614 // Microsofties can use
1615#elif defined(_MSC_VER) && !defined(SS_ANSI)
1616
1617 inline int ssvsprintf(PSTR pA, size_t nCount, PCSTR pFmtA, va_list vl)
1618 {
1619 return _vsnprintf(pA, nCount, pFmtA, vl);
1620 }
1621 inline int ssvsprintf(PWSTR pW, size_t nCount, PCWSTR pFmtW, va_list vl)
1622 {
1623 return _vsnwprintf(pW, nCount, pFmtW, vl);
1624 }
1625
1626#elif defined (SS_DANGEROUS_FORMAT) // ignore buffer size parameter if needed?
1627
1628 inline int ssvsprintf(PSTR pA, size_t /*nCount*/, PCSTR pFmtA, va_list vl)
1629 {
1630 return vsprintf(pA, pFmtA, vl);
1631 }
1632
1633 inline int ssvsprintf(PWSTR pW, size_t nCount, PCWSTR pFmtW, va_list vl)
1634 {
1635 // JMO: Some distributions of the "C" have a version of vswprintf that
1636 // takes 3 arguments (e.g. Microsoft, Borland, GNU). Others have a
1637 // version which takes 4 arguments (an extra "count" argument in the
1638 // second position. The best stab I can take at this so far is that if
1639 // you are NOT running with MS, Borland, or GNU, then I'll assume you
1640 // have the version that takes 4 arguments.
1641 //
1642 // I'm sure that these checks don't catch every platform correctly so if
1643 // you get compiler errors on one of the lines immediately below, it's
1644 // probably because your implemntation takes a different number of
1645 // arguments. You can comment out the offending line (and use the
1646 // alternate version) or you can figure out what compiler flag to check
1647 // and add that preprocessor check in. Regardless, if you get an error
1648 // on these lines, I'd sure like to hear from you about it.
1649 //
1650 // Thanks to Ronny Schulz for the SGI-specific checks here.
1651
1652// #if !defined(__MWERKS__) && !defined(__SUNPRO_CC_COMPAT) && !defined(__SUNPRO_CC)
1653 #if !defined(_MSC_VER) \
1654 && !defined (__BORLANDC__) \
1655 && !defined(__GNUC__) \
1656 && !defined(__sgi)
1657
1658 return vswprintf(pW, nCount, pFmtW, vl);
1659
1660 // suddenly with the current SGI 7.3 compiler there is no such function as
1661 // vswprintf and the substitute needs explicit casts to compile
1662
1663 #elif defined(__sgi)
1664
1665 nCount;
1666 return vsprintf( (char *)pW, (char *)pFmtW, vl);
1667
1668 #else
1669
1670 nCount;
1671 return vswprintf(pW, pFmtW, vl);
1672
1673 #endif
1674
1675 }
1676
1677#endif
1678
1679 // GOT COMPILER PROBLEMS HERE?
1680 // ---------------------------
1681 // Does your compiler choke on one or more of the following 2 functions? It
1682 // probably means that you don't have have either vsnprintf or vsnwprintf in
1683 // your version of the CRT. This is understandable since neither is an ANSI
1684 // "C" function. However it still leaves you in a dilemma. In order to make
1685 // this code build, you're going to have to to use some non-length-checked
1686 // formatting functions that every CRT has: vsprintf and vswprintf.
1687 //
1688 // This is very dangerous. With the proper erroneous (or malicious) code, it
1689 // can lead to buffer overlows and crashing your PC. Use at your own risk
1690 // In order to use them, just #define SS_DANGEROUS_FORMAT at the top of
1691 // this file.
1692 //
1693 // Even THEN you might not be all the way home due to some non-conforming
1694 // distributions. More on this in the comments below.
1695
1696 inline int ssnprintf(PSTR pA, size_t nCount, PCSTR pFmtA, va_list vl)
1697 {
1698 #ifdef _MSC_VER
1699 return _vsnprintf(pA, nCount, pFmtA, vl);
1700 #else
1701 return vsnprintf(pA, nCount, pFmtA, vl);
1702 #endif
1703 }
1704 inline int ssnprintf(PWSTR pW, size_t nCount, PCWSTR pFmtW, va_list vl)
1705 {
1706 #ifdef _MSC_VER
1707 return _vsnwprintf(pW, nCount, pFmtW, vl);
1708 #else
1709 return vswprintf(pW, nCount, pFmtW, vl);
1710 #endif
1711 }
1712
1713
1714
1715
1716// -----------------------------------------------------------------------------
1717// ssload: Type safe, overloaded ::LoadString wrappers
1718// There is no equivalent of these in non-Win32-specific builds. However, I'm
1719// thinking that with the message facet, there might eventually be one
1720// -----------------------------------------------------------------------------
1721#if defined (SS_WIN32) && !defined(SS_ANSI)
1722 inline int ssload(HMODULE hInst, UINT uId, PSTR pBuf, int nMax)
1723 {
1724 return ::LoadStringA(hInst, uId, pBuf, nMax);
1725 }
1726 inline int ssload(HMODULE hInst, UINT uId, PWSTR pBuf, int nMax)
1727 {
1728 return ::LoadStringW(hInst, uId, pBuf, nMax);
1729 }
1730#if defined ( _MSC_VER ) && ( _MSC_VER >= 1500 )
1731 inline int ssload(HMODULE hInst, UINT uId, uint16_t *pBuf, int nMax)
1732 {
1733 return 0;
1734 }
1735 inline int ssload(HMODULE hInst, UINT uId, uint32_t *pBuf, int nMax)
1736 {
1737 return 0;
1738 }
1739#endif
1740#endif
1741
1742
1743// -----------------------------------------------------------------------------
1744// sscoll/ssicoll: Collation wrappers
1745// Note -- with MSVC I have reversed the arguments order here because the
1746// functions appear to return the opposite of what they should
1747// -----------------------------------------------------------------------------
1748#ifndef SS_NO_LOCALE
1749template <typename CT>
1750inline int sscoll(const CT* sz1, int nLen1, const CT* sz2, int nLen2)
1751{
1752 const std::collate<CT>& coll =
1753 SS_USE_FACET(std::locale(), std::collate<CT>);
1754
1755 return coll.compare(sz2, sz2+nLen2, sz1, sz1+nLen1);
1756}
1757template <typename CT>
1758inline int ssicoll(const CT* sz1, int nLen1, const CT* sz2, int nLen2)
1759{
1760 const std::locale loc;
1761 const std::collate<CT>& coll = SS_USE_FACET(loc, std::collate<CT>);
1762
1763 // Some implementations seem to have trouble using the collate<>
1764 // facet typedefs so we'll just default to basic_string and hope
1765 // that's what the collate facet uses (which it generally should)
1766
1767// std::collate<CT>::string_type s1(sz1);
1768// std::collate<CT>::string_type s2(sz2);
1769 const std::basic_string<CT> sEmpty;
1770 std::basic_string<CT> s1(sz1 ? sz1 : sEmpty.c_str());
1771 std::basic_string<CT> s2(sz2 ? sz2 : sEmpty.c_str());
1772
1773 sslwr(const_cast<CT*>(s1.c_str()), nLen1, loc);
1774 sslwr(const_cast<CT*>(s2.c_str()), nLen2, loc);
1775 return coll.compare(s2.c_str(), s2.c_str()+nLen2,
1776 s1.c_str(), s1.c_str()+nLen1);
1777}
1778#endif
1779
1780
1781// -----------------------------------------------------------------------------
1782// ssfmtmsg: FormatMessage equivalents. Needed because I added a CString facade
1783// Again -- no equivalent of these on non-Win32 builds but their might one day
1784// be one if the message facet gets implemented
1785// -----------------------------------------------------------------------------
1786#if defined (SS_WIN32) && !defined(SS_ANSI)
1787 inline DWORD ssfmtmsg(DWORD dwFlags, LPCVOID pSrc, DWORD dwMsgId,
1788 DWORD dwLangId, PSTR pBuf, DWORD nSize,
1789 va_list* vlArgs)
1790 {
1791 return FormatMessageA(dwFlags, pSrc, dwMsgId, dwLangId,
1792 pBuf, nSize,vlArgs);
1793 }
1794 inline DWORD ssfmtmsg(DWORD dwFlags, LPCVOID pSrc, DWORD dwMsgId,
1795 DWORD dwLangId, PWSTR pBuf, DWORD nSize,
1796 va_list* vlArgs)
1797 {
1798 return FormatMessageW(dwFlags, pSrc, dwMsgId, dwLangId,
1799 pBuf, nSize,vlArgs);
1800 }
1801#else
1802#endif
1803
1804
1805
1806// FUNCTION: sscpy. Copies up to 'nMax' characters from pSrc to pDst.
1807// -----------------------------------------------------------------------------
1808// FUNCTION: sscpy
1809// inline int sscpy(PSTR pDst, PCSTR pSrc, int nMax=-1);
1810// inline int sscpy(PUSTR pDst, PCSTR pSrc, int nMax=-1)
1811// inline int sscpy(PSTR pDst, PCWSTR pSrc, int nMax=-1);
1812// inline int sscpy(PWSTR pDst, PCWSTR pSrc, int nMax=-1);
1813// inline int sscpy(PWSTR pDst, PCSTR pSrc, int nMax=-1);
1814//
1815// DESCRIPTION:
1816// This function is very much (but not exactly) like strcpy. These
1817// overloads simplify copying one C-style string into another by allowing
1818// the caller to specify two different types of strings if necessary.
1819//
1820// The strings must NOT overlap
1821//
1822// "Character" is expressed in terms of the destination string, not
1823// the source. If no 'nMax' argument is supplied, then the number of
1824// characters copied will be sslen(pSrc). A NULL terminator will
1825// also be added so pDst must actually be big enough to hold nMax+1
1826// characters. The return value is the number of characters copied,
1827// not including the NULL terminator.
1828//
1829// PARAMETERS:
1830// pSrc - the string to be copied FROM. May be a char based string, an
1831// MBCS string (in Win32 builds) or a wide string (wchar_t).
1832// pSrc - the string to be copied TO. Also may be either MBCS or wide
1833// nMax - the maximum number of characters to be copied into szDest. Note
1834// that this is expressed in whatever a "character" means to pDst.
1835// If pDst is a wchar_t type string than this will be the maximum
1836// number of wchar_ts that my be copied. The pDst string must be
1837// large enough to hold least nMaxChars+1 characters.
1838// If the caller supplies no argument for nMax this is a signal to
1839// the routine to copy all the characters in pSrc, regardless of
1840// how long it is.
1841//
1842// RETURN VALUE: none
1843// -----------------------------------------------------------------------------
1844
1845template<typename CT1, typename CT2>
1846inline int sscpycvt(CT1* pDst, const CT2* pSrc, int nMax)
1847{
1848 // Note -- we assume pDst is big enough to hold pSrc. If not, we're in
1849 // big trouble. No bounds checking. Caveat emptor.
1850
1851 int nSrc = sslen(pSrc);
1852
1853 const CT1* szCvt = StdCodeCvt(pDst, nMax, pSrc, nSrc);
1854
1855 // If we're copying the same size characters, then all the "code convert"
1856 // just did was basically memcpy so the #of characters copied is the same
1857 // as the number requested. I should probably specialize this function
1858 // template to achieve this purpose as it is silly to do a runtime check
1859 // of a fact known at compile time. I'll get around to it.
1860
1861 return sslen(szCvt);
1862}
1863
1864template<typename T>
1865inline int sscpycvt(T* pDst, const T* pSrc, int nMax)
1866{
1867 int nCount = nMax;
1868 for (; nCount > 0 && *pSrc; ++pSrc, ++pDst, --nCount)
1869 std::basic_string<T>::traits_type::assign(*pDst, *pSrc);
1870
1871 *pDst = 0;
1872 return nMax - nCount;
1873}
1874
1875inline int sscpycvt(PWSTR pDst, PCSTR pSrc, int nMax)
1876{
1877 // Note -- we assume pDst is big enough to hold pSrc. If not, we're in
1878 // big trouble. No bounds checking. Caveat emptor.
1879
1880 const PWSTR szCvt = StdCodeCvt(pDst, nMax, pSrc, nMax);
1881 return sslen(szCvt);
1882}
1883
1884template<typename CT1, typename CT2>
1885inline int sscpy(CT1* pDst, const CT2* pSrc, int nMax, int nLen)
1886{
1887 return sscpycvt(pDst, pSrc, SSMIN(nMax, nLen));
1888}
1889template<typename CT1, typename CT2>
1890inline int sscpy(CT1* pDst, const CT2* pSrc, int nMax)
1891{
1892 return sscpycvt(pDst, pSrc, SSMIN(nMax, sslen(pSrc)));
1893}
1894template<typename CT1, typename CT2>
1895inline int sscpy(CT1* pDst, const CT2* pSrc)
1896{
1897 return sscpycvt(pDst, pSrc, sslen(pSrc));
1898}
1899template<typename CT1, typename CT2>
1900inline int sscpy(CT1* pDst, const std::basic_string<CT2>& sSrc, int nMax)
1901{
1902 return sscpycvt(pDst, sSrc.c_str(), SSMIN(nMax, (int)sSrc.length()));
1903}
1904template<typename CT1, typename CT2>
1905inline int sscpy(CT1* pDst, const std::basic_string<CT2>& sSrc)
1906{
1907 return sscpycvt(pDst, sSrc.c_str(), (int)sSrc.length());
1908}
1909
1910#ifdef SS_INC_COMDEF
1911 template<typename CT1>
1912 inline int sscpy(CT1* pDst, const _bstr_t& bs, int nMax)
1913 {
1914 return sscpycvt(pDst, static_cast<PCOLESTR>(bs),
1915 SSMIN(nMax, static_cast<int>(bs.length())));
1916 }
1917 template<typename CT1>
1918 inline int sscpy(CT1* pDst, const _bstr_t& bs)
1919 {
1920 return sscpy(pDst, bs, static_cast<int>(bs.length()));
1921 }
1922#endif
1923
1924
1925// -----------------------------------------------------------------------------
1926// Functional objects for changing case. They also let you pass locales
1927// -----------------------------------------------------------------------------
1928
1929#ifdef SS_NO_LOCALE
1930 template<typename CT>
1931 struct SSToUpper : public std::unary_function<CT, CT>
1932 {
1933 inline CT operator()(const CT& t) const
1934 {
1935 return sstoupper(t);
1936 }
1937 };
1938 template<typename CT>
1939 struct SSToLower : public std::unary_function<CT, CT>
1940 {
1941 inline CT operator()(const CT& t) const
1942 {
1943 return sstolower(t);
1944 }
1945 };
1946#else
1947 template<typename CT>
1948 struct SSToUpper : public std::binary_function<CT, std::locale, CT>
1949 {
1950 inline CT operator()(const CT& t, const std::locale& loc) const
1951 {
1952 return sstoupper<CT>(t, loc);
1953 }
1954 };
1955 template<typename CT>
1956 struct SSToLower : public std::binary_function<CT, std::locale, CT>
1957 {
1958 inline CT operator()(const CT& t, const std::locale& loc) const
1959 {
1960 return sstolower<CT>(t, loc);
1961 }
1962 };
1963#endif
1964
1965// This struct is used for TrimRight() and TrimLeft() function implementations.
1966//template<typename CT>
1967//struct NotSpace : public std::unary_function<CT, bool>
1968//{
1969// const std::locale& loc;
1970// inline NotSpace(const std::locale& locArg) : loc(locArg) {}
1971// inline bool operator() (CT t) { return !std::isspace(t, loc); }
1972//};
1973template<typename CT>
1974struct NotSpace : public std::unary_function<CT, bool>
1975{
1976 // DINKUMWARE BUG:
1977 // Note -- using std::isspace in a COM DLL gives us access violations
1978 // because it causes the dynamic addition of a function to be called
1979 // when the library shuts down. Unfortunately the list is maintained
1980 // in DLL memory but the function is in static memory. So the COM DLL
1981 // goes away along with the function that was supposed to be called,
1982 // and then later when the DLL CRT shuts down it unloads the list and
1983 // tries to call the long-gone function.
1984 // This is DinkumWare's implementation problem. If you encounter this
1985 // problem, you may replace the calls here with good old isspace() and
1986 // iswspace() from the CRT unless they specify SS_ANSI
1987
1988#ifdef SS_NO_LOCALE
1989
1990 bool operator() (CT t) const { return !ssisspace(t); }
1991
1992#else
1993 const std::locale loc;
1994 NotSpace(const std::locale& locArg=std::locale()) : loc(locArg) {}
1995 bool operator() (CT t) const { return !std::isspace(t, loc); }
1996#endif
1997};
1998
1999
2000
2001
2002// Now we can define the template (finally!)
2003// =============================================================================
2004// TEMPLATE: CStdStr
2005// template<typename CT> class CStdStr : public std::basic_string<CT>
2006//
2007// REMARKS:
2008// This template derives from basic_string<CT> and adds some MFC CString-
2009// like functionality
2010//
2011// Basically, this is my attempt to make Standard C++ library strings as
2012// easy to use as the MFC CString class.
2013//
2014// Note that although this is a template, it makes the assumption that the
2015// template argument (CT, the character type) is either char or wchar_t.
2016// =============================================================================
2017
2018//#define CStdStr _SS // avoid compiler warning 4786
2019
2020// template<typename ARG> ARG& FmtArg(ARG& arg) { return arg; }
2021// PCSTR FmtArg(const std::string& arg) { return arg.c_str(); }
2022// PCWSTR FmtArg(const std::wstring& arg) { return arg.c_str(); }
2023
2024template<typename ARG>
2025struct FmtArg
2026{
2027 explicit FmtArg(const ARG& arg) : a_(arg) {}
2028 const ARG& operator()() const { return a_; }
2029 const ARG& a_;
2030private:
2031 FmtArg& operator=(const FmtArg&) { return *this; }
2032};
2033
2034template<typename CT>
2035class CStdStr : public std::basic_string<CT>
2036{
2037 // Typedefs for shorter names. Using these names also appears to help
2038 // us avoid some ambiguities that otherwise arise on some platforms
2039
2040 #define MYBASE std::basic_string<CT> // my base class
2041 //typedef typename std::basic_string<CT> MYBASE; // my base class
2042 typedef CStdStr<CT> MYTYPE; // myself
2043 typedef typename MYBASE::const_pointer PCMYSTR; // PCSTR or PCWSTR
2044 typedef typename MYBASE::pointer PMYSTR; // PSTR or PWSTR
2045 typedef typename MYBASE::iterator MYITER; // my iterator type
2046 typedef typename MYBASE::const_iterator MYCITER; // you get the idea...
2047 typedef typename MYBASE::reverse_iterator MYRITER;
2048 typedef typename MYBASE::size_type MYSIZE;
2049 typedef typename MYBASE::value_type MYVAL;
2050 typedef typename MYBASE::allocator_type MYALLOC;
2051
2052public:
2053 // shorthand conversion from PCTSTR to string resource ID
2054 #define SSRES(pctstr) LOWORD(reinterpret_cast<unsigned long>(pctstr))
2055
2056 bool TryLoad(const void* pT)
2057 {
2058 bool bLoaded = false;
2059
2060#if defined(SS_WIN32) && !defined(SS_ANSI)
2061 if ( ( pT != NULL ) && SS_IS_INTRESOURCE(pT) )
2062 {
2063 UINT nId = LOWORD(reinterpret_cast<unsigned long>(pT));
2064 if ( !LoadString(nId) )
2065 {
2066 TRACE(_T("Can't load string %u\n"), SSRES(pT));
2067 }
2068 bLoaded = true;
2069 }
2070#endif
2071
2072 return bLoaded;
2073 }
2074
2075
2076 // CStdStr inline constructors
2077 CStdStr()
2078 {
2079 }
2080
2081 CStdStr(const MYTYPE& str) : MYBASE(SSREF(str))
2082 {
2083 }
2084
2085 CStdStr(const std::string& str)
2086 {
2087 ssasn(*this, SSREF(str));
2088 }
2089
2090 CStdStr(const std::wstring& str)
2091 {
2092 ssasn(*this, SSREF(str));
2093 }
2094
2095 CStdStr(PCMYSTR pT, MYSIZE n) : MYBASE(pT, n)
2096 {
2097 }
2098
2099#ifdef SS_UNSIGNED
2100 CStdStr(PCUSTR pU)
2101 {
2102 *this = reinterpret_cast<PCSTR>(pU);
2103 }
2104#endif
2105
2106 CStdStr(PCSTR pA)
2107 {
2108 #ifdef SS_ANSI
2109 *this = pA;
2110 #else
2111 if ( !TryLoad(pA) )
2112 *this = pA;
2113 #endif
2114 }
2115
2116 CStdStr(PCWSTR pW)
2117 {
2118 #ifdef SS_ANSI
2119 *this = pW;
2120 #else
2121 if ( !TryLoad(pW) )
2122 *this = pW;
2123 #endif
2124 }
2125
2126 CStdStr(uint16_t* pW)
2127 {
2128 #ifdef SS_ANSI
2129 *this = pW;
2130 #else
2131 if ( !TryLoad(pW) )
2132 *this = pW;
2133 #endif
2134 }
2135
2136 CStdStr(uint32_t* pW)
2137 {
2138 #ifdef SS_ANSI
2139 *this = pW;
2140 #else
2141 if ( !TryLoad(pW) )
2142 *this = pW;
2143 #endif
2144 }
2145
2146 CStdStr(MYCITER first, MYCITER last)
2147 : MYBASE(first, last)
2148 {
2149 }
2150
2151 CStdStr(MYSIZE nSize, MYVAL ch, const MYALLOC& al=MYALLOC())
2152 : MYBASE(nSize, ch, al)
2153 {
2154 }
2155
2156 #ifdef SS_INC_COMDEF
2157 CStdStr(const _bstr_t& bstr)
2158 {
2159 if ( bstr.length() > 0 )
2160 this->append(static_cast<PCMYSTR>(bstr), bstr.length());
2161 }
2162 #endif
2163
2164 // CStdStr inline assignment operators -- the ssasn function now takes care
2165 // of fixing the MSVC assignment bug (see knowledge base article Q172398).
2166 MYTYPE& operator=(const MYTYPE& str)
2167 {
2168 ssasn(*this, str);
2169 return *this;
2170 }
2171
2172 MYTYPE& operator=(const std::string& str)
2173 {
2174 ssasn(*this, str);
2175 return *this;
2176 }
2177
2178 MYTYPE& operator=(const std::wstring& str)
2179 {
2180 ssasn(*this, str);
2181 return *this;
2182 }
2183
2184 MYTYPE& operator=(PCSTR pA)
2185 {
2186 ssasn(*this, pA);
2187 return *this;
2188 }
2189
2190 MYTYPE& operator=(PCWSTR pW)
2191 {
2192 ssasn(*this, pW);
2193 return *this;
2194 }
2195
2196#ifdef SS_UNSIGNED
2197 MYTYPE& operator=(PCUSTR pU)
2198 {
2199 ssasn(*this, reinterpret_cast<PCSTR>(pU));
2200 return *this;
2201 }
2202#endif
2203
2204 MYTYPE& operator=(uint16_t* pA)
2205 {
2206 ssasn(*this, pA);
2207 return *this;
2208 }
2209
2210 MYTYPE& operator=(uint32_t* pA)
2211 {
2212 ssasn(*this, pA);
2213 return *this;
2214 }
2215
2216 MYTYPE& operator=(CT t)
2217 {
2218 Q172398(*this);
2219 this->assign(1, t);
2220 return *this;
2221 }
2222
2223 #ifdef SS_INC_COMDEF
2224 MYTYPE& operator=(const _bstr_t& bstr)
2225 {
2226 if ( bstr.length() > 0 )
2227 {
2228 this->assign(static_cast<PCMYSTR>(bstr), bstr.length());
2229 return *this;
2230 }
2231 else
2232 {
2233 this->erase();
2234 return *this;
2235 }
2236 }
2237 #endif
2238
2239
2240 // Overloads also needed to fix the MSVC assignment bug (KB: Q172398)
2241 // *** Thanks to Pete The Plumber for catching this one ***
2242 // They also are compiled if you have explicitly turned off refcounting
2243 #if ( defined(_MSC_VER) && ( _MSC_VER < 1200 ) ) || defined(SS_NO_REFCOUNT)
2244
2245 MYTYPE& assign(const MYTYPE& str)
2246 {
2247 Q172398(*this);
2248 sscpy(GetBuffer(str.size()+1), SSREF(str));
2249 this->ReleaseBuffer(str.size());
2250 return *this;
2251 }
2252
2253 MYTYPE& assign(const MYTYPE& str, MYSIZE nStart, MYSIZE nChars)
2254 {
2255 // This overload of basic_string::assign is supposed to assign up to
2256 // <nChars> or the NULL terminator, whichever comes first. Since we
2257 // are about to call a less forgiving overload (in which <nChars>
2258 // must be a valid length), we must adjust the length here to a safe
2259 // value. Thanks to Ullrich Poll�hne for catching this bug
2260
2261 nChars = SSMIN(nChars, str.length() - nStart);
2262 MYTYPE strTemp(str.c_str()+nStart, nChars);
2263 Q172398(*this);
2264 this->assign(strTemp);
2265 return *this;
2266 }
2267
2268 MYTYPE& assign(const MYBASE& str)
2269 {
2270 ssasn(*this, str);
2271 return *this;
2272 }
2273
2274 MYTYPE& assign(const MYBASE& str, MYSIZE nStart, MYSIZE nChars)
2275 {
2276 // This overload of basic_string::assign is supposed to assign up to
2277 // <nChars> or the NULL terminator, whichever comes first. Since we
2278 // are about to call a less forgiving overload (in which <nChars>
2279 // must be a valid length), we must adjust the length here to a safe
2280 // value. Thanks to Ullrich Poll�hne for catching this bug
2281
2282 nChars = SSMIN(nChars, str.length() - nStart);
2283
2284 // Watch out for assignment to self
2285
2286 if ( this == &str )
2287 {
2288 MYTYPE strTemp(str.c_str() + nStart, nChars);
2289 static_cast<MYBASE*>(this)->assign(strTemp);
2290 }
2291 else
2292 {
2293 Q172398(*this);
2294 static_cast<MYBASE*>(this)->assign(str.c_str()+nStart, nChars);
2295 }
2296 return *this;
2297 }
2298
2299 MYTYPE& assign(const CT* pC, MYSIZE nChars)
2300 {
2301 // Q172398 only fix -- erase before assigning, but not if we're
2302 // assigning from our own buffer
2303
2304 #if defined ( _MSC_VER ) && ( _MSC_VER < 1200 )
2305 if ( !this->empty() &&
2306 ( pC < this->data() || pC > this->data() + this->capacity() ) )
2307 {
2308 this->erase();
2309 }
2310 #endif
2311 Q172398(*this);
2312 static_cast<MYBASE*>(this)->assign(pC, nChars);
2313 return *this;
2314 }
2315
2316 MYTYPE& assign(MYSIZE nChars, MYVAL val)
2317 {
2318 Q172398(*this);
2319 static_cast<MYBASE*>(this)->assign(nChars, val);
2320 return *this;
2321 }
2322
2323 MYTYPE& assign(const CT* pT)
2324 {
2325 return this->assign(pT, MYBASE::traits_type::length(pT));
2326 }
2327
2328 MYTYPE& assign(MYCITER iterFirst, MYCITER iterLast)
2329 {
2330 #if defined ( _MSC_VER ) && ( _MSC_VER < 1200 )
2331 // Q172398 fix. don't call erase() if we're assigning from ourself
2332 if ( iterFirst < this->begin() ||
2333 iterFirst > this->begin() + this->size() )
2334 {
2335 this->erase()
2336 }
2337 #endif
2338 this->replace(this->begin(), this->end(), iterFirst, iterLast);
2339 return *this;
2340 }
2341 #endif
2342
2343
2344 // -------------------------------------------------------------------------
2345 // CStdStr inline concatenation.
2346 // -------------------------------------------------------------------------
2347 MYTYPE& operator+=(const MYTYPE& str)
2348 {
2349 ssadd(*this, str);
2350 return *this;
2351 }
2352
2353 MYTYPE& operator+=(const std::string& str)
2354 {
2355 ssadd(*this, str);
2356 return *this;
2357 }
2358
2359 MYTYPE& operator+=(const std::wstring& str)
2360 {
2361 ssadd(*this, str);
2362 return *this;
2363 }
2364
2365 MYTYPE& operator+=(PCSTR pA)
2366 {
2367 ssadd(*this, pA);
2368 return *this;
2369 }
2370
2371 MYTYPE& operator+=(PCWSTR pW)
2372 {
2373 ssadd(*this, pW);
2374 return *this;
2375 }
2376
2377 MYTYPE& operator+=(uint16_t* pW)
2378 {
2379 ssadd(*this, pW);
2380 return *this;
2381 }
2382
2383 MYTYPE& operator+=(uint32_t* pW)
2384 {
2385 ssadd(*this, pW);
2386 return *this;
2387 }
2388
2389 MYTYPE& operator+=(CT t)
2390 {
2391 this->append(1, t);
2392 return *this;
2393 }
2394 #ifdef SS_INC_COMDEF // if we have _bstr_t, define a += for it too.
2395 MYTYPE& operator+=(const _bstr_t& bstr)
2396 {
2397 return this->operator+=(static_cast<PCMYSTR>(bstr));
2398 }
2399 #endif
2400
2401
2402 // -------------------------------------------------------------------------
2403 // Case changing functions
2404 // -------------------------------------------------------------------------
2405
2406 MYTYPE& ToUpper(const std::locale& loc=std::locale())
2407 {
2408 // Note -- if there are any MBCS character sets in which the lowercase
2409 // form a character takes up a different number of bytes than the
2410 // uppercase form, this would probably not work...
2411
2412 std::transform(this->begin(),
2413 this->end(),
2414 this->begin(),
2415#ifdef SS_NO_LOCALE
2416 SSToUpper<CT>());
2417#else
2418 std::bind2nd(SSToUpper<CT>(), loc));
2419#endif
2420
2421 // ...but if it were, this would probably work better. Also, this way
2422 // seems to be a bit faster when anything other then the "C" locale is
2423 // used...
2424
2425// if ( !empty() )
2426// {
2427// ssupr(this->GetBuf(), this->size(), loc);
2428// this->RelBuf();
2429// }
2430
2431 return *this;
2432 }
2433
2434 MYTYPE& ToLower(const std::locale& loc=std::locale())
2435 {
2436 // Note -- if there are any MBCS character sets in which the lowercase
2437 // form a character takes up a different number of bytes than the
2438 // uppercase form, this would probably not work...
2439
2440 std::transform(this->begin(),
2441 this->end(),
2442 this->begin(),
2443#ifdef SS_NO_LOCALE
2444 SSToLower<CT>());
2445#else
2446 std::bind2nd(SSToLower<CT>(), loc));
2447#endif
2448
2449 // ...but if it were, this would probably work better. Also, this way
2450 // seems to be a bit faster when anything other then the "C" locale is
2451 // used...
2452
2453// if ( !empty() )
2454// {
2455// sslwr(this->GetBuf(), this->size(), loc);
2456// this->RelBuf();
2457// }
2458 return *this;
2459 }
2460
2461
2462 MYTYPE& Normalize()
2463 {
2464 return Trim().ToLower();
2465 }
2466
2467
2468 // -------------------------------------------------------------------------
2469 // CStdStr -- Direct access to character buffer. In the MS' implementation,
2470 // the at() function that we use here also calls _Freeze() providing us some
2471 // protection from multithreading problems associated with ref-counting.
2472 // In VC 7 and later, of course, the ref-counting stuff is gone.
2473 // -------------------------------------------------------------------------
2474
2475 CT* GetBuf(int nMinLen=-1)
2476 {
2477 if ( static_cast<int>(this->size()) < nMinLen )
2478 this->resize(static_cast<MYSIZE>(nMinLen));
2479
2480 return this->empty() ? const_cast<CT*>(this->data()) : &(this->at(0));
2481 }
2482
2483 CT* SetBuf(int nLen)
2484 {
2485 nLen = ( nLen > 0 ? nLen : 0 );
2486 if ( this->capacity() < 1 && nLen == 0 )
2487 this->resize(1);
2488
2489 this->resize(static_cast<MYSIZE>(nLen));
2490 return const_cast<CT*>(this->data());
2491 }
2492 void RelBuf(int nNewLen=-1)
2493 {
2494 this->resize(static_cast<MYSIZE>(nNewLen > -1 ? nNewLen :
2495 sslen(this->c_str())));
2496 }
2497
2498 void BufferRel() { RelBuf(); } // backwards compatability
2499 CT* Buffer() { return GetBuf(); } // backwards compatability
2500 CT* BufferSet(int nLen) { return SetBuf(nLen);}// backwards compatability
2501
2502 bool Equals(const CT* pT, bool bUseCase=false) const
2503 {
2504 return 0 == (bUseCase ? this->compare(pT) : ssicmp(this->c_str(), pT));
2505 }
2506
2507 // -------------------------------------------------------------------------
2508 // FUNCTION: CStdStr::Load
2509 // REMARKS:
2510 // Loads string from resource specified by nID
2511 //
2512 // PARAMETERS:
2513 // nID - resource Identifier. Purely a Win32 thing in this case
2514 //
2515 // RETURN VALUE:
2516 // true if successful, false otherwise
2517 // -------------------------------------------------------------------------
2518
2519#ifndef SS_ANSI
2520
2521 bool Load(UINT nId, HMODULE hModule=NULL)
2522 {
2523 bool bLoaded = false; // set to true of we succeed.
2524
2525 #ifdef _MFC_VER // When in Rome (or MFC land)...
2526
2527 // If they gave a resource handle, use it. Note - this is archaic
2528 // and not really what I would recommend. But then again, in MFC
2529 // land, you ought to be using CString for resources anyway since
2530 // it walks the resource chain for you.
2531
2532 HMODULE hModuleOld = NULL;
2533
2534 if ( NULL != hModule )
2535 {
2536 hModuleOld = AfxGetResourceHandle();
2537 AfxSetResourceHandle(hModule);
2538 }
2539
2540 // ...load the string
2541
2542 CString strRes;
2543 bLoaded = FALSE != strRes.LoadString(nId);
2544
2545 // ...and if we set the resource handle, restore it.
2546
2547 if ( NULL != hModuleOld )
2548 AfxSetResourceHandle(hModule);
2549
2550 if ( bLoaded )
2551 *this = strRes;
2552
2553 #else // otherwise make our own hackneyed version of CString's Load
2554
2555 // Get the resource name and module handle
2556
2557 if ( NULL == hModule )
2558 hModule = GetResourceHandle();
2559
2560 PCTSTR szName = MAKEINTRESOURCE((nId>>4)+1); // lifted
2561 DWORD dwSize = 0;
2562
2563 // No sense continuing if we can't find the resource
2564
2565 HRSRC hrsrc = ::FindResource(hModule, szName, RT_STRING);
2566
2567 if ( NULL == hrsrc )
2568 {
2569 TRACE(_T("Cannot find resource %d: 0x%X"), nId, ::GetLastError());
2570 }
2571 else if ( 0 == (dwSize = ::SizeofResource(hModule, hrsrc) / sizeof(CT)))
2572 {
2573 TRACE(_T("Cant get size of resource %d 0x%X\n"),nId,GetLastError());
2574 }
2575 else
2576 {
2577 bLoaded = 0 != ssload(hModule, nId, GetBuf(dwSize), dwSize);
2578 ReleaseBuffer();
2579 }
2580
2581 #endif // #ifdef _MFC_VER
2582
2583 if ( !bLoaded )
2584 TRACE(_T("String not loaded 0x%X\n"), ::GetLastError());
2585
2586 return bLoaded;
2587 }
2588
2589#endif // #ifdef SS_ANSI
2590
2591 // -------------------------------------------------------------------------
2592 // FUNCTION: CStdStr::Format
2593 // void _cdecl Formst(CStdStringA& PCSTR szFormat, ...)
2594 // void _cdecl Format(PCSTR szFormat);
2595 //
2596 // DESCRIPTION:
2597 // This function does sprintf/wsprintf style formatting on CStdStringA
2598 // objects. It looks a lot like MFC's CString::Format. Some people
2599 // might even call this identical. Fortunately, these people are now
2600 // dead... heh heh.
2601 //
2602 // PARAMETERS:
2603 // nId - ID of string resource holding the format string
2604 // szFormat - a PCSTR holding the format specifiers
2605 // argList - a va_list holding the arguments for the format specifiers.
2606 //
2607 // RETURN VALUE: None.
2608 // -------------------------------------------------------------------------
2609 // formatting (using wsprintf style formatting)
2610
2611 // If they want a Format() function that safely handles string objects
2612 // without casting
2613
2614#ifdef SS_SAFE_FORMAT
2615
2616 // Question: Joe, you wacky coder you, why do you have so many overloads
2617 // of the Format() function
2618 // Answer: One reason only - CString compatability. In short, by making
2619 // the Format() function a template this way, I can do strong typing
2620 // and allow people to pass CStdString arguments as fillers for
2621 // "%s" format specifiers without crashing their program! The downside
2622 // is that I need to overload on the number of arguments. If you are
2623 // passing more arguments than I have listed below in any of my
2624 // overloads, just add another one.
2625 //
2626 // Yes, yes, this is really ugly. In essence what I am doing here is
2627 // protecting people from a bad (and incorrect) programming practice
2628 // that they should not be doing anyway. I am protecting them from
2629 // themselves. Why am I doing this? Well, if you had any idea the
2630 // number of times I've been emailed by people about this
2631 // "incompatability" in my code, you wouldn't ask.
2632
2633 void Fmt(const CT* szFmt, ...)
2634 {
2635 va_list argList;
2636 va_start(argList, szFmt);
2637 FormatV(szFmt, argList);
2638 va_end(argList);
2639 }
2640
2641#ifndef SS_ANSI
2642
2643 void Format(UINT nId)
2644 {
2645 MYTYPE strFmt;
2646 if ( strFmt.Load(nId) )
2647 this->swap(strFmt);
2648 }
2649 template<class A1>
2650 void Format(UINT nId, const A1& v)
2651 {
2652 MYTYPE strFmt;
2653 if ( strFmt.Load(nId) )
2654 Fmt(strFmt, FmtArg<A1>(v)());
2655 }
2656 template<class A1, class A2>
2657 void Format(UINT nId, const A1& v1, const A2& v2)
2658 {
2659 MYTYPE strFmt;
2660 if ( strFmt.Load(nId) )
2661 Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)());
2662 }
2663 template<class A1, class A2, class A3>
2664 void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3)
2665 {
2666 MYTYPE strFmt;
2667 if ( strFmt.Load(nId) )
2668 {
2669 Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
2670 FmtArg<A3>(v3)());
2671 }
2672 }
2673 template<class A1, class A2, class A3, class A4>
2674 void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,
2675 const A4& v4)
2676 {
2677 MYTYPE strFmt;
2678 if ( strFmt.Load(nId) )
2679 {
2680 Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
2681 FmtArg<A3>(v3)(), FmtArg<A4>(v4)());
2682 }
2683 }
2684 template<class A1, class A2, class A3, class A4, class A5>
2685 void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,
2686 const A4& v4, const A5& v5)
2687 {
2688 MYTYPE strFmt;
2689 if ( strFmt.Load(nId) )
2690 {
2691 Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
2692 FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)());
2693 }
2694 }
2695 template<class A1, class A2, class A3, class A4, class A5, class A6>
2696 void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,
2697 const A4& v4, const A5& v5, const A6& v6)
2698 {
2699 MYTYPE strFmt;
2700 if ( strFmt.Load(nId) )
2701 {
2702 Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
2703 FmtArg<A3>(v3)(), FmtArg<A4>(v4)(),FmtArg<A5>(v5)(),
2704 FmtArg<A6>(v6)());
2705 }
2706 }
2707 template<class A1, class A2, class A3, class A4, class A5, class A6,
2708 class A7>
2709 void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,
2710 const A4& v4, const A5& v5, const A6& v6, const A7& v7)
2711 {
2712 MYTYPE strFmt;
2713 if ( strFmt.Load(nId) )
2714 {
2715 Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
2716 FmtArg<A3>(v3)(), FmtArg<A4>(v4)(),FmtArg<A5>(v5)(),
2717 FmtArg<A6>(v6)(), FmtArg<A7>(v7)());
2718 }
2719 }
2720 template<class A1, class A2, class A3, class A4, class A5, class A6,
2721 class A7, class A8>
2722 void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,
2723 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
2724 const A8& v8)
2725 {
2726 MYTYPE strFmt;
2727 if ( strFmt.Load(nId) )
2728 {
2729 Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
2730 FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
2731 FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)());
2732 }
2733 }
2734 template<class A1, class A2, class A3, class A4, class A5, class A6,
2735 class A7, class A8, class A9>
2736 void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,
2737 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
2738 const A8& v8, const A9& v9)
2739 {
2740 MYTYPE strFmt;
2741 if ( strFmt.Load(nId) )
2742 {
2743 Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
2744 FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
2745 FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),
2746 FmtArg<A9>(v9)());
2747 }
2748 }
2749 template<class A1, class A2, class A3, class A4, class A5, class A6,
2750 class A7, class A8, class A9, class A10>
2751 void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,
2752 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
2753 const A8& v8, const A9& v9, const A10& v10)
2754 {
2755 MYTYPE strFmt;
2756 if ( strFmt.Load(nId) )
2757 {
2758 Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
2759 FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
2760 FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),
2761 FmtArg<A9>(v9)(), FmtArg<A10>(v10)());
2762 }
2763 }
2764 template<class A1, class A2, class A3, class A4, class A5, class A6,
2765 class A7, class A8, class A9, class A10, class A11>
2766 void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,
2767 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
2768 const A8& v8, const A9& v9, const A10& v10, const A11& v11)
2769 {
2770 MYTYPE strFmt;
2771 if ( strFmt.Load(nId) )
2772 {
2773 Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
2774 FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
2775 FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),
2776 FmtArg<A9>(v9)(),FmtArg<A10>(v10)(),FmtArg<A11>(v11)());
2777 }
2778 }
2779 template<class A1, class A2, class A3, class A4, class A5, class A6,
2780 class A7, class A8, class A9, class A10, class A11, class A12>
2781 void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,
2782 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
2783 const A8& v8, const A9& v9, const A10& v10, const A11& v11,
2784 const A12& v12)
2785 {
2786 MYTYPE strFmt;
2787 if ( strFmt.Load(nId) )
2788 {
2789 Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
2790 FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
2791 FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),
2792 FmtArg<A9>(v9)(), FmtArg<A10>(v10)(),FmtArg<A11>(v11)(),
2793 FmtArg<A12>(v12)());
2794 }
2795 }
2796 template<class A1, class A2, class A3, class A4, class A5, class A6,
2797 class A7, class A8, class A9, class A10, class A11, class A12,
2798 class A13>
2799 void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,
2800 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
2801 const A8& v8, const A9& v9, const A10& v10, const A11& v11,
2802 const A12& v12, const A13& v13)
2803 {
2804 MYTYPE strFmt;
2805 if ( strFmt.Load(nId) )
2806 {
2807 Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
2808 FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
2809 FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),
2810 FmtArg<A9>(v9)(), FmtArg<A10>(v10)(),FmtArg<A11>(v11)(),
2811 FmtArg<A12>(v12)(), FmtArg<A13>(v13)());
2812 }
2813 }
2814 template<class A1, class A2, class A3, class A4, class A5, class A6,
2815 class A7, class A8, class A9, class A10, class A11, class A12,
2816 class A13, class A14>
2817 void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,
2818 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
2819 const A8& v8, const A9& v9, const A10& v10, const A11& v11,
2820 const A12& v12, const A13& v13, const A14& v14)
2821 {
2822 MYTYPE strFmt;
2823 if ( strFmt.Load(nId) )
2824 {
2825 Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
2826 FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
2827 FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),
2828 FmtArg<A9>(v9)(), FmtArg<A10>(v10)(),FmtArg<A11>(v11)(),
2829 FmtArg<A12>(v12)(), FmtArg<A13>(v13)(),FmtArg<A14>(v14)());
2830 }
2831 }
2832 template<class A1, class A2, class A3, class A4, class A5, class A6,
2833 class A7, class A8, class A9, class A10, class A11, class A12,
2834 class A13, class A14, class A15>
2835 void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,
2836 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
2837 const A8& v8, const A9& v9, const A10& v10, const A11& v11,
2838 const A12& v12, const A13& v13, const A14& v14, const A15& v15)
2839 {
2840 MYTYPE strFmt;
2841 if ( strFmt.Load(nId) )
2842 {
2843 Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
2844 FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
2845 FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),
2846 FmtArg<A9>(v9)(), FmtArg<A10>(v10)(),FmtArg<A11>(v11)(),
2847 FmtArg<A12>(v12)(),FmtArg<A13>(v13)(),FmtArg<A14>(v14)(),
2848 FmtArg<A15>(v15)());
2849 }
2850 }
2851 template<class A1, class A2, class A3, class A4, class A5, class A6,
2852 class A7, class A8, class A9, class A10, class A11, class A12,
2853 class A13, class A14, class A15, class A16>
2854 void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,
2855 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
2856 const A8& v8, const A9& v9, const A10& v10, const A11& v11,
2857 const A12& v12, const A13& v13, const A14& v14, const A15& v15,
2858 const A16& v16)
2859 {
2860 MYTYPE strFmt;
2861 if ( strFmt.Load(nId) )
2862 {
2863 Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
2864 FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
2865 FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),
2866 FmtArg<A9>(v9)(), FmtArg<A10>(v10)(),FmtArg<A11>(v11)(),
2867 FmtArg<A12>(v12)(),FmtArg<A13>(v13)(),FmtArg<A14>(v14)(),
2868 FmtArg<A15>(v15)(), FmtArg<A16>(v16)());
2869 }
2870 }
2871 template<class A1, class A2, class A3, class A4, class A5, class A6,
2872 class A7, class A8, class A9, class A10, class A11, class A12,
2873 class A13, class A14, class A15, class A16, class A17>
2874 void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,
2875 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
2876 const A8& v8, const A9& v9, const A10& v10, const A11& v11,
2877 const A12& v12, const A13& v13, const A14& v14, const A15& v15,
2878 const A16& v16, const A17& v17)
2879 {
2880 MYTYPE strFmt;
2881 if ( strFmt.Load(nId) )
2882 {
2883 Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
2884 FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
2885 FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),
2886 FmtArg<A9>(v9)(), FmtArg<A10>(v10)(),FmtArg<A11>(v11)(),
2887 FmtArg<A12>(v12)(),FmtArg<A13>(v13)(),FmtArg<A14>(v14)(),
2888 FmtArg<A15>(v15)(),FmtArg<A16>(v16)(),FmtArg<A17>(v17)());
2889 }
2890 }
2891
2892#endif // #ifndef SS_ANSI
2893
2894 // ...now the other overload of Format: the one that takes a string literal
2895
2896 void Format(const CT* szFmt)
2897 {
2898 *this = szFmt;
2899 }
2900 template<class A1>
2901 void Format(const CT* szFmt, const A1& v)
2902 {
2903 Fmt(szFmt, FmtArg<A1>(v)());
2904 }
2905 template<class A1, class A2>
2906 void Format(const CT* szFmt, const A1& v1, const A2& v2)
2907 {
2908 Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)());
2909 }
2910 template<class A1, class A2, class A3>
2911 void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3)
2912 {
2913 Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
2914 FmtArg<A3>(v3)());
2915 }
2916 template<class A1, class A2, class A3, class A4>
2917 void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,
2918 const A4& v4)
2919 {
2920 Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
2921 FmtArg<A3>(v3)(), FmtArg<A4>(v4)());
2922 }
2923 template<class A1, class A2, class A3, class A4, class A5>
2924 void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,
2925 const A4& v4, const A5& v5)
2926 {
2927 Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
2928 FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)());
2929 }
2930 template<class A1, class A2, class A3, class A4, class A5, class A6>
2931 void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,
2932 const A4& v4, const A5& v5, const A6& v6)
2933 {
2934 Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
2935 FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
2936 FmtArg<A6>(v6)());
2937 }
2938 template<class A1, class A2, class A3, class A4, class A5, class A6,
2939 class A7>
2940 void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,
2941 const A4& v4, const A5& v5, const A6& v6, const A7& v7)
2942 {
2943 Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
2944 FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
2945 FmtArg<A6>(v6)(), FmtArg<A7>(v7)());
2946 }
2947 template<class A1, class A2, class A3, class A4, class A5, class A6,
2948 class A7, class A8>
2949 void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,
2950 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
2951 const A8& v8)
2952 {
2953 Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
2954 FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
2955 FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)());
2956 }
2957 template<class A1, class A2, class A3, class A4, class A5, class A6,
2958 class A7, class A8, class A9>
2959 void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,
2960 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
2961 const A8& v8, const A9& v9)
2962 {
2963 Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
2964 FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
2965 FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),
2966 FmtArg<A9>(v9)());
2967 }
2968 template<class A1, class A2, class A3, class A4, class A5, class A6,
2969 class A7, class A8, class A9, class A10>
2970 void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,
2971 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
2972 const A8& v8, const A9& v9, const A10& v10)
2973 {
2974 Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
2975 FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
2976 FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),
2977 FmtArg<A9>(v9)(), FmtArg<A10>(v10)());
2978 }
2979 template<class A1, class A2, class A3, class A4, class A5, class A6,
2980 class A7, class A8, class A9, class A10, class A11>
2981 void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,
2982 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
2983 const A8& v8, const A9& v9, const A10& v10, const A11& v11)
2984 {
2985 Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
2986 FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
2987 FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),
2988 FmtArg<A9>(v9)(),FmtArg<A10>(v10)(),FmtArg<A11>(v11)());
2989 }
2990 template<class A1, class A2, class A3, class A4, class A5, class A6,
2991 class A7, class A8, class A9, class A10, class A11, class A12>
2992 void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,
2993 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
2994 const A8& v8, const A9& v9, const A10& v10, const A11& v11,
2995 const A12& v12)
2996 {
2997 Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
2998 FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
2999 FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),
3000 FmtArg<A9>(v9)(), FmtArg<A10>(v10)(),FmtArg<A11>(v11)(),
3001 FmtArg<A12>(v12)());
3002 }
3003 template<class A1, class A2, class A3, class A4, class A5, class A6,
3004 class A7, class A8, class A9, class A10, class A11, class A12,
3005 class A13>
3006 void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,
3007 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
3008 const A8& v8, const A9& v9, const A10& v10, const A11& v11,
3009 const A12& v12, const A13& v13)
3010 {
3011 Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
3012 FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
3013 FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),
3014 FmtArg<A9>(v9)(), FmtArg<A10>(v10)(),FmtArg<A11>(v11)(),
3015 FmtArg<A12>(v12)(), FmtArg<A13>(v13)());
3016 }
3017 template<class A1, class A2, class A3, class A4, class A5, class A6,
3018 class A7, class A8, class A9, class A10, class A11, class A12,
3019 class A13, class A14>
3020 void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,
3021 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
3022 const A8& v8, const A9& v9, const A10& v10, const A11& v11,
3023 const A12& v12, const A13& v13, const A14& v14)
3024 {
3025 Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
3026 FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
3027 FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),
3028 FmtArg<A9>(v9)(), FmtArg<A10>(v10)(),FmtArg<A11>(v11)(),
3029 FmtArg<A12>(v12)(), FmtArg<A13>(v13)(),FmtArg<A14>(v14)());
3030 }
3031 template<class A1, class A2, class A3, class A4, class A5, class A6,
3032 class A7, class A8, class A9, class A10, class A11, class A12,
3033 class A13, class A14, class A15>
3034 void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,
3035 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
3036 const A8& v8, const A9& v9, const A10& v10, const A11& v11,
3037 const A12& v12, const A13& v13, const A14& v14, const A15& v15)
3038 {
3039 Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
3040 FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
3041 FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),
3042 FmtArg<A9>(v9)(), FmtArg<A10>(v10)(),FmtArg<A11>(v11)(),
3043 FmtArg<A12>(v12)(),FmtArg<A13>(v13)(),FmtArg<A14>(v14)(),
3044 FmtArg<A15>(v15)());
3045 }
3046 template<class A1, class A2, class A3, class A4, class A5, class A6,
3047 class A7, class A8, class A9, class A10, class A11, class A12,
3048 class A13, class A14, class A15, class A16>
3049 void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,
3050 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
3051 const A8& v8, const A9& v9, const A10& v10, const A11& v11,
3052 const A12& v12, const A13& v13, const A14& v14, const A15& v15,
3053 const A16& v16)
3054 {
3055 Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
3056 FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
3057 FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),
3058 FmtArg<A9>(v9)(), FmtArg<A10>(v10)(),FmtArg<A11>(v11)(),
3059 FmtArg<A12>(v12)(),FmtArg<A13>(v13)(),FmtArg<A14>(v14)(),
3060 FmtArg<A15>(v15)(), FmtArg<A16>(v16)());
3061 }
3062 template<class A1, class A2, class A3, class A4, class A5, class A6,
3063 class A7, class A8, class A9, class A10, class A11, class A12,
3064 class A13, class A14, class A15, class A16, class A17>
3065 void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,
3066 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
3067 const A8& v8, const A9& v9, const A10& v10, const A11& v11,
3068 const A12& v12, const A13& v13, const A14& v14, const A15& v15,
3069 const A16& v16, const A17& v17)
3070 {
3071 Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
3072 FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
3073 FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),
3074 FmtArg<A9>(v9)(), FmtArg<A10>(v10)(),FmtArg<A11>(v11)(),
3075 FmtArg<A12>(v12)(),FmtArg<A13>(v13)(),FmtArg<A14>(v14)(),
3076 FmtArg<A15>(v15)(),FmtArg<A16>(v16)(),FmtArg<A17>(v17)());
3077 }
3078
3079#else // #ifdef SS_SAFE_FORMAT
3080
3081
3082#ifndef SS_ANSI
3083
3084 void Format(UINT nId, ...)
3085 {
3086 va_list argList;
3087 va_start(argList, nId);
3088
3089 MYTYPE strFmt;
3090 if ( strFmt.Load(nId) )
3091 FormatV(strFmt, argList);
3092
3093 va_end(argList);
3094 }
3095
3096#endif // #ifdef SS_ANSI
3097
3098 void Format(const CT* szFmt, ...)
3099 {
3100 va_list argList;
3101 va_start(argList, szFmt);
3102 FormatV(szFmt, argList);
3103 va_end(argList);
3104 }
3105
3106#endif // #ifdef SS_SAFE_FORMAT
3107
3108 void AppendFormat(const CT* szFmt, ...)
3109 {
3110 va_list argList;
3111 va_start(argList, szFmt);
3112 AppendFormatV(szFmt, argList);
3113 va_end(argList);
3114 }
3115
3116 #define MAX_FMT_TRIES 5 // #of times we try
3117 #define FMT_BLOCK_SIZE 2048 // # of bytes to increment per try
3118 #define BUFSIZE_1ST 256
3119 #define BUFSIZE_2ND 512
3120 #define STD_BUF_SIZE 1024
3121
3122 // an efficient way to add formatted characters to the string. You may only
3123 // add up to STD_BUF_SIZE characters at a time, though
3124 void AppendFormatV(const CT* szFmt, va_list argList)
3125 {
3126 CT szBuf[STD_BUF_SIZE];
3127 int nLen = ssnprintf(szBuf, STD_BUF_SIZE-1, szFmt, argList);
3128
3129 if ( 0 < nLen )
3130 this->append(szBuf, nLen);
3131 }
3132
3133 // -------------------------------------------------------------------------
3134 // FUNCTION: FormatV
3135 // void FormatV(PCSTR szFormat, va_list, argList);
3136 //
3137 // DESCRIPTION:
3138 // This function formats the string with sprintf style format-specs.
3139 // It makes a general guess at required buffer size and then tries
3140 // successively larger buffers until it finds one big enough or a
3141 // threshold (MAX_FMT_TRIES) is exceeded.
3142 //
3143 // PARAMETERS:
3144 // szFormat - a PCSTR holding the format of the output
3145 // argList - a Microsoft specific va_list for variable argument lists
3146 //
3147 // RETURN VALUE:
3148 // -------------------------------------------------------------------------
3149
3150 // NOTE: Changed by JM to actually function under non-win32,
3151 // and to remove the upper limit on size.
3152 void FormatV(const CT* szFormat, va_list argList)
3153 {
3154 // try and grab a sufficient buffersize
3155 int nChars = FMT_BLOCK_SIZE;
3156 va_list argCopy;
3157
3158 CT *p = reinterpret_cast<CT*>(malloc(sizeof(CT)*nChars));
3159 if (!p) return;
3160
3161 while (1)
3162 {
3163 va_copy(argCopy, argList);
3164
3165 int nActual = ssvsprintf(p, nChars, szFormat, argCopy);
3166 /* If that worked, return the string. */
3167 if (nActual > -1 && nActual < nChars)
3168 { /* make sure it's NULL terminated */
3169 p[nActual] = '\0';
3170 this->assign(p, nActual);
3171 free(p);
3172 va_end(argCopy);
3173 return;
3174 }
3175 /* Else try again with more space. */
3176 if (nActual > -1) /* glibc 2.1 */
3177 nChars = nActual + 1; /* precisely what is needed */
3178 else /* glibc 2.0 */
3179 nChars *= 2; /* twice the old size */
3180
3181 CT *np = reinterpret_cast<CT*>(realloc(p, sizeof(CT)*nChars));
3182 if (np == NULL)
3183 {
3184 free(p);
3185 va_end(argCopy);
3186 return; // failed :(
3187 }
3188 p = np;
3189 va_end(argCopy);
3190 }
3191 }
3192
3193 // -------------------------------------------------------------------------
3194 // CString Facade Functions:
3195 //
3196 // The following methods are intended to allow you to use this class as a
3197 // near drop-in replacement for CString.
3198 // -------------------------------------------------------------------------
3199 #ifdef SS_WIN32
3200 BSTR AllocSysString() const
3201 {
3202 ostring os;
3203 ssasn(os, *this);
3204 return ::SysAllocString(os.c_str());
3205 }
3206 #endif
3207
3208#ifndef SS_NO_LOCALE
3209 int Collate(PCMYSTR szThat) const
3210 {
3211 return sscoll(this->c_str(), this->length(), szThat, sslen(szThat));
3212 }
3213
3214 int CollateNoCase(PCMYSTR szThat) const
3215 {
3216 return ssicoll(this->c_str(), this->length(), szThat, sslen(szThat));
3217 }
3218#endif
3219 int Compare(PCMYSTR szThat) const
3220 {
3221 return this->compare(szThat);
3222 }
3223
3224 int CompareNoCase(PCMYSTR szThat) const
3225 {
3226 return ssicmp(this->c_str(), szThat);
3227 }
3228
3229 int Delete(int nIdx, int nCount=1)
3230 {
3231 if ( nIdx < 0 )
3232 nIdx = 0;
3233
3234 if ( nIdx < this->GetLength() )
3235 this->erase(static_cast<MYSIZE>(nIdx), static_cast<MYSIZE>(nCount));
3236
3237 return GetLength();
3238 }
3239
3240 void Empty()
3241 {
3242 this->erase();
3243 }
3244
3245 int Find(CT ch) const
3246 {
3247 MYSIZE nIdx = this->find_first_of(ch);
3248 return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);
3249 }
3250
3251 int Find(PCMYSTR szSub) const
3252 {
3253 MYSIZE nIdx = this->find(szSub);
3254 return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);
3255 }
3256
3257 int Find(CT ch, int nStart) const
3258 {
3259 // CString::Find docs say add 1 to nStart when it's not zero
3260 // CString::Find code doesn't do that however. We'll stick
3261 // with what the code does
3262
3263 MYSIZE nIdx = this->find_first_of(ch, static_cast<MYSIZE>(nStart));
3264 return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);
3265 }
3266
3267 int Find(PCMYSTR szSub, int nStart) const
3268 {
3269 // CString::Find docs say add 1 to nStart when it's not zero
3270 // CString::Find code doesn't do that however. We'll stick
3271 // with what the code does
3272
3273 MYSIZE nIdx = this->find(szSub, static_cast<MYSIZE>(nStart));
3274 return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);
3275 }
3276
3277 int FindOneOf(PCMYSTR szCharSet) const
3278 {
3279 MYSIZE nIdx = this->find_first_of(szCharSet);
3280 return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);
3281 }
3282
3283#ifndef SS_ANSI
3284 void FormatMessage(PCMYSTR szFormat, ...) throw(std::exception)
3285 {
3286 va_list argList;
3287 va_start(argList, szFormat);
3288 PMYSTR szTemp;
3289 if ( ssfmtmsg(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ALLOCATE_BUFFER,
3290 szFormat, 0, 0,
3291 reinterpret_cast<PMYSTR>(&szTemp), 0, &argList) == 0 ||
3292 szTemp == 0 )
3293 {
3294 throw std::runtime_error("out of memory");
3295 }
3296 *this = szTemp;
3297 LocalFree(szTemp);
3298 va_end(argList);
3299 }
3300
3301 void FormatMessage(UINT nFormatId, ...) throw(std::exception)
3302 {
3303 MYTYPE sFormat;
3304 VERIFY(sFormat.LoadString(nFormatId));
3305 va_list argList;
3306 va_start(argList, nFormatId);
3307 PMYSTR szTemp;
3308 if ( ssfmtmsg(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ALLOCATE_BUFFER,
3309 sFormat, 0, 0,
3310 reinterpret_cast<PMYSTR>(&szTemp), 0, &argList) == 0 ||
3311 szTemp == 0)
3312 {
3313 throw std::runtime_error("out of memory");
3314 }
3315 *this = szTemp;
3316 LocalFree(szTemp);
3317 va_end(argList);
3318 }
3319#endif
3320
3321 // GetAllocLength -- an MSVC7 function but it costs us nothing to add it.
3322
3323 int GetAllocLength()
3324 {
3325 return static_cast<int>(this->capacity());
3326 }
3327
3328 // -------------------------------------------------------------------------
3329 // GetXXXX -- Direct access to character buffer
3330 // -------------------------------------------------------------------------
3331 CT GetAt(int nIdx) const
3332 {
3333 return this->at(static_cast<MYSIZE>(nIdx));
3334 }
3335
3336 CT* GetBuffer(int nMinLen=-1)
3337 {
3338 return GetBuf(nMinLen);
3339 }
3340
3341 CT* GetBufferSetLength(int nLen)
3342 {
3343 return BufferSet(nLen);
3344 }
3345
3346 // GetLength() -- MFC docs say this is the # of BYTES but
3347 // in truth it is the number of CHARACTERs (chars or wchar_ts)
3348 int GetLength() const
3349 {
3350 return static_cast<int>(this->length());
3351 }
3352
3353 int Insert(int nIdx, CT ch)
3354 {
3355 if ( static_cast<MYSIZE>(nIdx) > this->size()-1 )
3356 this->append(1, ch);
3357 else
3358 this->insert(static_cast<MYSIZE>(nIdx), 1, ch);
3359
3360 return GetLength();
3361 }
3362 int Insert(int nIdx, PCMYSTR sz)
3363 {
3364 if ( static_cast<MYSIZE>(nIdx) >= this->size() )
3365 this->append(sz, static_cast<MYSIZE>(sslen(sz)));
3366 else
3367 this->insert(static_cast<MYSIZE>(nIdx), sz);
3368
3369 return GetLength();
3370 }
3371
3372 bool IsEmpty() const
3373 {
3374 return this->empty();
3375 }
3376
3377 MYTYPE Left(int nCount) const
3378 {
3379 // Range check the count.
3380
3381 nCount = SSMAX(0, SSMIN(nCount, static_cast<int>(this->size())));
3382 return this->substr(0, static_cast<MYSIZE>(nCount));
3383 }
3384
3385#ifndef SS_ANSI
3386 bool LoadString(UINT nId)
3387 {
3388 return this->Load(nId);
3389 }
3390#endif
3391
3392 void MakeLower()
3393 {
3394 ToLower();
3395 }
3396
3397 void MakeReverse()
3398 {
3399 std::reverse(this->begin(), this->end());
3400 }
3401
3402 void MakeUpper()
3403 {
3404 ToUpper();
3405 }
3406
3407 MYTYPE Mid(int nFirst) const
3408 {
3409 return Mid(nFirst, this->GetLength()-nFirst);
3410 }
3411
3412 MYTYPE Mid(int nFirst, int nCount) const
3413 {
3414 // CString does range checking here. Since we're trying to emulate it,
3415 // we must check too.
3416
3417 if ( nFirst < 0 )
3418 nFirst = 0;
3419 if ( nCount < 0 )
3420 nCount = 0;
3421
3422 int nSize = static_cast<int>(this->size());
3423
3424 if ( nFirst + nCount > nSize )
3425 nCount = nSize - nFirst;
3426
3427 if ( nFirst > nSize )
3428 return MYTYPE();
3429
3430 ASSERT(nFirst >= 0);
3431 ASSERT(nFirst + nCount <= nSize);
3432
3433 return this->substr(static_cast<MYSIZE>(nFirst),
3434 static_cast<MYSIZE>(nCount));
3435 }
3436
3437 void ReleaseBuffer(int nNewLen=-1)
3438 {
3439 RelBuf(nNewLen);
3440 }
3441
3442 int Remove(CT ch)
3443 {
3444 MYSIZE nIdx = 0;
3445 int nRemoved = 0;
3446 while ( (nIdx=this->find_first_of(ch)) != MYBASE::npos )
3447 {
3448 this->erase(nIdx, 1);
3449 nRemoved++;
3450 }
3451 return nRemoved;
3452 }
3453
3454 int Replace(CT chOld, CT chNew)
3455 {
3456 int nReplaced = 0;
3457
3458 for ( MYITER iter=this->begin(); iter != this->end(); iter++ )
3459 {
3460 if ( *iter == chOld )
3461 {
3462 *iter = chNew;
3463 nReplaced++;
3464 }
3465 }
3466
3467 return nReplaced;
3468 }
3469
3470 int Replace(PCMYSTR szOld, PCMYSTR szNew)
3471 {
3472 int nReplaced = 0;
3473 MYSIZE nIdx = 0;
3474 MYSIZE nOldLen = sslen(szOld);
3475
3476 if ( 0 != nOldLen )
3477 {
3478 // If the replacement string is longer than the one it replaces, this
3479 // string is going to have to grow in size, Figure out how much
3480 // and grow it all the way now, rather than incrementally
3481
3482 MYSIZE nNewLen = sslen(szNew);
3483 if ( nNewLen > nOldLen )
3484 {
3485 int nFound = 0;
3486 while ( nIdx < this->length() &&
3487 (nIdx=this->find(szOld, nIdx)) != MYBASE::npos )
3488 {
3489 nFound++;
3490 nIdx += nOldLen;
3491 }
3492 this->reserve(this->size() + nFound * (nNewLen - nOldLen));
3493 }
3494
3495
3496 static const CT ch = CT(0);
3497 PCMYSTR szRealNew = szNew == 0 ? &ch : szNew;
3498 nIdx = 0;
3499
3500 while ( nIdx < this->length() &&
3501 (nIdx=this->find(szOld, nIdx)) != MYBASE::npos )
3502 {
3503 this->replace(this->begin()+nIdx, this->begin()+nIdx+nOldLen,
3504 szRealNew);
3505
3506 nReplaced++;
3507 nIdx += nNewLen;
3508 }
3509 }
3510
3511 return nReplaced;
3512 }
3513
3514 int ReverseFind(CT ch) const
3515 {
3516 MYSIZE nIdx = this->find_last_of(ch);
3517 return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);
3518 }
3519
3520 // ReverseFind overload that's not in CString but might be useful
3521 int ReverseFind(PCMYSTR szFind, MYSIZE pos=MYBASE::npos) const
3522 {
3523 //yuvalt - this does not compile with g++ since MYTTYPE() is different type
3524 //MYSIZE nIdx = this->rfind(0 == szFind ? MYTYPE() : szFind, pos);
3525 MYSIZE nIdx = this->rfind(0 == szFind ? "" : szFind, pos);
3526 return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);
3527 }
3528
3529 MYTYPE Right(int nCount) const
3530 {
3531 // Range check the count.
3532
3533 nCount = SSMAX(0, SSMIN(nCount, static_cast<int>(this->size())));
3534 return this->substr(this->size()-static_cast<MYSIZE>(nCount));
3535 }
3536
3537 void SetAt(int nIndex, CT ch)
3538 {
3539 ASSERT(this->size() > static_cast<MYSIZE>(nIndex));
3540 this->at(static_cast<MYSIZE>(nIndex)) = ch;
3541 }
3542
3543#ifndef SS_ANSI
3544 BSTR SetSysString(BSTR* pbstr) const
3545 {
3546 ostring os;
3547 ssasn(os, *this);
3548 if ( !::SysReAllocStringLen(pbstr, os.c_str(), os.length()) )
3549 throw std::runtime_error("out of memory");
3550
3551 ASSERT(*pbstr != 0);
3552 return *pbstr;
3553 }
3554#endif
3555
3556 MYTYPE SpanExcluding(PCMYSTR szCharSet) const
3557 {
3558 MYSIZE pos = this->find_first_of(szCharSet);
3559 return pos == MYBASE::npos ? *this : Left(pos);
3560 }
3561
3562 MYTYPE SpanIncluding(PCMYSTR szCharSet) const
3563 {
3564 MYSIZE pos = this->find_first_not_of(szCharSet);
3565 return pos == MYBASE::npos ? *this : Left(pos);
3566 }
3567
3568#if defined SS_WIN32 && !defined(UNICODE) && !defined(SS_ANSI)
3569
3570 // CString's OemToAnsi and AnsiToOem functions are available only in
3571 // Unicode builds. However since we're a template we also need a
3572 // runtime check of CT and a reinterpret_cast to account for the fact
3573 // that CStdStringW gets instantiated even in non-Unicode builds.
3574
3575 void AnsiToOem()
3576 {
3577 if ( sizeof(CT) == sizeof(char) && !empty() )
3578 {
3579 ::CharToOem(reinterpret_cast<PCSTR>(this->c_str()),
3580 reinterpret_cast<PSTR>(GetBuf()));
3581 }
3582 else
3583 {
3584 ASSERT(false);
3585 }
3586 }
3587
3588 void OemToAnsi()
3589 {
3590 if ( sizeof(CT) == sizeof(char) && !empty() )
3591 {
3592 ::OemToChar(reinterpret_cast<PCSTR>(this->c_str()),
3593 reinterpret_cast<PSTR>(GetBuf()));
3594 }
3595 else
3596 {
3597 ASSERT(false);
3598 }
3599 }
3600
3601#endif
3602
3603
3604 // -------------------------------------------------------------------------
3605 // Trim and its variants
3606 // -------------------------------------------------------------------------
3607 MYTYPE& Trim()
3608 {
3609 return TrimLeft().TrimRight();
3610 }
3611
3612 MYTYPE& TrimLeft()
3613 {
3614 this->erase(this->begin(),
3615 std::find_if(this->begin(), this->end(), NotSpace<CT>()));
3616
3617 return *this;
3618 }
3619
3620 MYTYPE& TrimLeft(CT tTrim)
3621 {
3622 this->erase(0, this->find_first_not_of(tTrim));
3623 return *this;
3624 }
3625
3626 MYTYPE& TrimLeft(PCMYSTR szTrimChars)
3627 {
3628 this->erase(0, this->find_first_not_of(szTrimChars));
3629 return *this;
3630 }
3631
3632 MYTYPE& TrimRight()
3633 {
3634 // NOTE: When comparing reverse_iterators here (MYRITER), I avoid using
3635 // operator!=. This is because namespace rel_ops also has a template
3636 // operator!= which conflicts with the global operator!= already defined
3637 // for reverse_iterator in the header <utility>.
3638 // Thanks to John James for alerting me to this.
3639
3640 MYRITER it = std::find_if(this->rbegin(), this->rend(), NotSpace<CT>());
3641 if ( !(this->rend() == it) )
3642 this->erase(this->rend() - it);
3643
3644 this->erase(!(it == this->rend()) ? this->find_last_of(*it) + 1 : 0);
3645 return *this;
3646 }
3647
3648 MYTYPE& TrimRight(CT tTrim)
3649 {
3650 MYSIZE nIdx = this->find_last_not_of(tTrim);
3651 this->erase(MYBASE::npos == nIdx ? 0 : ++nIdx);
3652 return *this;
3653 }
3654
3655 MYTYPE& TrimRight(PCMYSTR szTrimChars)
3656 {
3657 MYSIZE nIdx = this->find_last_not_of(szTrimChars);
3658 this->erase(MYBASE::npos == nIdx ? 0 : ++nIdx);
3659 return *this;
3660 }
3661
3662 void FreeExtra()
3663 {
3664 MYTYPE mt;
3665 this->swap(mt);
3666 if ( !mt.empty() )
3667 this->assign(mt.c_str(), mt.size());
3668 }
3669
3670 // I have intentionally not implemented the following CString
3671 // functions. You cannot make them work without taking advantage
3672 // of implementation specific behavior. However if you absolutely
3673 // MUST have them, uncomment out these lines for "sort-of-like"
3674 // their behavior. You're on your own.
3675
3676// CT* LockBuffer() { return GetBuf(); }// won't really lock
3677// void UnlockBuffer(); { } // why have UnlockBuffer w/o LockBuffer?
3678
3679 // Array-indexing operators. Required because we defined an implicit cast
3680 // to operator const CT* (Thanks to Julian Selman for pointing this out)
3681
3682 CT& operator[](int nIdx)
3683 {
3684 return static_cast<MYBASE*>(this)->operator[](static_cast<MYSIZE>(nIdx));
3685 }
3686
3687 const CT& operator[](int nIdx) const
3688 {
3689 return static_cast<const MYBASE*>(this)->operator[](static_cast<MYSIZE>(nIdx));
3690 }
3691
3692 CT& operator[](unsigned int nIdx)
3693 {
3694 return static_cast<MYBASE*>(this)->operator[](static_cast<MYSIZE>(nIdx));
3695 }
3696
3697 const CT& operator[](unsigned int nIdx) const
3698 {
3699 return static_cast<const MYBASE*>(this)->operator[](static_cast<MYSIZE>(nIdx));
3700 }
3701
3702 CT& operator[](unsigned long nIdx)
3703 {
3704 return static_cast<MYBASE*>(this)->operator[](static_cast<MYSIZE>(nIdx));
3705 }
3706
3707 const CT& operator[](unsigned long nIdx) const
3708 {
3709 return static_cast<const MYBASE*>(this)->operator[](static_cast<MYSIZE>(nIdx));
3710 }
3711
3712#ifndef SS_NO_IMPLICIT_CAST
3713 operator const CT*() const
3714 {
3715 return this->c_str();
3716 }
3717#endif
3718
3719 // IStream related functions. Useful in IPersistStream implementations
3720
3721#ifdef SS_INC_COMDEF
3722
3723 // struct SSSHDR - useful for non Std C++ persistence schemes.
3724 typedef struct SSSHDR
3725 {
3726 BYTE byCtrl;
3727 ULONG nChars;
3728 } SSSHDR; // as in "Standard String Stream Header"
3729
3730 #define SSSO_UNICODE 0x01 // the string is a wide string
3731 #define SSSO_COMPRESS 0x02 // the string is compressed
3732
3733 // -------------------------------------------------------------------------
3734 // FUNCTION: StreamSize
3735 // REMARKS:
3736 // Returns how many bytes it will take to StreamSave() this CStdString
3737 // object to an IStream.
3738 // -------------------------------------------------------------------------
3739 ULONG StreamSize() const
3740 {
3741 // Control header plus string
3742 ASSERT(this->size()*sizeof(CT) < 0xffffffffUL - sizeof(SSSHDR));
3743 return (this->size() * sizeof(CT)) + sizeof(SSSHDR);
3744 }
3745
3746 // -------------------------------------------------------------------------
3747 // FUNCTION: StreamSave
3748 // REMARKS:
3749 // Saves this CStdString object to a COM IStream.
3750 // -------------------------------------------------------------------------
3751 HRESULT StreamSave(IStream* pStream) const
3752 {
3753 ASSERT(this->size()*sizeof(CT) < 0xffffffffUL - sizeof(SSSHDR));
3754 HRESULT hr = E_FAIL;
3755 ASSERT(pStream != 0);
3756 SSSHDR hdr;
3757 hdr.byCtrl = sizeof(CT) == 2 ? SSSO_UNICODE : 0;
3758 hdr.nChars = this->size();
3759
3760
3761 if ( FAILED(hr=pStream->Write(&hdr, sizeof(SSSHDR), 0)) )
3762 {
3763 TRACE(_T("StreamSave: Cannot write control header, ERR=0x%X\n"),hr);
3764 }
3765 else if ( empty() )
3766 {
3767 ; // nothing to write
3768 }
3769 else if ( FAILED(hr=pStream->Write(this->c_str(),
3770 this->size()*sizeof(CT), 0)) )
3771 {
3772 TRACE(_T("StreamSave: Cannot write string to stream 0x%X\n"), hr);
3773 }
3774
3775 return hr;
3776 }
3777
3778
3779 // -------------------------------------------------------------------------
3780 // FUNCTION: StreamLoad
3781 // REMARKS:
3782 // This method loads the object from an IStream.
3783 // -------------------------------------------------------------------------
3784 HRESULT StreamLoad(IStream* pStream)
3785 {
3786 ASSERT(pStream != 0);
3787 SSSHDR hdr;
3788 HRESULT hr = E_FAIL;
3789
3790 if ( FAILED(hr=pStream->Read(&hdr, sizeof(SSSHDR), 0)) )
3791 {
3792 TRACE(_T("StreamLoad: Cant read control header, ERR=0x%X\n"), hr);
3793 }
3794 else if ( hdr.nChars > 0 )
3795 {
3796 ULONG nRead = 0;
3797 PMYSTR pMyBuf = BufferSet(hdr.nChars);
3798
3799 // If our character size matches the character size of the string
3800 // we're trying to read, then we can read it directly into our
3801 // buffer. Otherwise, we have to read into an intermediate buffer
3802 // and convert.
3803
3804 if ( (hdr.byCtrl & SSSO_UNICODE) != 0 )
3805 {
3806 ULONG nBytes = hdr.nChars * sizeof(wchar_t);
3807 if ( sizeof(CT) == sizeof(wchar_t) )
3808 {
3809 if ( FAILED(hr=pStream->Read(pMyBuf, nBytes, &nRead)) )
3810 TRACE(_T("StreamLoad: Cannot read string: 0x%X\n"), hr);
3811 }
3812 else
3813 {
3814 PWSTR pBufW = reinterpret_cast<PWSTR>(_alloca((nBytes)+1));
3815 if ( FAILED(hr=pStream->Read(pBufW, nBytes, &nRead)) )
3816 TRACE(_T("StreamLoad: Cannot read string: 0x%X\n"), hr);
3817 else
3818 sscpy(pMyBuf, pBufW, hdr.nChars);
3819 }
3820 }
3821 else
3822 {
3823 ULONG nBytes = hdr.nChars * sizeof(char);
3824 if ( sizeof(CT) == sizeof(char) )
3825 {
3826 if ( FAILED(hr=pStream->Read(pMyBuf, nBytes, &nRead)) )
3827 TRACE(_T("StreamLoad: Cannot read string: 0x%X\n"), hr);
3828 }
3829 else
3830 {
3831 PSTR pBufA = reinterpret_cast<PSTR>(_alloca(nBytes));
3832 if ( FAILED(hr=pStream->Read(pBufA, hdr.nChars, &nRead)) )
3833 TRACE(_T("StreamLoad: Cannot read string: 0x%X\n"), hr);
3834 else
3835 sscpy(pMyBuf, pBufA, hdr.nChars);
3836 }
3837 }
3838 }
3839 else
3840 {
3841 this->erase();
3842 }
3843 return hr;
3844 }
3845#endif // #ifdef SS_INC_COMDEF
3846
3847#ifndef SS_ANSI
3848
3849 // SetResourceHandle/GetResourceHandle. In MFC builds, these map directly
3850 // to AfxSetResourceHandle and AfxGetResourceHandle. In non-MFC builds they
3851 // point to a single static HINST so that those who call the member
3852 // functions that take resource IDs can provide an alternate HINST of a DLL
3853 // to search. This is not exactly the list of HMODULES that MFC provides
3854 // but it's better than nothing.
3855
3856 #ifdef _MFC_VER
3857 static void SetResourceHandle(HMODULE hNew)
3858 {
3859 AfxSetResourceHandle(hNew);
3860 }
3861 static HMODULE GetResourceHandle()
3862 {
3863 return AfxGetResourceHandle();
3864 }
3865 #else
3866 static void SetResourceHandle(HMODULE hNew)
3867 {
3868 SSResourceHandle() = hNew;
3869 }
3870 static HMODULE GetResourceHandle()
3871 {
3872 return SSResourceHandle();
3873 }
3874 #endif
3875
3876#endif
3877};
3878
3879// -----------------------------------------------------------------------------
3880// MSVC USERS: HOW TO EXPORT CSTDSTRING FROM A DLL
3881//
3882// If you are using MS Visual C++ and you want to export CStdStringA and
3883// CStdStringW from a DLL, then all you need to
3884//
3885// 1. make sure that all components link to the same DLL version
3886// of the CRT (not the static one).
3887// 2. Uncomment the 3 lines of code below
3888// 3. #define 2 macros per the instructions in MS KnowledgeBase
3889// article Q168958. The macros are:
3890//
3891// MACRO DEFINTION WHEN EXPORTING DEFINITION WHEN IMPORTING
3892// ----- ------------------------ -------------------------
3893// SSDLLEXP (nothing, just #define it) extern
3894// SSDLLSPEC __declspec(dllexport) __declspec(dllimport)
3895//
3896// Note that these macros must be available to ALL clients who want to
3897// link to the DLL and use the class. If they
3898//
3899// A word of advice: Don't bother.
3900//
3901// Really, it is not necessary to export CStdString functions from a DLL. I
3902// never do. In my projects, I do generally link to the DLL version of the
3903// Standard C++ Library, but I do NOT attempt to export CStdString functions.
3904// I simply include the header where it is needed and allow for the code
3905// redundancy.
3906//
3907// That redundancy is a lot less than you think. This class does most of its
3908// work via the Standard C++ Library, particularly the base_class basic_string<>
3909// member functions. Most of the functions here are small enough to be inlined
3910// anyway. Besides, you'll find that in actual practice you use less than 1/2
3911// of the code here, even in big projects and different modules will use as
3912// little as 10% of it. That means a lot less functions actually get linked
3913// your binaries. If you export this code from a DLL, it ALL gets linked in.
3914//
3915// I've compared the size of the binaries from exporting vs NOT exporting. Take
3916// my word for it -- exporting this code is not worth the hassle.
3917//
3918// -----------------------------------------------------------------------------
3919//#pragma warning(disable:4231) // non-standard extension ("extern template")
3920// SSDLLEXP template class SSDLLSPEC CStdStr<char>;
3921// SSDLLEXP template class SSDLLSPEC CStdStr<wchar_t>;
3922
3923
3924// =============================================================================
3925// END OF CStdStr INLINE FUNCTION DEFINITIONS
3926// =============================================================================
3927
3928// Now typedef our class names based upon this humongous template
3929
3930typedef CStdStr<char> CStdStringA; // a better std::string
3931typedef CStdStr<wchar_t> CStdStringW; // a better std::wstring
3932typedef CStdStr<uint16_t> CStdString16; // a 16bit char string
3933typedef CStdStr<uint32_t> CStdString32; // a 32bit char string
3934typedef CStdStr<OLECHAR> CStdStringO; // almost always CStdStringW
3935
3936// -----------------------------------------------------------------------------
3937// CStdStr addition functions defined as inline
3938// -----------------------------------------------------------------------------
3939
3940
3941inline CStdStringA operator+(const CStdStringA& s1, const CStdStringA& s2)
3942{
3943 CStdStringA sRet(SSREF(s1));
3944 sRet.append(s2);
3945 return sRet;
3946}
3947inline CStdStringA operator+(const CStdStringA& s1, CStdStringA::value_type t)
3948{
3949 CStdStringA sRet(SSREF(s1));
3950 sRet.append(1, t);
3951 return sRet;
3952}
3953inline CStdStringA operator+(const CStdStringA& s1, PCSTR pA)
3954{
3955 CStdStringA sRet(SSREF(s1));
3956 sRet.append(pA);
3957 return sRet;
3958}
3959inline CStdStringA operator+(PCSTR pA, const CStdStringA& sA)
3960{
3961 CStdStringA sRet;
3962 CStdStringA::size_type nObjSize = sA.size();
3963 CStdStringA::size_type nLitSize =
3964 static_cast<CStdStringA::size_type>(sslen(pA));
3965
3966 sRet.reserve(nLitSize + nObjSize);
3967 sRet.assign(pA);
3968 sRet.append(sA);
3969 return sRet;
3970}
3971
3972
3973inline CStdStringA operator+(const CStdStringA& s1, const CStdStringW& s2)
3974{
3975 return s1 + CStdStringA(s2);
3976}
3977inline CStdStringW operator+(const CStdStringW& s1, const CStdStringW& s2)
3978{
3979 CStdStringW sRet(SSREF(s1));
3980 sRet.append(s2);
3981 return sRet;
3982}
3983inline CStdStringA operator+(const CStdStringA& s1, PCWSTR pW)
3984{
3985 return s1 + CStdStringA(pW);
3986}
3987
3988#ifdef UNICODE
3989 inline CStdStringW operator+(PCWSTR pW, const CStdStringA& sA)
3990 {
3991 return CStdStringW(pW) + CStdStringW(SSREF(sA));
3992 }
3993 inline CStdStringW operator+(PCSTR pA, const CStdStringW& sW)
3994 {
3995 return CStdStringW(pA) + sW;
3996 }
3997#else
3998 inline CStdStringA operator+(PCWSTR pW, const CStdStringA& sA)
3999 {
4000 return CStdStringA(pW) + sA;
4001 }
4002 inline CStdStringA operator+(PCSTR pA, const CStdStringW& sW)
4003 {
4004 return pA + CStdStringA(sW);
4005 }
4006#endif
4007
4008// ...Now the wide string versions.
4009inline CStdStringW operator+(const CStdStringW& s1, CStdStringW::value_type t)
4010{
4011 CStdStringW sRet(SSREF(s1));
4012 sRet.append(1, t);
4013 return sRet;
4014}
4015inline CStdStringW operator+(const CStdStringW& s1, PCWSTR pW)
4016{
4017 CStdStringW sRet(SSREF(s1));
4018 sRet.append(pW);
4019 return sRet;
4020}
4021inline CStdStringW operator+(PCWSTR pW, const CStdStringW& sW)
4022{
4023 CStdStringW sRet;
4024 CStdStringW::size_type nObjSize = sW.size();
4025 CStdStringA::size_type nLitSize =
4026 static_cast<CStdStringW::size_type>(sslen(pW));
4027
4028 sRet.reserve(nLitSize + nObjSize);
4029 sRet.assign(pW);
4030 sRet.append(sW);
4031 return sRet;
4032}
4033
4034inline CStdStringW operator+(const CStdStringW& s1, const CStdStringA& s2)
4035{
4036 return s1 + CStdStringW(s2);
4037}
4038inline CStdStringW operator+(const CStdStringW& s1, PCSTR pA)
4039{
4040 return s1 + CStdStringW(pA);
4041}
4042
4043
4044// New-style format function is a template
4045
4046#ifdef SS_SAFE_FORMAT
4047
4048template<>
4049struct FmtArg<CStdStringA>
4050{
4051 explicit FmtArg(const CStdStringA& arg) : a_(arg) {}
4052 PCSTR operator()() const { return a_.c_str(); }
4053 const CStdStringA& a_;
4054private:
4055 FmtArg<CStdStringA>& operator=(const FmtArg<CStdStringA>&) { return *this; }
4056};
4057template<>
4058struct FmtArg<CStdStringW>
4059{
4060 explicit FmtArg(const CStdStringW& arg) : a_(arg) {}
4061 PCWSTR operator()() const { return a_.c_str(); }
4062 const CStdStringW& a_;
4063private:
4064 FmtArg<CStdStringW>& operator=(const FmtArg<CStdStringW>&) { return *this; }
4065};
4066
4067template<>
4068struct FmtArg<std::string>
4069{
4070 explicit FmtArg(const std::string& arg) : a_(arg) {}
4071 PCSTR operator()() const { return a_.c_str(); }
4072 const std::string& a_;
4073private:
4074 FmtArg<std::string>& operator=(const FmtArg<std::string>&) { return *this; }
4075};
4076template<>
4077struct FmtArg<std::wstring>
4078{
4079 explicit FmtArg(const std::wstring& arg) : a_(arg) {}
4080 PCWSTR operator()() const { return a_.c_str(); }
4081 const std::wstring& a_;
4082private:
4083 FmtArg<std::wstring>& operator=(const FmtArg<std::wstring>&) {return *this;}
4084};
4085#endif // #ifdef SS_SAFEFORMAT
4086
4087#ifndef SS_ANSI
4088 // SSResourceHandle: our MFC-like resource handle
4089 inline HMODULE& SSResourceHandle()
4090 {
4091 static HMODULE hModuleSS = GetModuleHandle(0);
4092 return hModuleSS;
4093 }
4094#endif
4095
4096
4097// In MFC builds, define some global serialization operators
4098// Special operators that allow us to serialize CStdStrings to CArchives.
4099// Note that we use an intermediate CString object in order to ensure that
4100// we use the exact same format.
4101
4102#ifdef _MFC_VER
4103 inline CArchive& AFXAPI operator<<(CArchive& ar, const CStdStringA& strA)
4104 {
4105 CString strTemp = strA;
4106 return ar << strTemp;
4107 }
4108 inline CArchive& AFXAPI operator<<(CArchive& ar, const CStdStringW& strW)
4109 {
4110 CString strTemp = strW;
4111 return ar << strTemp;
4112 }
4113
4114 inline CArchive& AFXAPI operator>>(CArchive& ar, CStdStringA& strA)
4115 {
4116 CString strTemp;
4117 ar >> strTemp;
4118 strA = strTemp;
4119 return ar;
4120 }
4121 inline CArchive& AFXAPI operator>>(CArchive& ar, CStdStringW& strW)
4122 {
4123 CString strTemp;
4124 ar >> strTemp;
4125 strW = strTemp;
4126 return ar;
4127 }
4128#endif // #ifdef _MFC_VER -- (i.e. is this MFC?)
4129
4130
4131
4132// -----------------------------------------------------------------------------
4133// GLOBAL FUNCTION: WUFormat
4134// CStdStringA WUFormat(UINT nId, ...);
4135// CStdStringA WUFormat(PCSTR szFormat, ...);
4136//
4137// REMARKS:
4138// This function allows the caller for format and return a CStdStringA
4139// object with a single line of code.
4140// -----------------------------------------------------------------------------
4141#ifdef SS_ANSI
4142#else
4143 inline CStdStringA WUFormatA(UINT nId, ...)
4144 {
4145 va_list argList;
4146 va_start(argList, nId);
4147
4148 CStdStringA strFmt;
4149 CStdStringA strOut;
4150 if ( strFmt.Load(nId) )
4151 strOut.FormatV(strFmt, argList);
4152
4153 va_end(argList);
4154 return strOut;
4155 }
4156 inline CStdStringA WUFormatA(PCSTR szFormat, ...)
4157 {
4158 va_list argList;
4159 va_start(argList, szFormat);
4160 CStdStringA strOut;
4161 strOut.FormatV(szFormat, argList);
4162 va_end(argList);
4163 return strOut;
4164 }
4165 inline CStdStringW WUFormatW(UINT nId, ...)
4166 {
4167 va_list argList;
4168 va_start(argList, nId);
4169
4170 CStdStringW strFmt;
4171 CStdStringW strOut;
4172 if ( strFmt.Load(nId) )
4173 strOut.FormatV(strFmt, argList);
4174
4175 va_end(argList);
4176 return strOut;
4177 }
4178 inline CStdStringW WUFormatW(PCWSTR szwFormat, ...)
4179 {
4180 va_list argList;
4181 va_start(argList, szwFormat);
4182 CStdStringW strOut;
4183 strOut.FormatV(szwFormat, argList);
4184 va_end(argList);
4185 return strOut;
4186 }
4187#endif // #ifdef SS_ANSI
4188
4189
4190
4191#if defined(SS_WIN32) && !defined (SS_ANSI)
4192 // -------------------------------------------------------------------------
4193 // FUNCTION: WUSysMessage
4194 // CStdStringA WUSysMessageA(DWORD dwError, DWORD dwLangId=SS_DEFLANGID);
4195 // CStdStringW WUSysMessageW(DWORD dwError, DWORD dwLangId=SS_DEFLANGID);
4196 //
4197 // DESCRIPTION:
4198 // This function simplifies the process of obtaining a string equivalent
4199 // of a system error code returned from GetLastError(). You simply
4200 // supply the value returned by GetLastError() to this function and the
4201 // corresponding system string is returned in the form of a CStdStringA.
4202 //
4203 // PARAMETERS:
4204 // dwError - a DWORD value representing the error code to be translated
4205 // dwLangId - the language id to use. defaults to english.
4206 //
4207 // RETURN VALUE:
4208 // a CStdStringA equivalent of the error code. Currently, this function
4209 // only returns either English of the system default language strings.
4210 // -------------------------------------------------------------------------
4211 #define SS_DEFLANGID MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT)
4212 inline CStdStringA WUSysMessageA(DWORD dwError, DWORD dwLangId=SS_DEFLANGID)
4213 {
4214 CHAR szBuf[512];
4215
4216 if ( 0 != ::FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError,
4217 dwLangId, szBuf, 511, NULL) )
4218 return WUFormatA("%s (0x%X)", szBuf, dwError);
4219 else
4220 return WUFormatA("Unknown error (0x%X)", dwError);
4221 }
4222 inline CStdStringW WUSysMessageW(DWORD dwError, DWORD dwLangId=SS_DEFLANGID)
4223 {
4224 WCHAR szBuf[512];
4225
4226 if ( 0 != ::FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError,
4227 dwLangId, szBuf, 511, NULL) )
4228 return WUFormatW(L"%s (0x%X)", szBuf, dwError);
4229 else
4230 return WUFormatW(L"Unknown error (0x%X)", dwError);
4231 }
4232#endif
4233
4234// Define TCHAR based friendly names for some of these functions
4235
4236#ifdef UNICODE
4237 //#define CStdString CStdStringW
4238 typedef CStdStringW CStdString;
4239 #define WUSysMessage WUSysMessageW
4240 #define WUFormat WUFormatW
4241#else
4242 //#define CStdString CStdStringA
4243 typedef CStdStringA CStdString;
4244 #define WUSysMessage WUSysMessageA
4245 #define WUFormat WUFormatA
4246#endif
4247
4248// ...and some shorter names for the space-efficient
4249
4250#define WUSysMsg WUSysMessage
4251#define WUSysMsgA WUSysMessageA
4252#define WUSysMsgW WUSysMessageW
4253#define WUFmtA WUFormatA
4254#define WUFmtW WUFormatW
4255#define WUFmt WUFormat
4256#define WULastErrMsg() WUSysMessage(::GetLastError())
4257#define WULastErrMsgA() WUSysMessageA(::GetLastError())
4258#define WULastErrMsgW() WUSysMessageW(::GetLastError())
4259
4260
4261// -----------------------------------------------------------------------------
4262// FUNCTIONAL COMPARATORS:
4263// REMARKS:
4264// These structs are derived from the std::binary_function template. They
4265// give us functional classes (which may be used in Standard C++ Library
4266// collections and algorithms) that perform case-insensitive comparisons of
4267// CStdString objects. This is useful for maps in which the key may be the
4268// proper string but in the wrong case.
4269// -----------------------------------------------------------------------------
4270#define StdStringLessNoCaseW SSLNCW // avoid VC compiler warning 4786
4271#define StdStringEqualsNoCaseW SSENCW
4272#define StdStringLessNoCaseA SSLNCA
4273#define StdStringEqualsNoCaseA SSENCA
4274
4275#ifdef UNICODE
4276 #define StdStringLessNoCase SSLNCW
4277 #define StdStringEqualsNoCase SSENCW
4278#else
4279 #define StdStringLessNoCase SSLNCA
4280 #define StdStringEqualsNoCase SSENCA
4281#endif
4282
4283struct StdStringLessNoCaseW
4284 : std::binary_function<CStdStringW, CStdStringW, bool>
4285{
4286 inline
4287 bool operator()(const CStdStringW& sLeft, const CStdStringW& sRight) const
4288 { return ssicmp(sLeft.c_str(), sRight.c_str()) < 0; }
4289};
4290struct StdStringEqualsNoCaseW
4291 : std::binary_function<CStdStringW, CStdStringW, bool>
4292{
4293 inline
4294 bool operator()(const CStdStringW& sLeft, const CStdStringW& sRight) const
4295 { return ssicmp(sLeft.c_str(), sRight.c_str()) == 0; }
4296};
4297struct StdStringLessNoCaseA
4298 : std::binary_function<CStdStringA, CStdStringA, bool>
4299{
4300 inline
4301 bool operator()(const CStdStringA& sLeft, const CStdStringA& sRight) const
4302 { return ssicmp(sLeft.c_str(), sRight.c_str()) < 0; }
4303};
4304struct StdStringEqualsNoCaseA
4305 : std::binary_function<CStdStringA, CStdStringA, bool>
4306{
4307 inline
4308 bool operator()(const CStdStringA& sLeft, const CStdStringA& sRight) const
4309 { return ssicmp(sLeft.c_str(), sRight.c_str()) == 0; }
4310};
4311
4312// If we had to define our own version of TRACE above, get rid of it now
4313
4314#ifdef TRACE_DEFINED_HERE
4315 #undef TRACE
4316 #undef TRACE_DEFINED_HERE
4317#endif
4318
4319
4320// These std::swap specializations come courtesy of Mike Crusader.
4321
4322//namespace std
4323//{
4324// inline void swap(CStdStringA& s1, CStdStringA& s2) throw()
4325// {
4326// s1.swap(s2);
4327// }
4328// template<>
4329// inline void swap(CStdStringW& s1, CStdStringW& s2) throw()
4330// {
4331// s1.swap(s2);
4332// }
4333//}
4334
4335// Turn back on any Borland warnings we turned off.
4336
4337#ifdef __BORLANDC__
4338 #pragma option pop // Turn back on inline function warnings
4339// #pragma warn +inl // Turn back on inline function warnings
4340#endif
4341
4342typedef std::vector<CStdString> CStdStringArray;
4343
4344#endif // #ifndef STDSTRING_H