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