/[rdesktop]/sourceforge.net/trunk/seamlessrdp/ClientDLL/stdstring.h
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Annotation of /sourceforge.net/trunk/seamlessrdp/ClientDLL/stdstring.h

Parent Directory Parent Directory | Revision Log Revision Log


Revision 937 - (hide annotations)
Fri Jul 1 06:50:52 2005 UTC (18 years, 11 months ago) by astrand
File MIME type: text/plain
File size: 157568 byte(s)
Indenting with astyle instead of indent

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

  ViewVC Help
Powered by ViewVC 1.1.26