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