/[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 933 - (hide annotations)
Thu Jun 30 14:46:14 2005 UTC (19 years ago) by astrand
File MIME type: text/plain
File size: 152888 byte(s)
Fixed indentation, by running indent-all.

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     // 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     // Igor Kholodov for noticing this.
171     // - 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 933 // 1999-AUG-20 - Improved Load() function to be more efficient by using
249     // 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     // the first 255 ANSI ones. Thanks to Craig Watson.
253     // - 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     // 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     // words, I copied Microsoft's conversion stuff again.
288     // - 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     // persisting CStdStrings to/from DCOM IStream interfaces
302     // - Added functional objects (e.g. StdStringLessNoCase) that
303     // allow CStdStrings to be used as keys STL map objects with
304     // case-insensitive comparison
305     // - 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     // 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     // that makes money off of it, good for you. I kinda like capitalism.
320     // 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     // Note however that this ONLY works for Format(), not sprintf, fprintf,
415     // 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     // of VC++ specific functions from being called.
465    
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     // Microsoft header files are screwy. Sometimes they depend on a preprocessor
512     // 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     // "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     //
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     // #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     // #define _UNICODE // no longer silently fix this
543     #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     // at least in the MS implementation) that you never know what's available
550     // -----------------------------------------------------------------------------
551 astrand 933 template < class Type >
552     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     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 933 // 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 933 // On Win32 we have TCHAR.H so just include it. This is NOT violating
572 astrand 931 // 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 931 // ... but on non-Win32 platforms, we must #define the types we need.
583    
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 933 // 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 933 // 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 933 // 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 933 // ...and
749     #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     // any preprocessor macro settings since their names won't collide.
769    
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     0};
807     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     0};
846     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    
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    
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    
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     // 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 931 // 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     // (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     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 931 // 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 931 // 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     //CharNextW doesn't work on Win95 so we use this
1042     #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 931 // 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     // std::char_traits<char>::copy(pDst, pSrc, nChars);
1155     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     // std::char_traits<wchar_t>::copy(pDst, pSrc, nChars);
1177     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     // to nothing.
1214     //
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     //
1220     // 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 933 template < typename CT > inline int sslen(const CT * pT)
1237 astrand 930 {
1238 astrand 933 return 0 == pT ? 0 : (int) std::basic_string <
1239     CT >::traits_type::length(pT);
1240     // return 0 == pT ? 0 : std::char_traits<CT>::length(pT);
1241 astrand 930 }
1242 astrand 933 inline SS_NOTHROW int sslen(const std::string & s)
1243 astrand 930 {
1244 astrand 933 return static_cast < int >(s.length());
1245 astrand 930 }
1246 astrand 933 inline SS_NOTHROW int sslen(const std::wstring & s)
1247 astrand 930 {
1248 astrand 933 return static_cast < int >(s.length());
1249 astrand 930 }
1250    
1251 astrand 931 // -----------------------------------------------------------------------------
1252     // sstolower/sstoupper -- convert characters to upper/lower case
1253     // -----------------------------------------------------------------------------
1254 astrand 933 template < typename CT >
1255     inline CT sstolower(const CT & t, const std::locale & loc = std::locale())
1256 astrand 931 {
1257 astrand 933 return std::tolower < CT > (t, loc);
1258 astrand 931 }
1259 astrand 933
1260     template < typename CT >
1261     inline CT sstoupper(const CT & t, const std::locale & loc = std::locale())
1262 astrand 931 {
1263 astrand 933 return std::toupper < CT > (t, loc);
1264 astrand 931 }
1265 astrand 930
1266     // -----------------------------------------------------------------------------
1267     // ssasn: assignment functions -- assign "sSrc" to "sDst"
1268     // -----------------------------------------------------------------------------
1269 astrand 933 typedef std::string::size_type SS_SIZETYPE; // just for shorthand, really
1270     typedef std::string::pointer SS_PTRTYPE;
1271     typedef std::wstring::size_type SW_SIZETYPE;
1272     typedef std::wstring::pointer SW_PTRTYPE;
1273 astrand 930
1274 astrand 933 inline void ssasn(std::string & sDst, const std::string & sSrc)
1275 astrand 930 {
1276 astrand 933 if (sDst.c_str() != sSrc.c_str()) {
1277     sDst.erase();
1278     sDst.assign(SSREF(sSrc));
1279     }
1280 astrand 930 }
1281 astrand 933 inline void ssasn(std::string & sDst, PCSTR pA)
1282 astrand 930 {
1283 astrand 933 // Watch out for NULLs, as always.
1284 astrand 930
1285 astrand 933 if (0 == pA) {
1286     sDst.erase();
1287     }
1288 astrand 930
1289 astrand 933 // If pA actually points to part of sDst, we must NOT erase(), but
1290     // rather take a substring
1291 astrand 930
1292 astrand 933 else if (pA >= sDst.c_str() && pA <= sDst.c_str() + sDst.size()) {
1293     sDst = sDst.substr(static_cast < SS_SIZETYPE > (pA - sDst.c_str()));
1294     }
1295 astrand 930
1296 astrand 933 // Otherwise (most cases) apply the assignment bug fix, if applicable
1297     // and do the assignment
1298 astrand 930
1299 astrand 933 else {
1300     Q172398(sDst);
1301     sDst.assign(pA);
1302     }
1303 astrand 930 }
1304 astrand 933 inline void ssasn(std::string & sDst, const std::wstring & sSrc)
1305 astrand 930 {
1306 astrand 933 if (sSrc.empty()) {
1307     sDst.erase();
1308     }
1309     else {
1310     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 933 nDst = static_cast < int >(static_cast < double >(nDst) * 1.3);
1317 astrand 931 #endif
1318    
1319 astrand 933 sDst.resize(nDst + 1);
1320     PCSTR szCvt =
1321     StdCodeCvt(const_cast < SS_PTRTYPE > (sDst.data()), nDst,
1322     sSrc.c_str(), static_cast < int >(sSrc.size()));
1323 astrand 931
1324 astrand 933 // In MBCS builds, we don't know how long the destination string will be.
1325 astrand 931
1326     #ifdef SS_MBCS
1327 astrand 933 sDst.resize(sslen(szCvt));
1328 astrand 930 #else
1329 astrand 933 szCvt;
1330     sDst.resize(sSrc.size());
1331 astrand 930 #endif
1332 astrand 933 }
1333 astrand 930 }
1334 astrand 933 inline void ssasn(std::string & sDst, PCWSTR pW)
1335 astrand 930 {
1336 astrand 933 int nSrc = sslen(pW);
1337     if (nSrc > 0) {
1338     int nSrc = sslen(pW);
1339     int nDst = nSrc;
1340 astrand 931
1341 astrand 933 // In MBCS builds, pad the buffer to account for the possibility of
1342     // some 3 byte characters. Not perfect but should get most cases.
1343 astrand 931
1344     #ifdef SS_MBCS
1345 astrand 933 nDst = static_cast < int >(static_cast < double >(nDst) * 1.3);
1346 astrand 931 #endif
1347    
1348 astrand 933 sDst.resize(nDst + 1);
1349     PCSTR szCvt =
1350     StdCodeCvt(const_cast < SS_PTRTYPE > (sDst.data()), nDst,
1351     pW, nSrc);
1352 astrand 931
1353 astrand 933 // In MBCS builds, we don't know how long the destination string will be.
1354 astrand 931
1355     #ifdef SS_MBCS
1356 astrand 933 sDst.resize(sslen(szCvt));
1357 astrand 930 #else
1358 astrand 933 sDst.resize(nDst);
1359     szCvt;
1360 astrand 930 #endif
1361 astrand 933 }
1362     else {
1363     sDst.erase();
1364     }
1365 astrand 930 }
1366 astrand 933 inline void ssasn(std::string & sDst, const int nNull)
1367 astrand 930 {
1368 astrand 933 UNUSED(nNull);
1369     ASSERT(nNull == 0);
1370     sDst.assign("");
1371     }
1372     inline void ssasn(std::wstring & sDst, const std::wstring & sSrc)
1373 astrand 930 {
1374 astrand 933 if (sDst.c_str() != sSrc.c_str()) {
1375     sDst.erase();
1376     sDst.assign(SSREF(sSrc));
1377     }
1378 astrand 930 }
1379 astrand 933 inline void ssasn(std::wstring & sDst, PCWSTR pW)
1380 astrand 930 {
1381 astrand 933 // Watch out for NULLs, as always.
1382 astrand 930
1383 astrand 933 if (0 == pW) {
1384     sDst.erase();
1385     }
1386 astrand 930
1387 astrand 933 // If pW actually points to part of sDst, we must NOT erase(), but
1388     // rather take a substring
1389 astrand 930
1390 astrand 933 else if (pW >= sDst.c_str() && pW <= sDst.c_str() + sDst.size()) {
1391     sDst = sDst.substr(static_cast < SW_SIZETYPE > (pW - sDst.c_str()));
1392     }
1393 astrand 930
1394 astrand 933 // Otherwise (most cases) apply the assignment bug fix, if applicable
1395     // and do the assignment
1396 astrand 930
1397 astrand 933 else {
1398     Q172398(sDst);
1399     sDst.assign(pW);
1400     }
1401 astrand 930 }
1402 astrand 933
1403 astrand 930 #undef StrSizeType
1404 astrand 933 inline void ssasn(std::wstring & sDst, const std::string & sSrc)
1405 astrand 930 {
1406 astrand 933 if (sSrc.empty()) {
1407     sDst.erase();
1408     }
1409     else {
1410     int nSrc = static_cast < int >(sSrc.size());
1411     int nDst = nSrc;
1412 astrand 931
1413 astrand 933 sDst.resize(nSrc + 1);
1414     PCWSTR szCvt =
1415     StdCodeCvt(const_cast < SW_PTRTYPE > (sDst.data()), nDst,
1416     sSrc.c_str(), nSrc);
1417 astrand 931
1418 astrand 933 sDst.resize(sslen(szCvt));
1419     }
1420 astrand 930 }
1421 astrand 933 inline void ssasn(std::wstring & sDst, PCSTR pA)
1422 astrand 930 {
1423 astrand 933 int nSrc = sslen(pA);
1424 astrand 931
1425 astrand 933 if (0 == nSrc) {
1426     sDst.erase();
1427     }
1428     else {
1429     int nDst = nSrc;
1430     sDst.resize(nDst + 1);
1431     PCWSTR szCvt =
1432     StdCodeCvt(const_cast < SW_PTRTYPE > (sDst.data()), nDst, pA,
1433     nSrc);
1434 astrand 931
1435 astrand 933 sDst.resize(sslen(szCvt));
1436     }
1437 astrand 930 }
1438 astrand 933 inline void ssasn(std::wstring & sDst, const int nNull)
1439 astrand 930 {
1440 astrand 933 UNUSED(nNull);
1441     ASSERT(nNull == 0);
1442     sDst.assign(L"");
1443 astrand 930 }
1444    
1445    
1446     // -----------------------------------------------------------------------------
1447     // ssadd: string object concatenation -- add second argument to first
1448     // -----------------------------------------------------------------------------
1449 astrand 933 inline void ssadd(std::string & sDst, const std::wstring & sSrc)
1450 astrand 930 {
1451 astrand 933 int nSrc = static_cast < int >(sSrc.size());
1452 astrand 931
1453 astrand 933 if (nSrc > 0) {
1454     int nDst = static_cast < int >(sDst.size());
1455     int nAdd = nSrc;
1456 astrand 931
1457 astrand 933 // In MBCS builds, pad the buffer to account for the possibility of
1458     // some 3 byte characters. Not perfect but should get most cases.
1459 astrand 931
1460     #ifdef SS_MBCS
1461 astrand 933 nAdd = static_cast < int >(static_cast < double >(nAdd) * 1.3);
1462 astrand 931 #endif
1463    
1464 astrand 933 sDst.resize(nDst + nAdd + 1);
1465     PCSTR szCvt =
1466     StdCodeCvt(const_cast < SS_PTRTYPE > (sDst.data() + nDst),
1467     nAdd, sSrc.c_str(), nSrc);
1468 astrand 931
1469     #ifdef SS_MBCS
1470 astrand 933 sDst.resize(nDst + sslen(szCvt));
1471 astrand 930 #else
1472 astrand 933 sDst.resize(nDst + nAdd);
1473     szCvt;
1474 astrand 930 #endif
1475 astrand 933 }
1476 astrand 930 }
1477 astrand 933 inline void ssadd(std::string & sDst, const std::string & sSrc)
1478 astrand 931 {
1479 astrand 933 sDst += sSrc;
1480 astrand 930 }
1481 astrand 933 inline void ssadd(std::string & sDst, PCWSTR pW)
1482 astrand 930 {
1483 astrand 933 int nSrc = sslen(pW);
1484     if (nSrc > 0) {
1485     int nDst = static_cast < int >(sDst.size());
1486     int nAdd = nSrc;
1487 astrand 931
1488     #ifdef SS_MBCS
1489 astrand 933 nAdd = static_cast < int >(static_cast < double >(nAdd) * 1.3);
1490 astrand 931 #endif
1491    
1492 astrand 933 sDst.resize(nDst + nAdd + 1);
1493     PCSTR szCvt =
1494     StdCodeCvt(const_cast < SS_PTRTYPE > (sDst.data() + nDst),
1495     nAdd, pW, nSrc);
1496 astrand 931
1497     #ifdef SS_MBCS
1498 astrand 933 sDst.resize(nDst + sslen(szCvt));
1499 astrand 930 #else
1500 astrand 933 sDst.resize(nDst + nSrc);
1501     szCvt;
1502 astrand 930 #endif
1503 astrand 933 }
1504 astrand 930 }
1505 astrand 933 inline void ssadd(std::string & sDst, PCSTR pA)
1506 astrand 930 {
1507 astrand 933 if (pA) {
1508     // If the string being added is our internal string or a part of our
1509     // internal string, then we must NOT do any reallocation without
1510     // first copying that string to another object (since we're using a
1511     // direct pointer)
1512 astrand 931
1513 astrand 933 if (pA >= sDst.c_str() && pA <= sDst.c_str() + sDst.length()) {
1514     if (sDst.capacity() <= sDst.size() + sslen(pA))
1515     sDst.append(std::string(pA));
1516     else
1517     sDst.append(pA);
1518     }
1519     else {
1520     sDst.append(pA);
1521     }
1522     }
1523 astrand 930 }
1524 astrand 933 inline void ssadd(std::wstring & sDst, const std::wstring & sSrc)
1525 astrand 930 {
1526 astrand 933 sDst += sSrc;
1527 astrand 930 }
1528 astrand 933 inline void ssadd(std::wstring & sDst, const std::string & sSrc)
1529 astrand 930 {
1530 astrand 933 if (!sSrc.empty()) {
1531     int nSrc = static_cast < int >(sSrc.size());
1532     int nDst = static_cast < int >(sDst.size());
1533 astrand 931
1534 astrand 933 sDst.resize(nDst + nSrc + 1);
1535     PCWSTR szCvt =
1536     StdCodeCvt(const_cast < SW_PTRTYPE > (sDst.data() + nDst),
1537     nSrc, sSrc.c_str(), nSrc + 1);
1538 astrand 931
1539     #ifdef SS_MBCS
1540 astrand 933 sDst.resize(nDst + sslen(szCvt));
1541 astrand 930 #else
1542 astrand 933 sDst.resize(nDst + nSrc);
1543     szCvt;
1544 astrand 930 #endif
1545 astrand 933 }
1546 astrand 930 }
1547 astrand 933 inline void ssadd(std::wstring & sDst, PCSTR pA)
1548 astrand 930 {
1549 astrand 933 int nSrc = sslen(pA);
1550 astrand 931
1551 astrand 933 if (nSrc > 0) {
1552     int nDst = static_cast < int >(sDst.size());
1553 astrand 931
1554 astrand 933 sDst.resize(nDst + nSrc + 1);
1555     PCWSTR szCvt =
1556     StdCodeCvt(const_cast < SW_PTRTYPE > (sDst.data() + nDst),
1557     nSrc, pA, nSrc + 1);
1558 astrand 931
1559     #ifdef SS_MBCS
1560 astrand 933 sDst.resize(nDst + sslen(szCvt));
1561 astrand 930 #else
1562 astrand 933 sDst.resize(nDst + nSrc);
1563     szCvt;
1564 astrand 930 #endif
1565 astrand 933 }
1566 astrand 930 }
1567 astrand 933 inline void ssadd(std::wstring & sDst, PCWSTR pW)
1568 astrand 930 {
1569 astrand 933 if (pW) {
1570     // If the string being added is our internal string or a part of our
1571     // internal string, then we must NOT do any reallocation without
1572     // first copying that string to another object (since we're using a
1573     // direct pointer)
1574 astrand 930
1575 astrand 933 if (pW >= sDst.c_str() && pW <= sDst.c_str() + sDst.length()) {
1576     if (sDst.capacity() <= sDst.size() + sslen(pW))
1577     sDst.append(std::wstring(pW));
1578     else
1579     sDst.append(pW);
1580     }
1581     else {
1582     sDst.append(pW);
1583     }
1584     }
1585 astrand 931 }
1586 astrand 930
1587 astrand 931
1588 astrand 930 // -----------------------------------------------------------------------------
1589 astrand 931 // sscmp: comparison (case sensitive, not affected by locale)
1590     // -----------------------------------------------------------------------------
1591 astrand 933 template < typename CT > inline int sscmp(const CT * pA1, const CT * pA2)
1592 astrand 931 {
1593     CT f;
1594     CT l;
1595    
1596 astrand 933 do {
1597     f = *(pA1++);
1598     l = *(pA2++);
1599     } while ((f) && (f == l));
1600 astrand 931
1601 astrand 933 return (int) (f - l);
1602 astrand 931 }
1603    
1604     // -----------------------------------------------------------------------------
1605     // ssicmp: comparison (case INsensitive, not affected by locale)
1606     // -----------------------------------------------------------------------------
1607 astrand 933 template < typename CT > inline int ssicmp(const CT * pA1, const CT * pA2)
1608 astrand 931 {
1609 astrand 933 // Using the "C" locale = "not affected by locale"
1610 astrand 931
1611 astrand 933 std::locale loc = std::locale::classic();
1612     const std::ctype < CT > &ct = SS_USE_FACET(loc, std::ctype < CT >);
1613 astrand 931 CT f;
1614     CT l;
1615    
1616 astrand 933 do {
1617     f = ct.tolower(*(pA1++));
1618     l = ct.tolower(*(pA2++));
1619     } while ((f) && (f == l));
1620 astrand 931
1621 astrand 933 return (int) (f - l);
1622 astrand 931 }
1623    
1624     // -----------------------------------------------------------------------------
1625 astrand 930 // ssupr/sslwr: Uppercase/Lowercase conversion functions
1626     // -----------------------------------------------------------------------------
1627 astrand 931
1628 astrand 933 template < typename CT >
1629     inline void sslwr(CT * pT, size_t nLen, const std::locale & loc =
1630     std::locale())
1631 astrand 931 {
1632 astrand 933 SS_USE_FACET(loc, std::ctype < CT >).tolower(pT, pT + nLen);
1633 astrand 931 }
1634 astrand 933 template < typename CT >
1635     inline void ssupr(CT * pT, size_t nLen, const std::locale & loc =
1636     std::locale())
1637 astrand 931 {
1638 astrand 933 SS_USE_FACET(loc, std::ctype < CT >).toupper(pT, pT + nLen);
1639 astrand 931 }
1640    
1641     // -----------------------------------------------------------------------------
1642     // vsprintf/vswprintf or _vsnprintf/_vsnwprintf equivalents. In standard
1643     // builds we can't use _vsnprintf/_vsnwsprintf because they're MS extensions.
1644     //
1645     // -----------------------------------------------------------------------------
1646     // Borland's headers put some ANSI "C" functions in the 'std' namespace.
1647     // Promote them to the global namespace so we can use them here.
1648    
1649     #if defined(__BORLANDC__)
1650 astrand 933 using std::vsprintf;
1651     using std::vswprintf;
1652 astrand 931 #endif
1653    
1654 astrand 933 // GNU is supposed to have vsnprintf and vsnwprintf. But only the newer
1655     // distributions do.
1656 astrand 931
1657     #if defined(__GNUC__)
1658    
1659 astrand 933 inline int ssvsprintf(PSTR pA, size_t nCount, PCSTR pFmtA, va_list vl)
1660     {
1661     return vsnprintf(pA, nCount, pFmtA, vl);
1662     }
1663     inline int ssvsprintf(PWSTR pW, size_t nCount, PCWSTR pFmtW, va_list vl)
1664     {
1665     return vswprintf(pW, nCount, pFmtW, vl);
1666     }
1667 astrand 931
1668 astrand 933 // Microsofties can use
1669 astrand 931 #elif defined(_MSC_VER) && !defined(SS_ANSI)
1670    
1671 astrand 933 inline int ssnprintf(PSTR pA, size_t nCount, PCSTR pFmtA, va_list vl)
1672     {
1673     return _vsnprintf(pA, nCount, pFmtA, vl);
1674     }
1675     inline int ssnprintf(PWSTR pW, size_t nCount, PCWSTR pFmtW, va_list vl)
1676     {
1677     return _vsnwprintf(pW, nCount, pFmtW, vl);
1678     }
1679 astrand 931
1680     #elif !defined (SS_DANGEROUS_FORMAT)
1681    
1682 astrand 933 // GOT COMPILER PROBLEMS HERE?
1683     // ---------------------------
1684     // Does your compiler choke on one or more of the following 2 functions? It
1685     // probably means that you don't have have either vsnprintf or vsnwprintf in
1686     // your version of the CRT. This is understandable since neither is an ANSI
1687     // "C" function. However it still leaves you in a dilemma. In order to make
1688     // this code build, you're going to have to to use some non-length-checked
1689     // formatting functions that every CRT has: vsprintf and vswprintf.
1690     //
1691     // This is very dangerous. With the proper erroneous (or malicious) code, it
1692     // can lead to buffer overlows and crashing your PC. Use at your own risk
1693     // In order to use them, just #define SS_DANGEROUS_FORMAT at the top of
1694     // this file.
1695     //
1696     // Even THEN you might not be all the way home due to some non-conforming
1697     // distributions. More on this in the comments below.
1698 astrand 931
1699 astrand 933 inline int ssnprintf(PSTR pA, size_t nCount, PCSTR pFmtA, va_list vl)
1700     {
1701     return vsnprintf(pA, nCount, pFmtA, vl);
1702     }
1703     inline int ssnprintf(PWSTR pW, size_t nCount, PCWSTR pFmtW, va_list vl)
1704     {
1705     return vsnwprintf(pW, nCount, pFmtW, vl);
1706     }
1707 astrand 930
1708 astrand 931 #else
1709    
1710 astrand 933 inline int ssvsprintf(PSTR pA, size_t /*nCount */ , PCSTR pFmtA, va_list vl)
1711     {
1712     return vsprintf(pA, pFmtA, vl);
1713     }
1714 astrand 931
1715 astrand 933 inline int ssvsprintf(PWSTR pW, size_t nCount, PCWSTR pFmtW, va_list vl)
1716     {
1717     // JMO: Some distributions of the "C" have a version of vswprintf that
1718     // takes 3 arguments (e.g. Microsoft, Borland, GNU). Others have a
1719     // version which takes 4 arguments (an extra "count" argument in the
1720     // second position. The best stab I can take at this so far is that if
1721     // you are NOT running with MS, Borland, or GNU, then I'll assume you
1722     // have the version that takes 4 arguments.
1723     //
1724     // I'm sure that these checks don't catch every platform correctly so if
1725     // you get compiler errors on one of the lines immediately below, it's
1726     // probably because your implemntation takes a different number of
1727     // arguments. You can comment out the offending line (and use the
1728     // alternate version) or you can figure out what compiler flag to check
1729     // and add that preprocessor check in. Regardless, if you get an error
1730     // on these lines, I'd sure like to hear from you about it.
1731     //
1732     // Thanks to Ronny Schulz for the SGI-specific checks here.
1733 astrand 931
1734 astrand 933 // #if !defined(__MWERKS__) && !defined(__SUNPRO_CC_COMPAT) && !defined(__SUNPRO_CC)
1735     #if !defined(_MSC_VER) \
1736 astrand 931 && !defined (__BORLANDC__) \
1737     && !defined(__GNUC__) \
1738     && !defined(__sgi)
1739    
1740 astrand 933 return vswprintf(pW, nCount, pFmtW, vl);
1741 astrand 931
1742     // suddenly with the current SGI 7.3 compiler there is no such function as
1743     // vswprintf and the substitute needs explicit casts to compile
1744    
1745 astrand 933 #elif defined(__sgi)
1746 astrand 931
1747 astrand 933 nCount;
1748     return vsprintf((char *) pW, (char *) pFmtW, vl);
1749 astrand 931
1750 astrand 933 #else
1751 astrand 931
1752 astrand 933 nCount;
1753     return vswprintf(pW, pFmtW, vl);
1754 astrand 931
1755 astrand 933 #endif
1756 astrand 931
1757 astrand 933 }
1758 astrand 931
1759 astrand 930 #endif
1760    
1761    
1762 astrand 931
1763 astrand 930 // -----------------------------------------------------------------------------
1764     // ssload: Type safe, overloaded ::LoadString wrappers
1765     // There is no equivalent of these in non-Win32-specific builds. However, I'm
1766     // thinking that with the message facet, there might eventually be one
1767     // -----------------------------------------------------------------------------
1768 astrand 931 #if defined (SS_WIN32) && !defined(SS_ANSI)
1769 astrand 933 inline int ssload(HMODULE hInst, UINT uId, PSTR pBuf, int nMax)
1770     {
1771     return::LoadStringA(hInst, uId, pBuf, nMax);
1772     }
1773     inline int ssload(HMODULE hInst, UINT uId, PWSTR pBuf, int nMax)
1774     {
1775     return::LoadStringW(hInst, uId, pBuf, nMax);
1776     }
1777 astrand 930 #endif
1778    
1779    
1780     // -----------------------------------------------------------------------------
1781     // sscoll/ssicoll: Collation wrappers
1782 astrand 933 // Note -- with MSVC I have reversed the arguments order here because the
1783     // functions appear to return the opposite of what they should
1784 astrand 930 // -----------------------------------------------------------------------------
1785 astrand 933 template < typename CT >
1786     inline int sscoll(const CT * sz1, int nLen1, const CT * sz2, int nLen2)
1787 astrand 931 {
1788 astrand 933 const std::collate < CT > &coll =
1789     SS_USE_FACET(std::locale(), std::collate < CT >);
1790 astrand 930
1791 astrand 933 return coll.compare(sz2, sz2 + nLen2, sz1, sz1 + nLen1);
1792 astrand 931 }
1793 astrand 933 template < typename CT >
1794     inline int ssicoll(const CT * sz1, int nLen1, const CT * sz2, int nLen2)
1795 astrand 931 {
1796 astrand 933 const std::locale loc;
1797     const std::collate < CT > &coll = SS_USE_FACET(loc, std::collate < CT >);
1798 astrand 930
1799 astrand 933 // Some implementations seem to have trouble using the collate<>
1800     // facet typedefs so we'll just default to basic_string and hope
1801     // that's what the collate facet uses (which it generally should)
1802 astrand 930
1803 astrand 933 // std::collate<CT>::string_type s1(sz1);
1804     // std::collate<CT>::string_type s2(sz2);
1805     const std::basic_string < CT > sEmpty;
1806     std::basic_string < CT > s1(sz1 ? sz1 : sEmpty.c_str());
1807     std::basic_string < CT > s2(sz2 ? sz2 : sEmpty.c_str());
1808 astrand 930
1809 astrand 933 sslwr(const_cast < CT * >(s1.c_str()), nLen1, loc);
1810     sslwr(const_cast < CT * >(s2.c_str()), nLen2, loc);
1811     return coll.compare(s2.c_str(), s2.c_str() + nLen2,
1812     s1.c_str(), s1.c_str() + nLen1);
1813 astrand 931 }
1814 astrand 930
1815 astrand 931
1816    
1817 astrand 930 // -----------------------------------------------------------------------------
1818     // ssfmtmsg: FormatMessage equivalents. Needed because I added a CString facade
1819     // Again -- no equivalent of these on non-Win32 builds but their might one day
1820     // be one if the message facet gets implemented
1821     // -----------------------------------------------------------------------------
1822 astrand 931 #if defined (SS_WIN32) && !defined(SS_ANSI)
1823 astrand 933 inline DWORD ssfmtmsg(DWORD dwFlags, LPCVOID pSrc, DWORD dwMsgId,
1824     DWORD dwLangId, PSTR pBuf, DWORD nSize,
1825     va_list * vlArgs)
1826     {
1827     return FormatMessageA(dwFlags, pSrc, dwMsgId, dwLangId,
1828     pBuf, nSize, vlArgs);
1829     }
1830     inline DWORD ssfmtmsg(DWORD dwFlags, LPCVOID pSrc, DWORD dwMsgId,
1831     DWORD dwLangId, PWSTR pBuf, DWORD nSize,
1832     va_list * vlArgs)
1833     {
1834     return FormatMessageW(dwFlags, pSrc, dwMsgId, dwLangId,
1835     pBuf, nSize, vlArgs);
1836     }
1837 astrand 931 #else
1838 astrand 930 #endif
1839    
1840    
1841 astrand 933
1842 astrand 930 // FUNCTION: sscpy. Copies up to 'nMax' characters from pSrc to pDst.
1843     // -----------------------------------------------------------------------------
1844     // FUNCTION: sscpy
1845 astrand 933 // inline int sscpy(PSTR pDst, PCSTR pSrc, int nMax=-1);
1846     // inline int sscpy(PUSTR pDst, PCSTR pSrc, int nMax=-1)
1847     // inline int sscpy(PSTR pDst, PCWSTR pSrc, int nMax=-1);
1848     // inline int sscpy(PWSTR pDst, PCWSTR pSrc, int nMax=-1);
1849     // inline int sscpy(PWSTR pDst, PCSTR pSrc, int nMax=-1);
1850 astrand 930 //
1851     // DESCRIPTION:
1852 astrand 933 // This function is very much (but not exactly) like strcpy. These
1853     // overloads simplify copying one C-style string into another by allowing
1854     // the caller to specify two different types of strings if necessary.
1855 astrand 930 //
1856 astrand 933 // The strings must NOT overlap
1857 astrand 930 //
1858 astrand 933 // "Character" is expressed in terms of the destination string, not
1859     // the source. If no 'nMax' argument is supplied, then the number of
1860     // characters copied will be sslen(pSrc). A NULL terminator will
1861     // also be added so pDst must actually be big enough to hold nMax+1
1862     // characters. The return value is the number of characters copied,
1863     // not including the NULL terminator.
1864 astrand 930 //
1865     // PARAMETERS:
1866 astrand 933 // pSrc - the string to be copied FROM. May be a char based string, an
1867     // MBCS string (in Win32 builds) or a wide string (wchar_t).
1868     // pSrc - the string to be copied TO. Also may be either MBCS or wide
1869     // nMax - the maximum number of characters to be copied into szDest. Note
1870     // that this is expressed in whatever a "character" means to pDst.
1871     // If pDst is a wchar_t type string than this will be the maximum
1872     // number of wchar_ts that my be copied. The pDst string must be
1873     // large enough to hold least nMaxChars+1 characters.
1874     // If the caller supplies no argument for nMax this is a signal to
1875     // the routine to copy all the characters in pSrc, regardless of
1876     // how long it is.
1877 astrand 930 //
1878     // RETURN VALUE: none
1879     // -----------------------------------------------------------------------------
1880 astrand 933 template < typename CT1, typename CT2 >
1881     inline int sscpycvt(CT1 * pDst, const CT2 * pSrc, int nMax)
1882 astrand 930 {
1883 astrand 933 // Note -- we assume pDst is big enough to hold pSrc. If not, we're in
1884     // big trouble. No bounds checking. Caveat emptor.
1885 astrand 931
1886 astrand 933 int nSrc = sslen(pSrc);
1887 astrand 931
1888 astrand 933 const CT1 *szCvt = StdCodeCvt(pDst, nMax, pSrc, nSrc);
1889 astrand 931
1890 astrand 933 // If we're copying the same size characters, then all the "code convert"
1891     // just did was basically memcpy so the #of characters copied is the same
1892     // as the number requested. I should probably specialize this function
1893     // template to achieve this purpose as it is silly to do a runtime check
1894     // of a fact known at compile time. I'll get around to it.
1895    
1896     return sslen(szCvt);
1897 astrand 930 }
1898    
1899 astrand 931 inline int sscpycvt(PSTR pDst, PCSTR pSrc, int nMax)
1900     {
1901 astrand 933 int nCount = nMax;
1902     for (; nCount > 0 && *pSrc; ++pSrc, ++pDst, --nCount)
1903     std::basic_string < char >::traits_type::assign(*pDst, *pSrc);
1904 astrand 931
1905 astrand 933 *pDst = '\0';
1906     return nMax - nCount;
1907 astrand 931 }
1908     inline int sscpycvt(PWSTR pDst, PCWSTR pSrc, int nMax)
1909     {
1910 astrand 933 int nCount = nMax;
1911     for (; nCount > 0 && *pSrc; ++pSrc, ++pDst, --nCount)
1912     std::basic_string < wchar_t >::traits_type::assign(*pDst, *pSrc);
1913 astrand 931
1914 astrand 933 *pDst = L'\0';
1915     return nMax - nCount;
1916 astrand 931 }
1917     inline int sscpycvt(PWSTR pDst, PCSTR pSrc, int nMax)
1918     {
1919 astrand 933 // Note -- we assume pDst is big enough to hold pSrc. If not, we're in
1920     // big trouble. No bounds checking. Caveat emptor.
1921 astrand 931
1922 astrand 933 const PWSTR szCvt = StdCodeCvt(pDst, nMax, pSrc, nMax);
1923     return sslen(szCvt);
1924 astrand 931 }
1925    
1926 astrand 933 template < typename CT1, typename CT2 >
1927     inline int sscpy(CT1 * pDst, const CT2 * pSrc, int nMax, int nLen)
1928 astrand 930 {
1929 astrand 933 return sscpycvt(pDst, pSrc, SSMIN(nMax, nLen));
1930 astrand 930 }
1931 astrand 933 template < typename CT1, typename CT2 >
1932     inline int sscpy(CT1 * pDst, const CT2 * pSrc, int nMax)
1933 astrand 930 {
1934 astrand 933 return sscpycvt(pDst, pSrc, SSMIN(nMax, sslen(pSrc)));
1935 astrand 930 }
1936 astrand 933 template < typename CT1, typename CT2 >
1937     inline int sscpy(CT1 * pDst, const CT2 * pSrc)
1938 astrand 930 {
1939 astrand 933 return sscpycvt(pDst, pSrc, sslen(pSrc));
1940 astrand 930 }
1941 astrand 933 template < typename CT1, typename CT2 >
1942     inline int sscpy(CT1 * pDst, const std::basic_string < CT2 > &sSrc,
1943     int nMax)
1944 astrand 930 {
1945 astrand 933 return sscpycvt(pDst, sSrc.c_str(), SSMIN(nMax, (int) sSrc.length()));
1946 astrand 930 }
1947 astrand 933 template < typename CT1, typename CT2 >
1948     inline int sscpy(CT1 * pDst, const std::basic_string < CT2 > &sSrc)
1949 astrand 930 {
1950 astrand 933 return sscpycvt(pDst, sSrc.c_str(), (int) sSrc.length());
1951 astrand 930 }
1952    
1953     #ifdef SS_INC_COMDEF
1954 astrand 933 template < typename CT1 >
1955     inline int sscpy(CT1 * pDst, const _bstr_t & bs, int nMax)
1956     {
1957     return sscpycvt(pDst, static_cast < PCOLESTR > (bs),
1958     SSMIN(nMax, static_cast < int >(bs.length())));
1959     }
1960     template < typename CT1 > inline int sscpy(CT1 * pDst, const _bstr_t & bs)
1961     {
1962     return sscpy(pDst, bs, static_cast < int >(bs.length()));
1963     }
1964 astrand 930 #endif
1965    
1966    
1967     // -----------------------------------------------------------------------------
1968     // Functional objects for changing case. They also let you pass locales
1969     // -----------------------------------------------------------------------------
1970    
1971 astrand 933 template < typename CT >
1972     struct SSToUpper:public std::binary_function < CT, std::locale, CT >
1973 astrand 931 {
1974 astrand 933 inline CT operator() (const CT & t, const std::locale & loc) const
1975 astrand 931 {
1976 astrand 933 return sstoupper < CT > (t, loc);
1977 astrand 931 }
1978     };
1979 astrand 933 template < typename CT >
1980     struct SSToLower:public std::binary_function < CT, std::locale, CT >
1981 astrand 931 {
1982 astrand 933 inline CT operator() (const CT & t, const std::locale & loc) const
1983 astrand 931 {
1984 astrand 933 return sstolower < CT > (t, loc);
1985 astrand 931 }
1986     };
1987 astrand 930
1988     // This struct is used for TrimRight() and TrimLeft() function implementations.
1989     //template<typename CT>
1990     //struct NotSpace : public std::unary_function<CT, bool>
1991     //{
1992 astrand 933 // const std::locale& loc;
1993     // inline NotSpace(const std::locale& locArg) : loc(locArg) {}
1994     // inline bool operator() (CT t) { return !std::isspace(t, loc); }
1995 astrand 930 //};
1996 astrand 933 template < typename CT >
1997     struct NotSpace:public std::unary_function < CT, bool >
1998 astrand 930 {
1999 astrand 933 // DINKUMWARE BUG:
2000     // Note -- using std::isspace in a COM DLL gives us access violations
2001     // because it causes the dynamic addition of a function to be called
2002     // when the library shuts down. Unfortunately the list is maintained
2003     // in DLL memory but the function is in static memory. So the COM DLL
2004     // goes away along with the function that was supposed to be called,
2005     // and then later when the DLL CRT shuts down it unloads the list and
2006     // tries to call the long-gone function.
2007     // This is DinkumWare's implementation problem. If you encounter this
2008     // problem, you may replace the calls here with good old isspace() and
2009     // iswspace() from the CRT unless they specify SS_ANSI
2010    
2011     const std::locale loc;
2012     NotSpace(const std::locale & locArg = std::locale()):loc(locArg) {
2013     }
2014     bool operator() (CT t) const
2015     {
2016     return !std::isspace(t, loc);
2017     }
2018 astrand 930 };
2019    
2020    
2021    
2022    
2023 astrand 933 // Now we can define the template (finally!)
2024 astrand 930 // =============================================================================
2025     // TEMPLATE: CStdStr
2026 astrand 933 // template<typename CT> class CStdStr : public std::basic_string<CT>
2027 astrand 930 //
2028     // REMARKS:
2029 astrand 933 // This template derives from basic_string<CT> and adds some MFC CString-
2030     // like functionality
2031 astrand 930 //
2032 astrand 933 // Basically, this is my attempt to make Standard C++ library strings as
2033     // easy to use as the MFC CString class.
2034 astrand 930 //
2035 astrand 933 // Note that although this is a template, it makes the assumption that the
2036     // template argument (CT, the character type) is either char or wchar_t.
2037 astrand 930 // =============================================================================
2038    
2039 astrand 933 //#define CStdStr _SS // avoid compiler warning 4786
2040 astrand 930
2041 astrand 931 // template<typename ARG> ARG& FmtArg(ARG& arg) { return arg; }
2042     // PCSTR FmtArg(const std::string& arg) { return arg.c_str(); }
2043     // PCWSTR FmtArg(const std::wstring& arg) { return arg.c_str(); }
2044 astrand 930
2045 astrand 933 template < typename ARG > struct FmtArg
2046 astrand 931 {
2047 astrand 933 explicit FmtArg(const ARG & arg):a_(arg)
2048     {
2049     }
2050     const ARG & operator() () const
2051     {
2052     return a_;
2053     }
2054     const ARG & a_;
2055     private:
2056     FmtArg & operator=(const FmtArg &)
2057     {
2058     return *this;
2059     }
2060 astrand 931 };
2061    
2062 astrand 933 template < typename CT > class CStdStr:public std::basic_string < CT > {
2063     // Typedefs for shorter names. Using these names also appears to help
2064     // us avoid some ambiguities that otherwise arise on some platforms
2065 astrand 930
2066 astrand 933 #define MYBASE std::basic_string<CT> // my base class
2067     //typedef typename std::basic_string<CT> MYBASE; // my base class
2068     typedef CStdStr < CT > MYTYPE; // myself
2069     typedef typename MYBASE::const_pointer PCMYSTR; // PCSTR or PCWSTR
2070     typedef typename MYBASE::pointer PMYSTR; // PSTR or PWSTR
2071     typedef typename MYBASE::iterator MYITER; // my iterator type
2072     typedef typename MYBASE::const_iterator MYCITER; // you get the idea...
2073     typedef typename MYBASE::reverse_iterator MYRITER;
2074     typedef typename MYBASE::size_type MYSIZE;
2075     typedef typename MYBASE::value_type MYVAL;
2076     typedef typename MYBASE::allocator_type MYALLOC;
2077 astrand 930
2078 astrand 933 public:
2079     // shorthand conversion from PCTSTR to string resource ID
2080     #define SSRES(pctstr) LOWORD(reinterpret_cast<unsigned long>(pctstr))
2081 astrand 931
2082 astrand 933 bool TryLoad(const void *pT)
2083     {
2084     bool bLoaded = false;
2085    
2086 astrand 931 #if defined(SS_WIN32) && !defined(SS_ANSI)
2087 astrand 933 if ((pT != NULL) && SS_IS_INTRESOURCE(pT)) {
2088     UINT nId = LOWORD(reinterpret_cast < unsigned long >(pT));
2089     if (!LoadString(nId)) {
2090     TRACE(_T("Can't load string %u\n"), SSRES(pT));
2091     }
2092     bLoaded = true;
2093     }
2094 astrand 931 #endif
2095    
2096 astrand 933 return bLoaded;
2097     }
2098 astrand 931
2099    
2100 astrand 933 // CStdStr inline constructors
2101     CStdStr() {
2102     }
2103 astrand 930
2104 astrand 933 CStdStr(const MYTYPE & str):MYBASE(SSREF(str)) {
2105     }
2106 astrand 930
2107 astrand 933 CStdStr(const std::string & str)
2108     {
2109     ssasn(*this, SSREF(str));
2110     }
2111 astrand 930
2112 astrand 933 CStdStr(const std::wstring & str)
2113     {
2114     ssasn(*this, SSREF(str));
2115     }
2116 astrand 930
2117 astrand 933 CStdStr(PCMYSTR pT, MYSIZE n):MYBASE(pT, n) {
2118     }
2119 astrand 930
2120 astrand 931 #ifdef SS_UNSIGNED
2121 astrand 933 CStdStr(PCUSTR pU) {
2122     *this = reinterpret_cast < PCSTR > (pU);
2123     }
2124 astrand 931 #endif
2125    
2126 astrand 933 CStdStr(PCSTR pA) {
2127     #ifdef SS_ANSI
2128     *this = pA;
2129     #else
2130     if (!TryLoad(pA))
2131     *this = pA;
2132     #endif
2133     }
2134 astrand 930
2135 astrand 933 CStdStr(PCWSTR pW) {
2136     #ifdef SS_ANSI
2137     *this = pW;
2138     #else
2139     if (!TryLoad(pW))
2140     *this = pW;
2141     #endif
2142     }
2143 astrand 930
2144 astrand 933 CStdStr(MYCITER first, MYCITER last)
2145     : MYBASE(first, last) {
2146     }
2147 astrand 930
2148 astrand 933 CStdStr(MYSIZE nSize, MYVAL ch, const MYALLOC & al = MYALLOC())
2149     : MYBASE(nSize, ch, al) {
2150     }
2151 astrand 930
2152 astrand 933 #ifdef SS_INC_COMDEF
2153     CStdStr(const _bstr_t & bstr)
2154     {
2155     if (bstr.length() > 0)
2156     this->append(static_cast < PCMYSTR > (bstr), bstr.length());
2157     }
2158     #endif
2159 astrand 930
2160 astrand 933 // CStdStr inline assignment operators -- the ssasn function now takes care
2161     // of fixing the MSVC assignment bug (see knowledge base article Q172398).
2162     MYTYPE & operator=(const MYTYPE & str)
2163     {
2164     ssasn(*this, str);
2165     return *this;
2166     }
2167 astrand 930
2168 astrand 933 MYTYPE & operator=(const std::string & str) {
2169     ssasn(*this, str);
2170     return *this;
2171     }
2172 astrand 930
2173 astrand 933 MYTYPE & operator=(const std::wstring & str) {
2174     ssasn(*this, str);
2175     return *this;
2176     }
2177 astrand 930
2178 astrand 933 MYTYPE & operator=(PCSTR pA) {
2179     ssasn(*this, pA);
2180     return *this;
2181     }
2182 astrand 930
2183 astrand 933 MYTYPE & operator=(PCWSTR pW) {
2184     ssasn(*this, pW);
2185     return *this;
2186     }
2187 astrand 930
2188 astrand 931 #ifdef SS_UNSIGNED
2189 astrand 933 MYTYPE & operator=(PCUSTR pU) {
2190     ssasn(*this, reinterpret_cast < PCSTR > (pU));
2191     return *this;
2192     }
2193 astrand 931 #endif
2194    
2195 astrand 933 MYTYPE & operator=(CT t) {
2196     Q172398(*this);
2197     this->assign(1, t);
2198     return *this;
2199     }
2200 astrand 930
2201 astrand 933 #ifdef SS_INC_COMDEF
2202     MYTYPE & operator=(const _bstr_t & bstr) {
2203     if (bstr.length() > 0) {
2204     this->assign(static_cast < PCMYSTR > (bstr), bstr.length());
2205     return *this;
2206     }
2207     else {
2208     this->erase();
2209     return *this;
2210     }
2211     }
2212     #endif
2213 astrand 930
2214    
2215 astrand 933 // Overloads also needed to fix the MSVC assignment bug (KB: Q172398)
2216     // *** Thanks to Pete The Plumber for catching this one ***
2217     // They also are compiled if you have explicitly turned off refcounting
2218     #if ( defined(_MSC_VER) && ( _MSC_VER < 1200 ) ) || defined(SS_NO_REFCOUNT)
2219 astrand 930
2220 astrand 933 MYTYPE & assign(const MYTYPE & str) {
2221     Q172398(*this);
2222     sscpy(GetBuffer(str.size() + 1), SSREF(str));
2223     this->ReleaseBuffer(str.size());
2224     return *this;
2225     }
2226 astrand 930
2227 astrand 933 MYTYPE & assign(const MYTYPE & str, MYSIZE nStart, MYSIZE nChars) {
2228     // This overload of basic_string::assign is supposed to assign up to
2229     // <nChars> or the NULL terminator, whichever comes first. Since we
2230     // are about to call a less forgiving overload (in which <nChars>
2231     // must be a valid length), we must adjust the length here to a safe
2232     // value. Thanks to Ullrich Pollähne for catching this bug
2233 astrand 930
2234 astrand 933 nChars = SSMIN(nChars, str.length() - nStart);
2235     MYTYPE strTemp(str.c_str() + nStart, nChars);
2236     Q172398(*this);
2237     this->assign(strTemp);
2238     return *this;
2239     }
2240 astrand 930
2241 astrand 933 MYTYPE & assign(const MYBASE & str) {
2242     ssasn(*this, str);
2243     return *this;
2244     }
2245 astrand 930
2246 astrand 933 MYTYPE & assign(const MYBASE & str, MYSIZE nStart, MYSIZE nChars) {
2247     // This overload of basic_string::assign is supposed to assign up to
2248     // <nChars> or the NULL terminator, whichever comes first. Since we
2249     // are about to call a less forgiving overload (in which <nChars>
2250     // must be a valid length), we must adjust the length here to a safe
2251     // value. Thanks to Ullrich Pollähne for catching this bug
2252 astrand 930
2253 astrand 933 nChars = SSMIN(nChars, str.length() - nStart);
2254 astrand 930
2255 astrand 933 // Watch out for assignment to self
2256 astrand 930
2257 astrand 933 if (this == &str) {
2258     MYTYPE strTemp(str.c_str() + nStart, nChars);
2259     static_cast < MYBASE * >(this)->assign(strTemp);
2260     }
2261     else {
2262     Q172398(*this);
2263     static_cast < MYBASE * >(this)->assign(str.c_str() + nStart,
2264     nChars);
2265     }
2266     return *this;
2267     }
2268 astrand 930
2269 astrand 933 MYTYPE & assign(const CT * pC, MYSIZE nChars) {
2270     // Q172398 only fix -- erase before assigning, but not if we're
2271     // assigning from our own buffer
2272 astrand 930
2273 astrand 933 #if defined ( _MSC_VER ) && ( _MSC_VER < 1200 )
2274     if (!this->empty() &&
2275     (pC < this->data() || pC > this->data() + this->capacity())) {
2276     this->erase();
2277     }
2278     #endif
2279     Q172398(*this);
2280     static_cast < MYBASE * >(this)->assign(pC, nChars);
2281     return *this;
2282     }
2283 astrand 930
2284 astrand 933 MYTYPE & assign(MYSIZE nChars, MYVAL val) {
2285     Q172398(*this);
2286     static_cast < MYBASE * >(this)->assign(nChars, val);
2287     return *this;
2288     }
2289 astrand 930
2290 astrand 933 MYTYPE & assign(const CT * pT) {
2291     return this->assign(pT, MYBASE::traits_type::length(pT));
2292     }
2293 astrand 930
2294 astrand 933 MYTYPE & assign(MYCITER iterFirst, MYCITER iterLast) {
2295     #if defined ( _MSC_VER ) && ( _MSC_VER < 1200 )
2296     // Q172398 fix. don't call erase() if we're assigning from ourself
2297     if (iterFirst < this->begin() ||
2298     iterFirst > this->begin() + this->size()) {
2299     this->erase()
2300     }
2301     #endif
2302     this->replace(this->begin(), this->end(), iterFirst, iterLast);
2303     return *this;
2304     }
2305     #endif
2306 astrand 930
2307    
2308 astrand 933 // -------------------------------------------------------------------------
2309     // CStdStr inline concatenation.
2310     // -------------------------------------------------------------------------
2311     MYTYPE & operator+=(const MYTYPE & str) {
2312     ssadd(*this, str);
2313     return *this;
2314     }
2315 astrand 930
2316 astrand 933 MYTYPE & operator+=(const std::string & str) {
2317     ssadd(*this, str);
2318     return *this;
2319     }
2320 astrand 930
2321 astrand 933 MYTYPE & operator+=(const std::wstring & str) {
2322     ssadd(*this, str);
2323     return *this;
2324     }
2325 astrand 930
2326 astrand 933 MYTYPE & operator+=(PCSTR pA) {
2327     ssadd(*this, pA);
2328     return *this;
2329     }
2330 astrand 930
2331 astrand 933 MYTYPE & operator+=(PCWSTR pW) {
2332     ssadd(*this, pW);
2333     return *this;
2334     }
2335 astrand 930
2336 astrand 933 MYTYPE & operator+=(CT t) {
2337     this->append(1, t);
2338     return *this;
2339     }
2340     #ifdef SS_INC_COMDEF // if we have _bstr_t, define a += for it too.
2341     MYTYPE & operator+=(const _bstr_t & bstr) {
2342     return this->operator+=(static_cast < PCMYSTR > (bstr));
2343     }
2344     #endif
2345 astrand 930
2346    
2347 astrand 933 // -------------------------------------------------------------------------
2348     // Case changing functions
2349     // -------------------------------------------------------------------------
2350 astrand 931
2351 astrand 933 MYTYPE & ToUpper(const std::locale & loc = std::locale()) {
2352     // Note -- if there are any MBCS character sets in which the lowercase
2353     // form a character takes up a different number of bytes than the
2354     // uppercase form, this would probably not work...
2355 astrand 930
2356 astrand 933 std::transform(this->begin(),
2357     this->end(),
2358     this->begin(), std::bind2nd(SSToUpper < CT > (), loc));
2359 astrand 930
2360 astrand 933 // ...but if it were, this would probably work better. Also, this way
2361     // seems to be a bit faster when anything other then the "C" locale is
2362     // used...
2363 astrand 930
2364 astrand 933 // if ( !empty() )
2365     // {
2366     // ssupr(this->GetBuf(), this->size(), loc);
2367     // this->RelBuf();
2368     // }
2369 astrand 930
2370 astrand 933 return *this;
2371     }
2372 astrand 930
2373 astrand 933 MYTYPE & ToLower(const std::locale & loc = std::locale()) {
2374     // Note -- if there are any MBCS character sets in which the lowercase
2375     // form a character takes up a different number of bytes than the
2376     // uppercase form, this would probably not work...
2377 astrand 930
2378 astrand 933 std::transform(this->begin(),
2379     this->end(),
2380     this->begin(), std::bind2nd(SSToLower < CT > (), loc));
2381 astrand 930
2382 astrand 933 // ...but if it were, this would probably work better. Also, this way
2383     // seems to be a bit faster when anything other then the "C" locale is
2384     // used...
2385 astrand 930
2386 astrand 933 // if ( !empty() )
2387     // {
2388     // sslwr(this->GetBuf(), this->size(), loc);
2389     // this->RelBuf();
2390     // }
2391     return *this;
2392     }
2393 astrand 930
2394    
2395 astrand 933 MYTYPE & Normalize() {
2396     return Trim().ToLower();
2397     }
2398 astrand 930
2399    
2400 astrand 933 // -------------------------------------------------------------------------
2401     // CStdStr -- Direct access to character buffer. In the MS' implementation,
2402     // the at() function that we use here also calls _Freeze() providing us some
2403     // protection from multithreading problems associated with ref-counting.
2404 astrand 931 // In VC 7 and later, of course, the ref-counting stuff is gone.
2405 astrand 933 // -------------------------------------------------------------------------
2406 astrand 931
2407 astrand 933 CT *GetBuf(int nMinLen = -1) {
2408     if (static_cast < int >(this->size()) < nMinLen)
2409     this->resize(static_cast < MYSIZE > (nMinLen));
2410 astrand 930
2411 astrand 933 return this->empty()? const_cast <
2412     CT * >(this->data()) : &(this->at(0));
2413     }
2414 astrand 930
2415 astrand 933 CT *SetBuf(int nLen)
2416     {
2417     nLen = (nLen > 0 ? nLen : 0);
2418     if (this->capacity() < 1 && nLen == 0)
2419     this->resize(1);
2420 astrand 930
2421 astrand 933 this->resize(static_cast < MYSIZE > (nLen));
2422     return const_cast < CT * >(this->data());
2423     }
2424     void RelBuf(int nNewLen = -1) {
2425     this->resize(static_cast < MYSIZE > (nNewLen > -1 ? nNewLen :
2426     sslen(this->c_str())));
2427     }
2428 astrand 930
2429 astrand 933 void BufferRel()
2430     {
2431     RelBuf();
2432     } // backwards compatability
2433     CT *Buffer()
2434     {
2435     return GetBuf();
2436     } // backwards compatability
2437     CT *BufferSet(int nLen)
2438     {
2439     return SetBuf(nLen);
2440     } // backwards compatability
2441 astrand 930
2442 astrand 933 bool Equals(const CT * pT, bool bUseCase = false) const
2443     {
2444     return 0 ==
2445     (bUseCase ? this->compare(pT) : ssicmp(this->c_str(), pT));
2446     }
2447 astrand 930
2448 astrand 933 // -------------------------------------------------------------------------
2449     // FUNCTION: CStdStr::Load
2450     // REMARKS:
2451     // Loads string from resource specified by nID
2452     //
2453     // PARAMETERS:
2454     // nID - resource Identifier. Purely a Win32 thing in this case
2455     //
2456     // RETURN VALUE:
2457     // true if successful, false otherwise
2458     // -------------------------------------------------------------------------
2459 astrand 931
2460 astrand 930 #ifndef SS_ANSI
2461 astrand 931
2462 astrand 933 bool Load(UINT nId, HMODULE hModule = NULL) {
2463     bool bLoaded = false; // set to true of we succeed.
2464 astrand 930
2465 astrand 933 #ifdef _MFC_VER // When in Rome (or MFC land)...
2466 astrand 930
2467 astrand 933 // If they gave a resource handle, use it. Note - this is archaic
2468     // and not really what I would recommend. But then again, in MFC
2469     // land, you ought to be using CString for resources anyway since
2470     // it walks the resource chain for you.
2471 astrand 931
2472 astrand 933 HMODULE hModuleOld = NULL;
2473 astrand 931
2474 astrand 933 if (NULL != hModule) {
2475     hModuleOld = AfxGetResourceHandle();
2476     AfxSetResourceHandle(hModule);
2477     }
2478 astrand 931
2479 astrand 933 // ...load the string
2480 astrand 931
2481 astrand 933 CString strRes;
2482     bLoaded = FALSE != strRes.LoadString(nId);
2483 astrand 931
2484 astrand 933 // ...and if we set the resource handle, restore it.
2485 astrand 931
2486 astrand 933 if (NULL != hModuleOld)
2487     AfxSetResourceHandle(hModule);
2488 astrand 931
2489 astrand 933 if (bLoaded)
2490     *this = strRes;
2491 astrand 930
2492 astrand 933 #else // otherwise make our own hackneyed version of CString's Load
2493 astrand 930
2494 astrand 933 // Get the resource name and module handle
2495 astrand 930
2496 astrand 933 if (NULL == hModule)
2497     hModule = GetResourceHandle();
2498 astrand 930
2499 astrand 933 PCTSTR szName = MAKEINTRESOURCE((nId >> 4) + 1); // lifted
2500     DWORD dwSize = 0;
2501 astrand 930
2502 astrand 933 // No sense continuing if we can't find the resource
2503 astrand 930
2504 astrand 933 HRSRC hrsrc =::FindResource(hModule, szName, RT_STRING);
2505 astrand 930
2506 astrand 933 if (NULL == hrsrc) {
2507     TRACE(_T("Cannot find resource %d: 0x%X"), nId,::GetLastError());
2508     }
2509     else if (0 == (dwSize =::SizeofResource(hModule, hrsrc) / sizeof(CT))) {
2510     TRACE(_T("Cant get size of resource %d 0x%X\n"), nId,
2511     GetLastError());
2512     }
2513     else {
2514     bLoaded = 0 != ssload(hModule, nId, GetBuf(dwSize), dwSize);
2515     ReleaseBuffer();
2516     }
2517 astrand 930
2518 astrand 933 #endif // #ifdef _MFC_VER
2519 astrand 930
2520 astrand 933 if (!bLoaded)
2521     TRACE(_T("String not loaded 0x%X\n"),::GetLastError());
2522 astrand 931
2523 astrand 933 return bLoaded;
2524     }
2525 astrand 931
2526 astrand 933 #endif // #ifdef SS_ANSI
2527    
2528     // -------------------------------------------------------------------------
2529     // FUNCTION: CStdStr::Format
2530     // void _cdecl Formst(CStdStringA& PCSTR szFormat, ...)
2531     // void _cdecl Format(PCSTR szFormat);
2532     //
2533     // DESCRIPTION:
2534     // This function does sprintf/wsprintf style formatting on CStdStringA
2535     // objects. It looks a lot like MFC's CString::Format. Some people
2536     // might even call this identical. Fortunately, these people are now
2537     // dead... heh heh.
2538     //
2539     // PARAMETERS:
2540     // nId - ID of string resource holding the format string
2541     // szFormat - a PCSTR holding the format specifiers
2542     // argList - a va_list holding the arguments for the format specifiers.
2543     //
2544     // RETURN VALUE: None.
2545     // -------------------------------------------------------------------------
2546     // formatting (using wsprintf style formatting)
2547    
2548 astrand 931 // If they want a Format() function that safely handles string objects
2549     // without casting
2550 astrand 933
2551     #ifdef SS_SAFE_FORMAT
2552    
2553 astrand 931 // Question: Joe, you wacky coder you, why do you have so many overloads
2554     // of the Format() function
2555     // Answer: One reason only - CString compatability. In short, by making
2556     // the Format() function a template this way, I can do strong typing
2557     // and allow people to pass CStdString arguments as fillers for
2558     // "%s" format specifiers without crashing their program! The downside
2559     // is that I need to overload on the number of arguments. If you are
2560     // passing more arguments than I have listed below in any of my
2561     // overloads, just add another one.
2562     //
2563     // Yes, yes, this is really ugly. In essence what I am doing here is
2564     // protecting people from a bad (and incorrect) programming practice
2565     // that they should not be doing anyway. I am protecting them from
2566     // themselves. Why am I doing this? Well, if you had any idea the
2567     // number of times I've been emailed by people about this
2568     // "incompatability" in my code, you wouldn't ask.
2569    
2570 astrand 933 void Fmt(const CT * szFmt, ...)
2571     {
2572     va_list argList;
2573     va_start(argList, szFmt);
2574     FormatV(szFmt, argList);
2575     va_end(argList);
2576     }
2577 astrand 931
2578     #ifndef SS_ANSI
2579    
2580     void Format(UINT nId)
2581     {
2582 astrand 933 MYTYPE strFmt;
2583     if (strFmt.Load(nId))
2584 astrand 931 this->swap(strFmt);
2585     }
2586 astrand 933 template < class A1 > void Format(UINT nId, const A1 & v)
2587 astrand 931 {
2588 astrand 933 MYTYPE strFmt;
2589     if (strFmt.Load(nId))
2590     Fmt(strFmt, FmtArg < A1 > (v) ());
2591 astrand 931 }
2592 astrand 933 template < class A1, class A2 >
2593     void Format(UINT nId, const A1 & v1, const A2 & v2)
2594 astrand 931 {
2595 astrand 933 MYTYPE strFmt;
2596     if (strFmt.Load(nId))
2597     Fmt(strFmt, FmtArg < A1 > (v1) (), FmtArg < A2 > (v2) ());
2598 astrand 931 }
2599 astrand 933 template < class A1, class A2, class A3 >
2600     void Format(UINT nId, const A1 & v1, const A2 & v2, const A3 & v3)
2601 astrand 931 {
2602 astrand 933 MYTYPE strFmt;
2603     if (strFmt.Load(nId)) {
2604     Fmt(strFmt, FmtArg < A1 > (v1) (), FmtArg < A2 > (v2) (),
2605     FmtArg < A3 > (v3) ());
2606 astrand 931 }
2607     }
2608 astrand 933 template < class A1, class A2, class A3, class A4 >
2609     void Format(UINT nId, const A1 & v1, const A2 & v2, const A3 & v3,
2610     const A4 & v4)
2611 astrand 931 {
2612 astrand 933 MYTYPE strFmt;
2613     if (strFmt.Load(nId)) {
2614     Fmt(strFmt, FmtArg < A1 > (v1) (), FmtArg < A2 > (v2) (),
2615     FmtArg < A3 > (v3) (), FmtArg < A4 > (v4) ());
2616 astrand 931 }
2617     }
2618 astrand 933 template < class A1, class A2, class A3, class A4, class A5 >
2619     void Format(UINT nId, const A1 & v1, const A2 & v2, const A3 & v3,
2620     const A4 & v4, const A5 & v5)
2621 astrand 931 {
2622 astrand 933 MYTYPE strFmt;
2623     if (strFmt.Load(nId)) {
2624     Fmt(strFmt, FmtArg < A1 > (v1) (), FmtArg < A2 > (v2) (),
2625     FmtArg < A3 > (v3) (), FmtArg < A4 > (v4) (),
2626     FmtArg < A5 > (v5) ());
2627 astrand 931 }
2628     }
2629 astrand 933 template < class A1, class A2, class A3, class A4, class A5, class A6 >
2630     void Format(UINT nId, const A1 & v1, const A2 & v2, const A3 & v3,
2631     const A4 & v4, const A5 & v5, const A6 & v6)
2632 astrand 931 {
2633 astrand 933 MYTYPE strFmt;
2634     if (strFmt.Load(nId)) {
2635     Fmt(strFmt, FmtArg < A1 > (v1) (), FmtArg < A2 > (v2) (),
2636     FmtArg < A3 > (v3) (), FmtArg < A4 > (v4) (),
2637     FmtArg < A5 > (v5) (), FmtArg < A6 > (v6) ());
2638 astrand 931 }
2639     }
2640 astrand 933 template < class A1, class A2, class A3, class A4, class A5, class A6,
2641     class A7 >
2642     void Format(UINT nId, const A1 & v1, const A2 & v2, const A3 & v3,
2643     const A4 & v4, const A5 & v5, const A6 & v6,
2644     const A7 & v7)
2645 astrand 931 {
2646 astrand 933 MYTYPE strFmt;
2647     if (strFmt.Load(nId)) {
2648     Fmt(strFmt, FmtArg < A1 > (v1) (), FmtArg < A2 > (v2) (),
2649     FmtArg < A3 > (v3) (), FmtArg < A4 > (v4) (),
2650     FmtArg < A5 > (v5) (), FmtArg < A6 > (v6) (),
2651     FmtArg < A7 > (v7) ());
2652 astrand 931 }
2653     }
2654 astrand 933 template < class A1, class A2, class A3, class A4, class A5, class A6,
2655     class A7, class A8 >
2656     void Format(UINT nId, const A1 & v1, const A2 & v2, const A3 & v3,
2657     const A4 & v4, const A5 & v5, const A6 & v6,
2658     const A7 & v7, const A8 & v8)
2659 astrand 931 {
2660 astrand 933 MYTYPE strFmt;
2661     if (strFmt.Load(nId)) {
2662     Fmt(strFmt, FmtArg < A1 > (v1) (), FmtArg < A2 > (v2) (),
2663     FmtArg < A3 > (v3) (), FmtArg < A4 > (v4) (),
2664     FmtArg < A5 > (v5) (), FmtArg < A6 > (v6) (),
2665     FmtArg < A7 > (v7) (), FmtArg < A8 > (v8) ());
2666 astrand 931 }
2667     }
2668 astrand 933 template < class A1, class A2, class A3, class A4, class A5, class A6,
2669     class A7, class A8, class A9 >
2670     void Format(UINT nId, const A1 & v1, const A2 & v2, const A3 & v3,
2671     const A4 & v4, const A5 & v5, const A6 & v6,
2672     const A7 & v7, const A8 & v8, const A9 & v9)
2673 astrand 931 {
2674 astrand 933 MYTYPE strFmt;
2675     if (strFmt.Load(nId)) {
2676     Fmt(strFmt, FmtArg < A1 > (v1) (), FmtArg < A2 > (v2) (),
2677     FmtArg < A3 > (v3) (), FmtArg < A4 > (v4) (),
2678     FmtArg < A5 > (v5) (), FmtArg < A6 > (v6) (),
2679     FmtArg < A7 > (v7) (), FmtArg < A8 > (v8) (),
2680     FmtArg < A9 > (v9) ());
2681 astrand 931 }
2682     }
2683 astrand 933 template < class A1, class A2, class A3, class A4, class A5, class A6,
2684     class A7, class A8, class A9, class A10 >
2685     void Format(UINT nId, const A1 & v1, const A2 & v2, const A3 & v3,
2686     const A4 & v4, const A5 & v5, const A6 & v6,
2687     const A7 & v7, const A8 & v8, const A9 & v9,
2688     const A10 & v10)
2689 astrand 931 {
2690 astrand 933 MYTYPE strFmt;
2691     if (strFmt.Load(nId)) {
2692     Fmt(strFmt, FmtArg < A1 > (v1) (), FmtArg < A2 > (v2) (),
2693     FmtArg < A3 > (v3) (), FmtArg < A4 > (v4) (),
2694     FmtArg < A5 > (v5) (), FmtArg < A6 > (v6) (),
2695     FmtArg < A7 > (v7) (), FmtArg < A8 > (v8) (),
2696     FmtArg < A9 > (v9) (), FmtArg < A10 > (v10) ());
2697 astrand 931 }
2698     }
2699 astrand 933 template < class A1, class A2, class A3, class A4, class A5, class A6,
2700     class A7, class A8, class A9, class A10, class A11 >
2701     void Format(UINT nId, const A1 & v1, const A2 & v2, const A3 & v3,
2702     const A4 & v4, const A5 & v5, const A6 & v6,
2703     const A7 & v7, const A8 & v8, const A9 & v9,
2704     const A10 & v10, const A11 & v11)
2705 astrand 931 {
2706 astrand 933 MYTYPE strFmt;
2707     if (strFmt.Load(nId)) {
2708     Fmt(strFmt, FmtArg < A1 > (v1) (), FmtArg < A2 > (v2) (),
2709     FmtArg < A3 > (v3) (), FmtArg < A4 > (v4) (),
2710     FmtArg < A5 > (v5) (), FmtArg < A6 > (v6) (),
2711     FmtArg < A7 > (v7) (), FmtArg < A8 > (v8) (),
2712     FmtArg < A9 > (v9) (), FmtArg < A10 > (v10) (),
2713     FmtArg < A11 > (v11) ());
2714 astrand 931 }
2715     }
2716 astrand 933 template < class A1, class A2, class A3, class A4, class A5, class A6,
2717     class A7, class A8, class A9, class A10, class A11, class A12 >
2718     void Format(UINT nId, const A1 & v1, const A2 & v2, const A3 & v3,
2719     const A4 & v4, const A5 & v5, const A6 & v6,
2720     const A7 & v7, const A8 & v8, const A9 & v9,
2721     const A10 & v10, const A11 & v11, const A12 & v12)
2722 astrand 931 {
2723 astrand 933 MYTYPE strFmt;
2724     if (strFmt.Load(nId)) {
2725     Fmt(strFmt, FmtArg < A1 > (v1) (), FmtArg < A2 > (v2) (),
2726     FmtArg < A3 > (v3) (), FmtArg < A4 > (v4) (),
2727     FmtArg < A5 > (v5) (), FmtArg < A6 > (v6) (),
2728     FmtArg < A7 > (v7) (), FmtArg < A8 > (v8) (),
2729     FmtArg < A9 > (v9) (), FmtArg < A10 > (v10) (),
2730     FmtArg < A11 > (v11) (), FmtArg < A12 > (v12) ());
2731 astrand 931 }
2732     }
2733 astrand 933 template < class A1, class A2, class A3, class A4, class A5, class A6,
2734 astrand 931 class A7, class A8, class A9, class A10, class A11, class A12,
2735 astrand 933 class A13 >
2736     void Format(UINT nId, const A1 & v1, const A2 & v2, const A3 & v3,
2737     const A4 & v4, const A5 & v5, const A6 & v6,
2738     const A7 & v7, const A8 & v8, const A9 & v9,
2739     const A10 & v10, const A11 & v11, const A12 & v12,
2740     const A13 & v13)
2741 astrand 931 {
2742 astrand 933 MYTYPE strFmt;
2743     if (strFmt.Load(nId)) {
2744     Fmt(strFmt, FmtArg < A1 > (v1) (), FmtArg < A2 > (v2) (),
2745     FmtArg < A3 > (v3) (), FmtArg < A4 > (v4) (),
2746     FmtArg < A5 > (v5) (), FmtArg < A6 > (v6) (),
2747     FmtArg < A7 > (v7) (), FmtArg < A8 > (v8) (),
2748     FmtArg < A9 > (v9) (), FmtArg < A10 > (v10) (),
2749     FmtArg < A11 > (v11) (), FmtArg < A12 > (v12) (),
2750     FmtArg < A13 > (v13) ());
2751 astrand 931 }
2752     }
2753 astrand 933 template < class A1, class A2, class A3, class A4, class A5, class A6,
2754 astrand 931 class A7, class A8, class A9, class A10, class A11, class A12,
2755 astrand 933 class A13, class A14 >
2756     void Format(UINT nId, const A1 & v1, const A2 & v2, const A3 & v3,
2757     const A4 & v4, const A5 & v5, const A6 & v6,
2758     const A7 & v7, const A8 & v8, const A9 & v9,
2759     const A10 & v10, const A11 & v11, const A12 & v12,
2760     const A13 & v13, const A14 & v14)
2761 astrand 931 {
2762 astrand 933 MYTYPE strFmt;
2763     if (strFmt.Load(nId)) {
2764     Fmt(strFmt, FmtArg < A1 > (v1) (), FmtArg < A2 > (v2) (),
2765     FmtArg < A3 > (v3) (), FmtArg < A4 > (v4) (),
2766     FmtArg < A5 > (v5) (), FmtArg < A6 > (v6) (),
2767     FmtArg < A7 > (v7) (), FmtArg < A8 > (v8) (),
2768     FmtArg < A9 > (v9) (), FmtArg < A10 > (v10) (),
2769     FmtArg < A11 > (v11) (), FmtArg < A12 > (v12) (),
2770     FmtArg < A13 > (v13) (), FmtArg < A14 > (v14) ());
2771 astrand 931 }
2772     }
2773 astrand 933 template < class A1, class A2, class A3, class A4, class A5, class A6,
2774 astrand 931 class A7, class A8, class A9, class A10, class A11, class A12,
2775 astrand 933 class A13, class A14, class A15 >
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     const A13 & v13, const A14 & v14, const A15 & v15)
2781 astrand 931 {
2782 astrand 933 MYTYPE strFmt;
2783     if (strFmt.Load(nId)) {
2784     Fmt(strFmt, FmtArg < A1 > (v1) (), FmtArg < A2 > (v2) (),
2785     FmtArg < A3 > (v3) (), FmtArg < A4 > (v4) (),
2786     FmtArg < A5 > (v5) (), FmtArg < A6 > (v6) (),
2787     FmtArg < A7 > (v7) (), FmtArg < A8 > (v8) (),
2788     FmtArg < A9 > (v9) (), FmtArg < A10 > (v10) (),
2789     FmtArg < A11 > (v11) (), FmtArg < A12 > (v12) (),
2790     FmtArg < A13 > (v13) (), FmtArg < A14 > (v14) (),
2791     FmtArg < A15 > (v15) ());
2792 astrand 931 }
2793     }
2794 astrand 933 template < class A1, class A2, class A3, class A4, class A5, class A6,
2795 astrand 931 class A7, class A8, class A9, class A10, class A11, class A12,
2796 astrand 933 class A13, class A14, class A15, class A16 >
2797     void Format(UINT nId, const A1 & v1, const A2 & v2, const A3 & v3,
2798     const A4 & v4, const A5 & v5, const A6 & v6,
2799     const A7 & v7, const A8 & v8, const A9 & v9,
2800     const A10 & v10, const A11 & v11, const A12 & v12,
2801     const A13 & v13, const A14 & v14, const A15 & v15,
2802     const A16 & v16)
2803 astrand 931 {
2804 astrand 933 MYTYPE strFmt;
2805     if (strFmt.Load(nId)) {
2806     Fmt(strFmt, FmtArg < A1 > (v1) (), FmtArg < A2 > (v2) (),
2807     FmtArg < A3 > (v3) (), FmtArg < A4 > (v4) (),
2808     FmtArg < A5 > (v5) (), FmtArg < A6 > (v6) (),
2809     FmtArg < A7 > (v7) (), FmtArg < A8 > (v8) (),
2810     FmtArg < A9 > (v9) (), FmtArg < A10 > (v10) (),
2811     FmtArg < A11 > (v11) (), FmtArg < A12 > (v12) (),
2812     FmtArg < A13 > (v13) (), FmtArg < A14 > (v14) (),
2813     FmtArg < A15 > (v15) (), FmtArg < A16 > (v16) ());
2814 astrand 931 }
2815     }
2816 astrand 933 template < class A1, class A2, class A3, class A4, class A5, class A6,
2817 astrand 931 class A7, class A8, class A9, class A10, class A11, class A12,
2818 astrand 933 class A13, class A14, class A15, class A16, class A17 >
2819     void Format(UINT nId, const A1 & v1, const A2 & v2, const A3 & v3,
2820     const A4 & v4, const A5 & v5, const A6 & v6,
2821     const A7 & v7, const A8 & v8, const A9 & v9,
2822     const A10 & v10, const A11 & v11, const A12 & v12,
2823     const A13 & v13, const A14 & v14, const A15 & v15,
2824     const A16 & v16, const A17 & v17)
2825 astrand 931 {
2826 astrand 933 MYTYPE strFmt;
2827     if (strFmt.Load(nId)) {
2828     Fmt(strFmt, FmtArg < A1 > (v1) (), FmtArg < A2 > (v2) (),
2829     FmtArg < A3 > (v3) (), FmtArg < A4 > (v4) (),
2830     FmtArg < A5 > (v5) (), FmtArg < A6 > (v6) (),
2831     FmtArg < A7 > (v7) (), FmtArg < A8 > (v8) (),
2832     FmtArg < A9 > (v9) (), FmtArg < A10 > (v10) (),
2833     FmtArg < A11 > (v11) (), FmtArg < A12 > (v12) (),
2834     FmtArg < A13 > (v13) (), FmtArg < A14 > (v14) (),
2835     FmtArg < A15 > (v15) (), FmtArg < A16 > (v16) (),
2836     FmtArg < A17 > (v17) ());
2837 astrand 931 }
2838     }
2839 astrand 933
2840 astrand 931 #endif // #ifndef SS_ANSI
2841    
2842     // ...now the other overload of Format: the one that takes a string literal
2843    
2844 astrand 933 void Format(const CT * szFmt)
2845 astrand 931 {
2846     *this = szFmt;
2847     }
2848 astrand 933 template < class A1 > void Format(const CT * szFmt, const A1 & v)
2849 astrand 931 {
2850 astrand 933 Fmt(szFmt, FmtArg < A1 > (v) ());
2851 astrand 931 }
2852 astrand 933 template < class A1, class A2 >
2853     void Format(const CT * szFmt, const A1 & v1, const A2 & v2)
2854 astrand 931 {
2855 astrand 933 Fmt(szFmt, FmtArg < A1 > (v1) (), FmtArg < A2 > (v2) ());
2856 astrand 931 }
2857 astrand 933 template < class A1, class A2, class A3 >
2858     void Format(const CT * szFmt, const A1 & v1, const A2 & v2,
2859     const A3 & v3)
2860 astrand 931 {
2861 astrand 933 Fmt(szFmt, FmtArg < A1 > (v1) (), FmtArg < A2 > (v2) (),
2862     FmtArg < A3 > (v3) ());
2863 astrand 931 }
2864 astrand 933 template < class A1, class A2, class A3, class A4 >
2865     void Format(const CT * szFmt, const A1 & v1, const A2 & v2,
2866     const A3 & v3, const A4 & v4)
2867 astrand 931 {
2868 astrand 933 Fmt(szFmt, FmtArg < A1 > (v1) (), FmtArg < A2 > (v2) (),
2869     FmtArg < A3 > (v3) (), FmtArg < A4 > (v4) ());
2870 astrand 931 }
2871 astrand 933 template < class A1, class A2, class A3, class A4, class A5 >
2872     void Format(const CT * szFmt, const A1 & v1, const A2 & v2,
2873     const A3 & v3, const A4 & v4, const A5 & v5)
2874 astrand 931 {
2875 astrand 933 Fmt(szFmt, FmtArg < A1 > (v1) (), FmtArg < A2 > (v2) (),
2876     FmtArg < A3 > (v3) (), FmtArg < A4 > (v4) (),
2877     FmtArg < A5 > (v5) ());
2878 astrand 931 }
2879 astrand 933 template < class A1, class A2, class A3, class A4, class A5, class A6 >
2880     void Format(const CT * szFmt, const A1 & v1, const A2 & v2,
2881     const A3 & v3, const A4 & v4, const A5 & v5,
2882     const A6 & v6)
2883 astrand 931 {
2884 astrand 933 Fmt(szFmt, FmtArg < A1 > (v1) (), FmtArg < A2 > (v2) (),
2885     FmtArg < A3 > (v3) (), FmtArg < A4 > (v4) (),
2886     FmtArg < A5 > (v5) (), FmtArg < A6 > (v6) ());
2887 astrand 931 }
2888 astrand 933 template < class A1, class A2, class A3, class A4, class A5, class A6,
2889     class A7 >
2890     void Format(const CT * szFmt, const A1 & v1, const A2 & v2,
2891     const A3 & v3, const A4 & v4, const A5 & v5,
2892     const A6 & v6, const A7 & v7)
2893 astrand 931 {
2894 astrand 933 Fmt(szFmt, FmtArg < A1 > (v1) (), FmtArg < A2 > (v2) (),
2895     FmtArg < A3 > (v3) (), FmtArg < A4 > (v4) (),
2896     FmtArg < A5 > (v5) (), FmtArg < A6 > (v6) (),
2897     FmtArg < A7 > (v7) ());
2898 astrand 931 }
2899 astrand 933 template < class A1, class A2, class A3, class A4, class A5, class A6,
2900     class A7, class A8 >
2901     void Format(const CT * szFmt, const A1 & v1, const A2 & v2,
2902     const A3 & v3, const A4 & v4, const A5 & v5,
2903     const A6 & v6, const A7 & v7, const A8 & v8)
2904 astrand 931 {
2905 astrand 933 Fmt(szFmt, FmtArg < A1 > (v1) (), FmtArg < A2 > (v2) (),
2906     FmtArg < A3 > (v3) (), FmtArg < A4 > (v4) (),
2907     FmtArg < A5 > (v5) (), FmtArg < A6 > (v6) (),
2908     FmtArg < A7 > (v7) (), FmtArg < A8 > (v8) ());
2909 astrand 931 }
2910 astrand 933 template < class A1, class A2, class A3, class A4, class A5, class A6,
2911     class A7, class A8, class A9 >
2912     void Format(const CT * szFmt, const A1 & v1, const A2 & v2,
2913     const A3 & v3, const A4 & v4, const A5 & v5,
2914     const A6 & v6, const A7 & v7, const A8 & v8,
2915     const A9 & v9)
2916 astrand 931 {
2917 astrand 933 Fmt(szFmt, FmtArg < A1 > (v1) (), FmtArg < A2 > (v2) (),
2918     FmtArg < A3 > (v3) (), FmtArg < A4 > (v4) (),
2919     FmtArg < A5 > (v5) (), FmtArg < A6 > (v6) (),
2920     FmtArg < A7 > (v7) (), FmtArg < A8 > (v8) (),
2921     FmtArg < A9 > (v9) ());
2922 astrand 931 }
2923 astrand 933 template < class A1, class A2, class A3, class A4, class A5, class A6,
2924     class A7, class A8, class A9, class A10 >
2925     void Format(const CT * szFmt, const A1 & v1, const A2 & v2,
2926     const A3 & v3, const A4 & v4, const A5 & v5,
2927     const A6 & v6, const A7 & v7, const A8 & v8,
2928     const A9 & v9, const A10 & v10)
2929 astrand 931 {
2930 astrand 933 Fmt(szFmt, FmtArg < A1 > (v1) (), FmtArg < A2 > (v2) (),
2931     FmtArg < A3 > (v3) (), FmtArg < A4 > (v4) (),
2932     FmtArg < A5 > (v5) (), FmtArg < A6 > (v6) (),
2933     FmtArg < A7 > (v7) (), FmtArg < A8 > (v8) (),
2934     FmtArg < A9 > (v9) (), FmtArg < A10 > (v10) ());
2935 astrand 931 }
2936 astrand 933 template < class A1, class A2, class A3, class A4, class A5, class A6,
2937     class A7, class A8, class A9, class A10, class A11 >
2938     void Format(const CT * szFmt, const A1 & v1, const A2 & v2,
2939     const A3 & v3, const A4 & v4, const A5 & v5,
2940     const A6 & v6, const A7 & v7, const A8 & v8,
2941     const A9 & v9, const A10 & v10, const A11 & v11)
2942 astrand 931 {
2943 astrand 933 Fmt(szFmt, FmtArg < A1 > (v1) (), FmtArg < A2 > (v2) (),
2944     FmtArg < A3 > (v3) (), FmtArg < A4 > (v4) (),
2945     FmtArg < A5 > (v5) (), FmtArg < A6 > (v6) (),
2946     FmtArg < A7 > (v7) (), FmtArg < A8 > (v8) (),
2947     FmtArg < A9 > (v9) (), FmtArg < A10 > (v10) (),
2948     FmtArg < A11 > (v11) ());
2949 astrand 931 }
2950 astrand 933 template < class A1, class A2, class A3, class A4, class A5, class A6,
2951     class A7, class A8, class A9, class A10, class A11, class A12 >
2952     void Format(const CT * szFmt, const A1 & v1, const A2 & v2,
2953     const A3 & v3, const A4 & v4, const A5 & v5,
2954     const A6 & v6, const A7 & v7, const A8 & v8,
2955     const A9 & v9, const A10 & v10, const A11 & v11,
2956     const A12 & v12)
2957 astrand 931 {
2958 astrand 933 Fmt(szFmt, FmtArg < A1 > (v1) (), FmtArg < A2 > (v2) (),
2959     FmtArg < A3 > (v3) (), FmtArg < A4 > (v4) (),
2960     FmtArg < A5 > (v5) (), FmtArg < A6 > (v6) (),
2961     FmtArg < A7 > (v7) (), FmtArg < A8 > (v8) (),
2962     FmtArg < A9 > (v9) (), FmtArg < A10 > (v10) (),
2963     FmtArg < A11 > (v11) (), FmtArg < A12 > (v12) ());
2964 astrand 931 }
2965 astrand 933 template < class A1, class A2, class A3, class A4, class A5, class A6,
2966 astrand 931 class A7, class A8, class A9, class A10, class A11, class A12,
2967 astrand 933 class A13 >
2968     void Format(const CT * szFmt, const A1 & v1, const A2 & v2,
2969     const A3 & v3, const A4 & v4, const A5 & v5,
2970     const A6 & v6, const A7 & v7, const A8 & v8,
2971     const A9 & v9, const A10 & v10, const A11 & v11,
2972     const A12 & v12, const A13 & v13)
2973 astrand 931 {
2974 astrand 933 Fmt(szFmt, FmtArg < A1 > (v1) (), FmtArg < A2 > (v2) (),
2975     FmtArg < A3 > (v3) (), FmtArg < A4 > (v4) (),
2976     FmtArg < A5 > (v5) (), FmtArg < A6 > (v6) (),
2977     FmtArg < A7 > (v7) (), FmtArg < A8 > (v8) (),
2978     FmtArg < A9 > (v9) (), FmtArg < A10 > (v10) (),
2979     FmtArg < A11 > (v11) (), FmtArg < A12 > (v12) (),
2980     FmtArg < A13 > (v13) ());
2981 astrand 931 }
2982 astrand 933 template < class A1, class A2, class A3, class A4, class A5, class A6,
2983 astrand 931 class A7, class A8, class A9, class A10, class A11, class A12,
2984 astrand 933 class A13, class A14 >
2985     void Format(const CT * szFmt, const A1 & v1, const A2 & v2,
2986     const A3 & v3, const A4 & v4, const A5 & v5,
2987     const A6 & v6, const A7 & v7, const A8 & v8,
2988     const A9 & v9, const A10 & v10, const A11 & v11,
2989     const A12 & v12, const A13 & v13, const A14 & v14)
2990 astrand 931 {
2991 astrand 933 Fmt(szFmt, FmtArg < A1 > (v1) (), FmtArg < A2 > (v2) (),
2992     FmtArg < A3 > (v3) (), FmtArg < A4 > (v4) (),
2993     FmtArg < A5 > (v5) (), FmtArg < A6 > (v6) (),
2994     FmtArg < A7 > (v7) (), FmtArg < A8 > (v8) (),
2995     FmtArg < A9 > (v9) (), FmtArg < A10 > (v10) (),
2996     FmtArg < A11 > (v11) (), FmtArg < A12 > (v12) (),
2997     FmtArg < A13 > (v13) (), FmtArg < A14 > (v14) ());
2998 astrand 931 }
2999 astrand 933 template < class A1, class A2, class A3, class A4, class A5, class A6,
3000 astrand 931 class A7, class A8, class A9, class A10, class A11, class A12,
3001 astrand 933 class A13, class A14, class A15 >
3002     void Format(const CT * szFmt, const A1 & v1, const A2 & v2,
3003     const A3 & v3, const A4 & v4, const A5 & v5,
3004     const A6 & v6, const A7 & v7, const A8 & v8,
3005     const A9 & v9, const A10 & v10, const A11 & v11,
3006     const A12 & v12, const A13 & v13, const A14 & v14,
3007     const A15 & v15)
3008 astrand 931 {
3009 astrand 933 Fmt(szFmt, FmtArg < A1 > (v1) (), FmtArg < A2 > (v2) (),
3010     FmtArg < A3 > (v3) (), FmtArg < A4 > (v4) (),
3011     FmtArg < A5 > (v5) (), FmtArg < A6 > (v6) (),
3012     FmtArg < A7 > (v7) (), FmtArg < A8 > (v8) (),
3013     FmtArg < A9 > (v9) (), FmtArg < A10 > (v10) (),
3014     FmtArg < A11 > (v11) (), FmtArg < A12 > (v12) (),
3015     FmtArg < A13 > (v13) (), FmtArg < A14 > (v14) (),
3016     FmtArg < A15 > (v15) ());
3017 astrand 931 }
3018 astrand 933 template < class A1, class A2, class A3, class A4, class A5, class A6,
3019 astrand 931 class A7, class A8, class A9, class A10, class A11, class A12,
3020 astrand 933 class A13, class A14, class A15, class A16 >
3021     void Format(const CT * szFmt, const A1 & v1, const A2 & v2,
3022     const A3 & v3, const A4 & v4, const A5 & v5,
3023     const A6 & v6, const A7 & v7, const A8 & v8,
3024     const A9 & v9, const A10 & v10, const A11 & v11,
3025     const A12 & v12, const A13 & v13, const A14 & v14,
3026     const A15 & v15, const A16 & v16)
3027 astrand 931 {
3028 astrand 933 Fmt(szFmt, FmtArg < A1 > (v1) (), FmtArg < A2 > (v2) (),
3029     FmtArg < A3 > (v3) (), FmtArg < A4 > (v4) (),
3030     FmtArg < A5 > (v5) (), FmtArg < A6 > (v6) (),
3031     FmtArg < A7 > (v7) (), FmtArg < A8 > (v8) (),
3032     FmtArg < A9 > (v9) (), FmtArg < A10 > (v10) (),
3033     FmtArg < A11 > (v11) (), FmtArg < A12 > (v12) (),
3034     FmtArg < A13 > (v13) (), FmtArg < A14 > (v14) (),
3035     FmtArg < A15 > (v15) (), FmtArg < A16 > (v16) ());
3036 astrand 931 }
3037 astrand 933 template < class A1, class A2, class A3, class A4, class A5, class A6,
3038 astrand 931 class A7, class A8, class A9, class A10, class A11, class A12,
3039 astrand 933 class A13, class A14, class A15, class A16, class A17 >
3040     void Format(const CT * szFmt, const A1 & v1, const A2 & v2,
3041     const A3 & v3, const A4 & v4, const A5 & v5,
3042     const A6 & v6, const A7 & v7, const A8 & v8,
3043     const A9 & v9, const A10 & v10, const A11 & v11,
3044     const A12 & v12, const A13 & v13, const A14 & v14,
3045     const A15 & v15, const A16 & v16, const A17 & v17)
3046 astrand 931 {
3047 astrand 933 Fmt(szFmt, FmtArg < A1 > (v1) (), FmtArg < A2 > (v2) (),
3048     FmtArg < A3 > (v3) (), FmtArg < A4 > (v4) (),
3049     FmtArg < A5 > (v5) (), FmtArg < A6 > (v6) (),
3050     FmtArg < A7 > (v7) (), FmtArg < A8 > (v8) (),
3051     FmtArg < A9 > (v9) (), FmtArg < A10 > (v10) (),
3052     FmtArg < A11 > (v11) (), FmtArg < A12 > (v12) (),
3053     FmtArg < A13 > (v13) (), FmtArg < A14 > (v14) (),
3054     FmtArg < A15 > (v15) (), FmtArg < A16 > (v16) (),
3055     FmtArg < A17 > (v17) ());
3056 astrand 931 }
3057    
3058 astrand 933 #else // #ifdef SS_SAFE_FORMAT
3059 astrand 931
3060    
3061     #ifndef SS_ANSI
3062    
3063 astrand 933 void Format(UINT nId, ...)
3064     {
3065     va_list argList;
3066     va_start(argList, nId);
3067 astrand 930
3068 astrand 933 MYTYPE strFmt;
3069     if (strFmt.Load(nId))
3070     FormatV(strFmt, argList);
3071 astrand 930
3072 astrand 933 va_end(argList);
3073     }
3074 astrand 931
3075 astrand 933 #endif // #ifdef SS_ANSI
3076 astrand 931
3077 astrand 933 void Format(const CT * szFmt, ...)
3078     {
3079     va_list argList;
3080     va_start(argList, szFmt);
3081     FormatV(szFmt, argList);
3082     va_end(argList);
3083     }
3084    
3085 astrand 931 #endif // #ifdef SS_SAFE_FORMAT
3086    
3087 astrand 933 void AppendFormat(const CT * szFmt, ...)
3088     {
3089     va_list argList;
3090     va_start(argList, szFmt);
3091     AppendFormatV(szFmt, argList);
3092     va_end(argList);
3093     }
3094 astrand 930
3095 astrand 933 #define MAX_FMT_TRIES 5 // #of times we try
3096     #define FMT_BLOCK_SIZE 2048 // # of bytes to increment per try
3097     #define BUFSIZE_1ST 256
3098     #define BUFSIZE_2ND 512
3099     #define STD_BUF_SIZE 1024
3100 astrand 930
3101 astrand 933 // an efficient way to add formatted characters to the string. You may only
3102     // add up to STD_BUF_SIZE characters at a time, though
3103     void AppendFormatV(const CT * szFmt, va_list argList)
3104     {
3105     CT szBuf[STD_BUF_SIZE];
3106     #ifdef SS_ANSI
3107     int nLen = ssvsprintf(szBuf, STD_BUF_SIZE - 1, szFmt, argList);
3108     #else
3109     int nLen = ssnprintf(szBuf, STD_BUF_SIZE - 1, szFmt, argList);
3110     #endif
3111     if (0 < nLen)
3112     this->append(szBuf, nLen);
3113     }
3114 astrand 930
3115 astrand 933 // -------------------------------------------------------------------------
3116     // FUNCTION: FormatV
3117     // void FormatV(PCSTR szFormat, va_list, argList);
3118     //
3119     // DESCRIPTION:
3120     // This function formats the string with sprintf style format-specs.
3121     // It makes a general guess at required buffer size and then tries
3122     // successively larger buffers until it finds one big enough or a
3123     // threshold (MAX_FMT_TRIES) is exceeded.
3124     //
3125     // PARAMETERS:
3126     // szFormat - a PCSTR holding the format of the output
3127     // argList - a Microsoft specific va_list for variable argument lists
3128     //
3129     // RETURN VALUE:
3130     // -------------------------------------------------------------------------
3131 astrand 930
3132 astrand 933 void FormatV(const CT * szFormat, va_list argList)
3133     {
3134     #ifdef SS_ANSI
3135 astrand 930
3136 astrand 933 int nLen = sslen(szFormat) + STD_BUF_SIZE;
3137     ssvsprintf(GetBuffer(nLen), nLen - 1, szFormat, argList);
3138     ReleaseBuffer();
3139 astrand 930
3140 astrand 933 #else
3141 astrand 930
3142 astrand 933 CT *pBuf = NULL;
3143     int nChars = 1;
3144     int nUsed = 0;
3145     size_type nActual = 0;
3146     int nTry = 0;
3147 astrand 930
3148 astrand 933 do {
3149     // Grow more than linearly (e.g. 512, 1536, 3072, etc)
3150 astrand 930
3151 astrand 933 nChars += ((nTry + 1) * FMT_BLOCK_SIZE);
3152     pBuf = reinterpret_cast < CT * >(_alloca(sizeof(CT) * nChars));
3153     nUsed = ssnprintf(pBuf, nChars - 1, szFormat, argList);
3154 astrand 930
3155 astrand 933 // Ensure proper NULL termination.
3156 astrand 930
3157 astrand 933 nActual = nUsed == -1 ? nChars - 1 : SSMIN(nUsed, nChars - 1);
3158     pBuf[nActual] = '\0';
3159 astrand 930
3160    
3161 astrand 933 } while (nUsed < 0 && nTry++ < MAX_FMT_TRIES);
3162 astrand 930
3163 astrand 933 // assign whatever we managed to format
3164 astrand 930
3165 astrand 933 this->assign(pBuf, nActual);
3166 astrand 930
3167 astrand 933 #endif
3168     }
3169 astrand 930
3170 astrand 933 // -------------------------------------------------------------------------
3171     // CString Facade Functions:
3172     //
3173     // The following methods are intended to allow you to use this class as a
3174     // near drop-in replacement for CString.
3175     // -------------------------------------------------------------------------
3176     #ifdef SS_WIN32
3177     BSTR AllocSysString() const
3178     {
3179     ostring os;
3180     ssasn(os, *this);
3181     return::SysAllocString(os.c_str());
3182     }
3183     #endif
3184 astrand 930
3185 astrand 933 int Collate(PCMYSTR szThat) const
3186     {
3187     return sscoll(this->c_str(), this->length(), szThat, sslen(szThat));
3188     }
3189 astrand 930
3190 astrand 933 int CollateNoCase(PCMYSTR szThat) const
3191     {
3192     return ssicoll(this->c_str(), this->length(), szThat, sslen(szThat));
3193     }
3194 astrand 930
3195 astrand 933 int Compare(PCMYSTR szThat) const
3196     {
3197     return this->compare(szThat);
3198     }
3199 astrand 930
3200 astrand 933 int CompareNoCase(PCMYSTR szThat) const
3201     {
3202     return ssicmp(this->c_str(), szThat);
3203     }
3204 astrand 930
3205 astrand 933 int Delete(int nIdx, int nCount = 1) {
3206     if (nIdx < 0)
3207     nIdx = 0;
3208 astrand 930
3209 astrand 933 if (nIdx < this->GetLength())
3210     this->erase(static_cast < MYSIZE > (nIdx),
3211     static_cast < MYSIZE > (nCount));
3212 astrand 931
3213 astrand 933 return GetLength();
3214     }
3215 astrand 930
3216 astrand 933 void Empty()
3217     {
3218     this->erase();
3219     }
3220 astrand 930
3221 astrand 933 int Find(CT ch) const
3222     {
3223     MYSIZE nIdx = this->find_first_of(ch);
3224     return static_cast < int >(MYBASE::npos == nIdx ? -1 : nIdx);
3225     }
3226 astrand 930
3227 astrand 933 int Find(PCMYSTR szSub) const
3228     {
3229     MYSIZE nIdx = this->find(szSub);
3230     return static_cast < int >(MYBASE::npos == nIdx ? -1 : nIdx);
3231     }
3232 astrand 930
3233 astrand 933 int Find(CT ch, int nStart) const
3234     {
3235     // CString::Find docs say add 1 to nStart when it's not zero
3236     // CString::Find code doesn't do that however. We'll stick
3237     // with what the code does
3238 astrand 930
3239 astrand 933 MYSIZE nIdx =
3240     this->find_first_of(ch, static_cast < MYSIZE > (nStart));
3241     return static_cast < int >(MYBASE::npos == nIdx ? -1 : nIdx);
3242     }
3243 astrand 930
3244 astrand 933 int Find(PCMYSTR szSub, int nStart) const
3245     {
3246     // CString::Find docs say add 1 to nStart when it's not zero
3247     // CString::Find code doesn't do that however. We'll stick
3248     // with what the code does
3249 astrand 930
3250 astrand 933 MYSIZE nIdx = this->find(szSub, static_cast < MYSIZE > (nStart));
3251     return static_cast < int >(MYBASE::npos == nIdx ? -1 : nIdx);
3252     }
3253 astrand 930
3254 astrand 933 int FindOneOf(PCMYSTR szCharSet) const
3255     {
3256     MYSIZE nIdx = this->find_first_of(szCharSet);
3257     return static_cast < int >(MYBASE::npos == nIdx ? -1 : nIdx);
3258     }
3259 astrand 930
3260     #ifndef SS_ANSI
3261 astrand 933 void FormatMessage(PCMYSTR szFormat, ...) throw(std::exception)
3262     {
3263     va_list argList;
3264     va_start(argList, szFormat);
3265     PMYSTR szTemp;
3266     if (ssfmtmsg
3267     (FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER,
3268     szFormat, 0, 0, reinterpret_cast < PMYSTR > (&szTemp), 0,
3269     &argList) == 0 || szTemp == 0) {
3270     throw std::runtime_error("out of memory");
3271     }
3272     *this = szTemp;
3273     LocalFree(szTemp);
3274     va_end(argList);
3275     }
3276 astrand 930
3277 astrand 933 void FormatMessage(UINT nFormatId, ...) throw(std::exception)
3278     {
3279     MYTYPE sFormat;
3280     VERIFY(sFormat.LoadString(nFormatId));
3281     va_list argList;
3282     va_start(argList, nFormatId);
3283     PMYSTR szTemp;
3284     if (ssfmtmsg
3285     (FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER,
3286     sFormat, 0, 0, reinterpret_cast < PMYSTR > (&szTemp), 0,
3287     &argList) == 0 || szTemp == 0) {
3288     throw std::runtime_error("out of memory");
3289     }
3290     *this = szTemp;
3291     LocalFree(szTemp);
3292     va_end(argList);
3293     }
3294 astrand 930 #endif
3295    
3296 astrand 933 // GetAllocLength -- an MSVC7 function but it costs us nothing to add it.
3297 astrand 930
3298 astrand 933 int GetAllocLength()
3299     {
3300     return static_cast < int >(this->capacity());
3301     }
3302 astrand 931
3303 astrand 933 // -------------------------------------------------------------------------
3304     // GetXXXX -- Direct access to character buffer
3305     // -------------------------------------------------------------------------
3306     CT GetAt(int nIdx) const
3307     {
3308     return this->at(static_cast < MYSIZE > (nIdx));
3309     }
3310 astrand 930
3311 astrand 933 CT *GetBuffer(int nMinLen = -1) {
3312     return GetBuf(nMinLen);
3313     }
3314 astrand 930
3315 astrand 933 CT *GetBufferSetLength(int nLen)
3316     {
3317     return BufferSet(nLen);
3318     }
3319 astrand 930
3320 astrand 933 // GetLength() -- MFC docs say this is the # of BYTES but
3321     // in truth it is the number of CHARACTERs (chars or wchar_ts)
3322     int GetLength() const
3323     {
3324     return static_cast < int >(this->length());
3325     }
3326 astrand 930
3327 astrand 933 int Insert(int nIdx, CT ch)
3328     {
3329     if (static_cast < MYSIZE > (nIdx) > this->size() - 1)
3330     this->append(1, ch);
3331     else
3332     this->insert(static_cast < MYSIZE > (nIdx), 1, ch);
3333 astrand 930
3334 astrand 933 return GetLength();
3335     }
3336     int Insert(int nIdx, PCMYSTR sz)
3337     {
3338     if (static_cast < MYSIZE > (nIdx) >= this->size())
3339     this->append(sz, static_cast < MYSIZE > (sslen(sz)));
3340     else
3341     this->insert(static_cast < MYSIZE > (nIdx), sz);
3342 astrand 930
3343 astrand 933 return GetLength();
3344     }
3345 astrand 930
3346 astrand 933 bool IsEmpty() const
3347     {
3348     return this->empty();
3349     }
3350    
3351     MYTYPE Left(int nCount) const
3352     {
3353 astrand 931 // Range check the count.
3354    
3355 astrand 933 nCount = SSMAX(0, SSMIN(nCount, static_cast < int >(this->size())));
3356     return this->substr(0, static_cast < MYSIZE > (nCount));
3357     }
3358 astrand 930
3359 astrand 931 #ifndef SS_ANSI
3360 astrand 933 bool LoadString(UINT nId)
3361     {
3362     return this->Load(nId);
3363     }
3364 astrand 931 #endif
3365 astrand 930
3366 astrand 933 void MakeLower()
3367     {
3368     ToLower();
3369     }
3370 astrand 930
3371 astrand 933 void MakeReverse()
3372     {
3373     std::reverse(this->begin(), this->end());
3374     }
3375 astrand 930
3376 astrand 933 void MakeUpper()
3377     {
3378     ToUpper();
3379     }
3380 astrand 930
3381 astrand 933 MYTYPE Mid(int nFirst) const
3382     {
3383     return Mid(nFirst, this->GetLength() - nFirst);
3384     }
3385 astrand 930
3386 astrand 933 MYTYPE Mid(int nFirst, int nCount) const
3387     {
3388     // CString does range checking here. Since we're trying to emulate it,
3389     // we must check too.
3390 astrand 931
3391 astrand 933 if (nFirst < 0)
3392     nFirst = 0;
3393     if (nCount < 0)
3394     nCount = 0;
3395 astrand 931
3396 astrand 933 int nSize = static_cast < int >(this->size());
3397 astrand 931
3398 astrand 933 if (nFirst + nCount > nSize)
3399     nCount = nSize - nFirst;
3400 astrand 931
3401 astrand 933 if (nFirst > nSize)
3402     return MYTYPE();
3403 astrand 931
3404 astrand 933 ASSERT(nFirst >= 0);
3405     ASSERT(nFirst + nCount <= nSize);
3406 astrand 931
3407 astrand 933 return this->substr(static_cast < MYSIZE > (nFirst),
3408     static_cast < MYSIZE > (nCount));
3409     }
3410 astrand 930
3411 astrand 933 void ReleaseBuffer(int nNewLen = -1) {
3412     RelBuf(nNewLen);
3413     }
3414 astrand 930
3415 astrand 933 int Remove(CT ch)
3416     {
3417     MYSIZE nIdx = 0;
3418     int nRemoved = 0;
3419     while ((nIdx = this->find_first_of(ch)) != MYBASE::npos) {
3420     this->erase(nIdx, 1);
3421     nRemoved++;
3422     }
3423     return nRemoved;
3424     }
3425 astrand 930
3426 astrand 933 int Replace(CT chOld, CT chNew)
3427     {
3428     int nReplaced = 0;
3429 astrand 931
3430 astrand 933 for (MYITER iter = this->begin(); iter != this->end(); iter++) {
3431     if (*iter == chOld) {
3432     *iter = chNew;
3433     nReplaced++;
3434     }
3435     }
3436 astrand 931
3437 astrand 933 return nReplaced;
3438     }
3439 astrand 930
3440 astrand 933 int Replace(PCMYSTR szOld, PCMYSTR szNew)
3441     {
3442     int nReplaced = 0;
3443     MYSIZE nIdx = 0;
3444     MYSIZE nOldLen = sslen(szOld);
3445 astrand 930
3446 astrand 933 if (0 != nOldLen) {
3447     // If the replacement string is longer than the one it replaces, this
3448     // string is going to have to grow in size, Figure out how much
3449     // and grow it all the way now, rather than incrementally
3450 astrand 930
3451 astrand 933 MYSIZE nNewLen = sslen(szNew);
3452     if (nNewLen > nOldLen) {
3453     int nFound = 0;
3454     while (nIdx < this->length() &&
3455     (nIdx = this->find(szOld, nIdx)) != MYBASE::npos) {
3456     nFound++;
3457     nIdx += nOldLen;
3458     }
3459     this->reserve(this->size() + nFound * (nNewLen - nOldLen));
3460     }
3461 astrand 931
3462    
3463 astrand 933 static const CT ch = CT(0);
3464     PCMYSTR szRealNew = szNew == 0 ? &ch : szNew;
3465     nIdx = 0;
3466 astrand 931
3467 astrand 933 while (nIdx < this->length() &&
3468     (nIdx = this->find(szOld, nIdx)) != MYBASE::npos) {
3469     this->replace(this->begin() + nIdx,
3470     this->begin() + nIdx + nOldLen, szRealNew);
3471 astrand 931
3472 astrand 933 nReplaced++;
3473     nIdx += nNewLen;
3474     }
3475     }
3476 astrand 931
3477 astrand 933 return nReplaced;
3478     }
3479 astrand 930
3480 astrand 933 int ReverseFind(CT ch) const
3481     {
3482     MYSIZE nIdx = this->find_last_of(ch);
3483     return static_cast < int >(MYBASE::npos == nIdx ? -1 : nIdx);
3484     }
3485 astrand 930
3486 astrand 933 // ReverseFind overload that's not in CString but might be useful
3487     int ReverseFind(PCMYSTR szFind, MYSIZE pos = MYBASE::npos) const
3488     {
3489     MYSIZE nIdx = this->rfind(0 == szFind ? MYTYPE() : szFind, pos);
3490     return static_cast < int >(MYBASE::npos == nIdx ? -1 : nIdx);
3491     }
3492 astrand 930
3493 astrand 933 MYTYPE Right(int nCount) const
3494     {
3495 astrand 931 // Range check the count.
3496    
3497 astrand 933 nCount = SSMAX(0, SSMIN(nCount, static_cast < int >(this->size())));
3498     return this->substr(this->size() - static_cast < MYSIZE > (nCount));
3499     }
3500 astrand 930
3501 astrand 933 void SetAt(int nIndex, CT ch)
3502     {
3503     ASSERT(this->size() > static_cast < MYSIZE > (nIndex));
3504     this->at(static_cast < MYSIZE > (nIndex)) = ch;
3505     }
3506 astrand 930
3507 astrand 931 #ifndef SS_ANSI
3508 astrand 933 BSTR SetSysString(BSTR * pbstr) const
3509     {
3510     ostring os;
3511     ssasn(os, *this);
3512     if (!::SysReAllocStringLen(pbstr, os.c_str(), os.length()))
3513     throw std::runtime_error("out of memory");
3514 astrand 930
3515 astrand 933 ASSERT(*pbstr != 0);
3516     return *pbstr;
3517     }
3518 astrand 931 #endif
3519 astrand 930
3520 astrand 933 MYTYPE SpanExcluding(PCMYSTR szCharSet) const
3521     {
3522 astrand 931 MYSIZE pos = this->find_first_of(szCharSet);
3523     return pos == MYBASE::npos ? *this : Left(pos);
3524 astrand 933 }
3525 astrand 930
3526 astrand 933 MYTYPE SpanIncluding(PCMYSTR szCharSet) const
3527     {
3528 astrand 931 MYSIZE pos = this->find_first_not_of(szCharSet);
3529     return pos == MYBASE::npos ? *this : Left(pos);
3530 astrand 933 }
3531 astrand 930
3532 astrand 931 #if defined SS_WIN32 && !defined(UNICODE) && !defined(SS_ANSI)
3533 astrand 930
3534 astrand 933 // CString's OemToAnsi and AnsiToOem functions are available only in
3535     // Unicode builds. However since we're a template we also need a
3536     // runtime check of CT and a reinterpret_cast to account for the fact
3537     // that CStdStringW gets instantiated even in non-Unicode builds.
3538 astrand 930
3539 astrand 933 void AnsiToOem()
3540     {
3541     if (sizeof(CT) == sizeof(char) && !empty()) {
3542     ::CharToOem(reinterpret_cast < PCSTR > (this->c_str()),
3543     reinterpret_cast < PSTR > (GetBuf()));
3544     }
3545     else {
3546     ASSERT(false);
3547     }
3548     }
3549 astrand 930
3550 astrand 933 void OemToAnsi()
3551     {
3552     if (sizeof(CT) == sizeof(char) && !empty()) {
3553     ::OemToChar(reinterpret_cast < PCSTR > (this->c_str()),
3554     reinterpret_cast < PSTR > (GetBuf()));
3555     }
3556     else {
3557     ASSERT(false);
3558     }
3559     }
3560 astrand 930
3561 astrand 931 #endif
3562 astrand 930
3563    
3564 astrand 933 // -------------------------------------------------------------------------
3565     // Trim and its variants
3566     // -------------------------------------------------------------------------
3567     MYTYPE & Trim() {
3568     return TrimLeft().TrimRight();
3569     }
3570 astrand 931
3571 astrand 933 MYTYPE & TrimLeft() {
3572     this->erase(this->begin(),
3573     std::find_if(this->begin(), this->end(),
3574     NotSpace < CT > ()));
3575 astrand 930
3576 astrand 933 return *this;
3577     }
3578 astrand 930
3579 astrand 933 MYTYPE & TrimLeft(CT tTrim) {
3580     this->erase(0, this->find_first_not_of(tTrim));
3581     return *this;
3582     }
3583 astrand 930
3584 astrand 933 MYTYPE & TrimLeft(PCMYSTR szTrimChars) {
3585     this->erase(0, this->find_first_not_of(szTrimChars));
3586     return *this;
3587     }
3588 astrand 930
3589 astrand 933 MYTYPE & TrimRight() {
3590     // NOTE: When comparing reverse_iterators here (MYRITER), I avoid using
3591     // operator!=. This is because namespace rel_ops also has a template
3592     // operator!= which conflicts with the global operator!= already defined
3593     // for reverse_iterator in the header <utility>.
3594     // Thanks to John James for alerting me to this.
3595 astrand 931
3596 astrand 933 MYRITER it =
3597     std::find_if(this->rbegin(), this->rend(), NotSpace < CT > ());
3598     if (!(this->rend() == it))
3599     this->erase(this->rend() - it);
3600 astrand 930
3601 astrand 933 this->erase(!(it == this->rend())? this->find_last_of(*it) + 1 : 0);
3602     return *this;
3603     }
3604 astrand 930
3605 astrand 933 MYTYPE & TrimRight(CT tTrim) {
3606     MYSIZE nIdx = this->find_last_not_of(tTrim);
3607     this->erase(MYBASE::npos == nIdx ? 0 : ++nIdx);
3608     return *this;
3609     }
3610 astrand 930
3611 astrand 933 MYTYPE & TrimRight(PCMYSTR szTrimChars) {
3612     MYSIZE nIdx = this->find_last_not_of(szTrimChars);
3613     this->erase(MYBASE::npos == nIdx ? 0 : ++nIdx);
3614     return *this;
3615     }
3616 astrand 930
3617 astrand 933 void FreeExtra()
3618     {
3619     MYTYPE mt;
3620     this->swap(mt);
3621     if (!mt.empty())
3622     this->assign(mt.c_str(), mt.size());
3623     }
3624 astrand 930
3625 astrand 933 // I have intentionally not implemented the following CString
3626     // functions. You cannot make them work without taking advantage
3627     // of implementation specific behavior. However if you absolutely
3628     // MUST have them, uncomment out these lines for "sort-of-like"
3629     // their behavior. You're on your own.
3630 astrand 930
3631 astrand 933 // CT* LockBuffer() { return GetBuf(); }// won't really lock
3632     // void UnlockBuffer(); { } // why have UnlockBuffer w/o LockBuffer?
3633 astrand 931
3634 astrand 933 // Array-indexing operators. Required because we defined an implicit cast
3635     // to operator const CT* (Thanks to Julian Selman for pointing this out)
3636 astrand 930
3637 astrand 933 CT & operator[](int nIdx) {
3638     return static_cast < MYBASE * >(this)->operator[](static_cast <
3639     MYSIZE > (nIdx));
3640     }
3641 astrand 930
3642 astrand 933 const CT & operator[] (int nIdx) const
3643     {
3644     return static_cast < const MYBASE *>(this)->operator[] (static_cast <
3645     MYSIZE >
3646     (nIdx));
3647     }
3648 astrand 930
3649 astrand 933 CT & operator[] (unsigned int nIdx)
3650     {
3651     return static_cast < MYBASE * >(this)->operator[](static_cast <
3652     MYSIZE > (nIdx));
3653     }
3654 astrand 930
3655 astrand 933 const CT & operator[] (unsigned int nIdx) const
3656     {
3657     return static_cast < const MYBASE *>(this)->operator[] (static_cast <
3658     MYSIZE >
3659     (nIdx));
3660     }
3661    
3662 astrand 931 #ifndef SS_NO_IMPLICIT_CAST
3663 astrand 933 operator const CT *() const
3664     {
3665     return this->c_str();
3666     }
3667 astrand 931 #endif
3668 astrand 930
3669 astrand 933 // IStream related functions. Useful in IPersistStream implementations
3670 astrand 930
3671     #ifdef SS_INC_COMDEF
3672    
3673 astrand 933 // struct SSSHDR - useful for non Std C++ persistence schemes.
3674     typedef struct SSSHDR
3675     {
3676     BYTE byCtrl;
3677     ULONG nChars;
3678     } SSSHDR; // as in "Standard String Stream Header"
3679 astrand 930
3680 astrand 933 #define SSSO_UNICODE 0x01 // the string is a wide string
3681     #define SSSO_COMPRESS 0x02 // the string is compressed
3682 astrand 930
3683 astrand 933 // -------------------------------------------------------------------------
3684     // FUNCTION: StreamSize
3685     // REMARKS:
3686     // Returns how many bytes it will take to StreamSave() this CStdString
3687     // object to an IStream.
3688     // -------------------------------------------------------------------------
3689     ULONG StreamSize() const
3690     {
3691     // Control header plus string
3692     ASSERT(this->size() * sizeof(CT) < 0xffffffffUL - sizeof(SSSHDR));
3693     return (this->size() * sizeof(CT)) + sizeof(SSSHDR);
3694     }
3695 astrand 930
3696 astrand 933 // -------------------------------------------------------------------------
3697     // FUNCTION: StreamSave
3698     // REMARKS:
3699     // Saves this CStdString object to a COM IStream.
3700     // -------------------------------------------------------------------------
3701     HRESULT StreamSave(IStream * pStream) const
3702     {
3703     ASSERT(this->size() * sizeof(CT) < 0xffffffffUL - sizeof(SSSHDR));
3704     HRESULT hr = E_FAIL;
3705     ASSERT(pStream != 0);
3706     SSSHDR hdr;
3707     hdr.byCtrl = sizeof(CT) == 2 ? SSSO_UNICODE : 0;
3708     hdr.nChars = this->size();
3709 astrand 930
3710    
3711 astrand 933 if (FAILED(hr = pStream->Write(&hdr, sizeof(SSSHDR), 0))) {
3712     TRACE(_T("StreamSave: Cannot write control header, ERR=0x%X\n"),
3713     hr);
3714     }
3715     else if (empty())
3716     {
3717     ; // nothing to write
3718     }
3719     else if (FAILED(hr = pStream->Write(this->c_str(),
3720     this->size() * sizeof(CT), 0))) {
3721     TRACE(_T("StreamSave: Cannot write string to stream 0x%X\n"), hr);
3722     }
3723 astrand 930
3724 astrand 933 return hr;
3725     }
3726 astrand 930
3727    
3728 astrand 933 // -------------------------------------------------------------------------
3729     // FUNCTION: StreamLoad
3730     // REMARKS:
3731     // This method loads the object from an IStream.
3732     // -------------------------------------------------------------------------
3733     HRESULT StreamLoad(IStream * pStream)
3734     {
3735     ASSERT(pStream != 0);
3736     SSSHDR hdr;
3737     HRESULT hr = E_FAIL;
3738 astrand 930
3739 astrand 933 if (FAILED(hr = pStream->Read(&hdr, sizeof(SSSHDR), 0))) {
3740     TRACE(_T("StreamLoad: Cant read control header, ERR=0x%X\n"), hr);
3741     }
3742     else if (hdr.nChars > 0) {
3743     ULONG nRead = 0;
3744     PMYSTR pMyBuf = BufferSet(hdr.nChars);
3745 astrand 930
3746 astrand 933 // If our character size matches the character size of the string
3747     // we're trying to read, then we can read it directly into our
3748     // buffer. Otherwise, we have to read into an intermediate buffer
3749     // and convert.
3750    
3751     if ((hdr.byCtrl & SSSO_UNICODE) != 0) {
3752     ULONG nBytes = hdr.nChars * sizeof(wchar_t);
3753     if (sizeof(CT) == sizeof(wchar_t)) {
3754     if (FAILED(hr = pStream->Read(pMyBuf, nBytes, &nRead)))
3755     TRACE(_T("StreamLoad: Cannot read string: 0x%X\n"),
3756     hr);
3757     }
3758     else {
3759     PWSTR pBufW =
3760     reinterpret_cast < PWSTR > (_alloca((nBytes) + 1));
3761     if (FAILED(hr = pStream->Read(pBufW, nBytes, &nRead)))
3762     TRACE(_T("StreamLoad: Cannot read string: 0x%X\n"),
3763     hr);
3764     else
3765     sscpy(pMyBuf, pBufW, hdr.nChars);
3766     }
3767     }
3768     else {
3769     ULONG nBytes = hdr.nChars * sizeof(char);
3770     if (sizeof(CT) == sizeof(char)) {
3771     if (FAILED(hr = pStream->Read(pMyBuf, nBytes, &nRead)))
3772     TRACE(_T("StreamLoad: Cannot read string: 0x%X\n"),
3773     hr);
3774     }
3775     else {
3776     PSTR pBufA = reinterpret_cast < PSTR > (_alloca(nBytes));
3777     if (FAILED(hr = pStream->Read(pBufA, hdr.nChars, &nRead)))
3778     TRACE(_T("StreamLoad: Cannot read string: 0x%X\n"),
3779     hr);
3780     else
3781     sscpy(pMyBuf, pBufA, hdr.nChars);
3782     }
3783     }
3784     }
3785     else {
3786     this->erase();
3787     }
3788     return hr;
3789     }
3790 astrand 930 #endif // #ifdef SS_INC_COMDEF
3791    
3792     #ifndef SS_ANSI
3793    
3794 astrand 933 // SetResourceHandle/GetResourceHandle. In MFC builds, these map directly
3795     // to AfxSetResourceHandle and AfxGetResourceHandle. In non-MFC builds they
3796     // point to a single static HINST so that those who call the member
3797     // functions that take resource IDs can provide an alternate HINST of a DLL
3798     // to search. This is not exactly the list of HMODULES that MFC provides
3799     // but it's better than nothing.
3800 astrand 930
3801 astrand 933 #ifdef _MFC_VER
3802     static void SetResourceHandle(HMODULE hNew)
3803     {
3804     AfxSetResourceHandle(hNew);
3805     }
3806     static HMODULE GetResourceHandle()
3807     {
3808     return AfxGetResourceHandle();
3809     }
3810     #else
3811     static void SetResourceHandle(HMODULE hNew)
3812     {
3813     SSResourceHandle() = hNew;
3814     }
3815     static HMODULE GetResourceHandle()
3816     {
3817     return SSResourceHandle();
3818     }
3819     #endif
3820 astrand 930
3821     #endif
3822     };
3823    
3824 astrand 931 // -----------------------------------------------------------------------------
3825     // MSVC USERS: HOW TO EXPORT CSTDSTRING FROM A DLL
3826     //
3827     // If you are using MS Visual C++ and you want to export CStdStringA and
3828     // CStdStringW from a DLL, then all you need to
3829     //
3830 astrand 933 // 1. make sure that all components link to the same DLL version
3831     // of the CRT (not the static one).
3832     // 2. Uncomment the 3 lines of code below
3833     // 3. #define 2 macros per the instructions in MS KnowledgeBase
3834     // article Q168958. The macros are:
3835 astrand 931 //
3836 astrand 933 // MACRO DEFINTION WHEN EXPORTING DEFINITION WHEN IMPORTING
3837     // ----- ------------------------ -------------------------
3838     // SSDLLEXP (nothing, just #define it) extern
3839     // SSDLLSPEC __declspec(dllexport) __declspec(dllimport)
3840 astrand 931 //
3841 astrand 933 // Note that these macros must be available to ALL clients who want to
3842     // link to the DLL and use the class. If they
3843 astrand 931 //
3844     // A word of advice: Don't bother.
3845     //
3846     // Really, it is not necessary to export CStdString functions from a DLL. I
3847     // never do. In my projects, I do generally link to the DLL version of the
3848     // Standard C++ Library, but I do NOT attempt to export CStdString functions.
3849     // I simply include the header where it is needed and allow for the code
3850     // redundancy.
3851     //
3852     // That redundancy is a lot less than you think. This class does most of its
3853     // work via the Standard C++ Library, particularly the base_class basic_string<>
3854     // member functions. Most of the functions here are small enough to be inlined
3855     // anyway. Besides, you'll find that in actual practice you use less than 1/2
3856     // of the code here, even in big projects and different modules will use as
3857     // little as 10% of it. That means a lot less functions actually get linked
3858     // your binaries. If you export this code from a DLL, it ALL gets linked in.
3859     //
3860     // I've compared the size of the binaries from exporting vs NOT exporting. Take
3861     // my word for it -- exporting this code is not worth the hassle.
3862     //
3863     // -----------------------------------------------------------------------------
3864     //#pragma warning(disable:4231) // non-standard extension ("extern template")
3865 astrand 933 // SSDLLEXP template class SSDLLSPEC CStdStr<char>;
3866     // SSDLLEXP template class SSDLLSPEC CStdStr<wchar_t>;
3867 astrand 930
3868    
3869 astrand 931 // =============================================================================
3870 astrand 933 // END OF CStdStr INLINE FUNCTION DEFINITIONS
3871 astrand 931 // =============================================================================
3872    
3873 astrand 933 // Now typedef our class names based upon this humongous template
3874 astrand 931
3875 astrand 933 typedef CStdStr < char >CStdStringA; // a better std::string
3876     typedef CStdStr < wchar_t > CStdStringW; // a better std::wstring
3877     typedef CStdStr < OLECHAR > CStdStringO; // almost always CStdStringW
3878 astrand 931
3879 astrand 930 // -----------------------------------------------------------------------------
3880 astrand 931 // CStdStr addition functions defined as inline
3881 astrand 930 // -----------------------------------------------------------------------------
3882 astrand 931
3883    
3884 astrand 933 inline CStdStringA operator+(const CStdStringA & s1, const CStdStringA & s2)
3885 astrand 930 {
3886 astrand 933 CStdStringA sRet(SSREF(s1));
3887     sRet.append(s2);
3888     return sRet;
3889 astrand 930 }
3890 astrand 933 inline CStdStringA operator+(const CStdStringA & s1,
3891     CStdStringA::value_type t)
3892 astrand 930 {
3893 astrand 933 CStdStringA sRet(SSREF(s1));
3894     sRet.append(1, t);
3895     return sRet;
3896 astrand 930 }
3897 astrand 933 inline CStdStringA operator+(const CStdStringA & s1, PCSTR pA)
3898 astrand 930 {
3899 astrand 933 CStdStringA sRet(SSREF(s1));
3900     sRet.append(pA);
3901     return sRet;
3902 astrand 930 }
3903 astrand 933 inline CStdStringA operator+(PCSTR pA, const CStdStringA & sA)
3904 astrand 930 {
3905 astrand 933 CStdStringA sRet;
3906     CStdStringA::size_type nObjSize = sA.size();
3907     CStdStringA::size_type nLitSize =
3908     static_cast < CStdStringA::size_type > (sslen(pA));
3909 astrand 930
3910 astrand 933 sRet.reserve(nLitSize + nObjSize);
3911     sRet.assign(pA);
3912     sRet.append(sA);
3913     return sRet;
3914 astrand 930 }
3915    
3916 astrand 931
3917 astrand 933 inline CStdStringA operator+(const CStdStringA & s1, const CStdStringW & s2)
3918 astrand 930 {
3919 astrand 933 return s1 + CStdStringA(s2);
3920 astrand 930 }
3921 astrand 933 inline CStdStringW operator+(const CStdStringW & s1, const CStdStringW & s2)
3922 astrand 931 {
3923 astrand 933 CStdStringW sRet(SSREF(s1));
3924     sRet.append(s2);
3925     return sRet;
3926 astrand 931 }
3927 astrand 933 inline CStdStringA operator+(const CStdStringA & s1, PCWSTR pW)
3928 astrand 931 {
3929 astrand 933 return s1 + CStdStringA(pW);
3930 astrand 931 }
3931 astrand 930
3932 astrand 931 #ifdef UNICODE
3933 astrand 933 inline CStdStringW operator+(PCWSTR pW, const CStdStringA & sA)
3934     {
3935     return CStdStringW(pW) + CStdStringW(SSREF(sA));
3936     }
3937     inline CStdStringW operator+(PCSTR pA, const CStdStringW & sW)
3938     {
3939     return CStdStringW(pA) + sW;
3940     }
3941 astrand 931 #else
3942 astrand 933 inline CStdStringA operator+(PCWSTR pW, const CStdStringA & sA)
3943     {
3944     return CStdStringA(pW) + sA;
3945     }
3946     inline CStdStringA operator+(PCSTR pA, const CStdStringW & sW)
3947     {
3948     return pA + CStdStringA(sW);
3949     }
3950 astrand 930 #endif
3951    
3952 astrand 931 // ...Now the wide string versions.
3953 astrand 933 inline CStdStringW operator+(const CStdStringW & s1,
3954     CStdStringW::value_type t)
3955 astrand 930 {
3956 astrand 933 CStdStringW sRet(SSREF(s1));
3957     sRet.append(1, t);
3958     return sRet;
3959 astrand 930 }
3960 astrand 933 inline CStdStringW operator+(const CStdStringW & s1, PCWSTR pW)
3961 astrand 930 {
3962 astrand 933 CStdStringW sRet(SSREF(s1));
3963     sRet.append(pW);
3964     return sRet;
3965 astrand 930 }
3966 astrand 933 inline CStdStringW operator+(PCWSTR pW, const CStdStringW & sW)
3967 astrand 930 {
3968 astrand 933 CStdStringW sRet;
3969     CStdStringW::size_type nObjSize = sW.size();
3970     CStdStringA::size_type nLitSize =
3971     static_cast < CStdStringW::size_type > (sslen(pW));
3972 astrand 930
3973 astrand 933 sRet.reserve(nLitSize + nObjSize);
3974     sRet.assign(pW);
3975     sRet.append(sW);
3976     return sRet;
3977 astrand 930 }
3978    
3979 astrand 933 inline CStdStringW operator+(const CStdStringW & s1, const CStdStringA & s2)
3980 astrand 930 {
3981 astrand 933 return s1 + CStdStringW(s2);
3982 astrand 930 }
3983 astrand 933 inline CStdStringW operator+(const CStdStringW & s1, PCSTR pA)
3984 astrand 930 {
3985 astrand 933 return s1 + CStdStringW(pA);
3986 astrand 930 }
3987    
3988    
3989 astrand 931 // New-style format function is a template
3990 astrand 930
3991 astrand 931 #ifdef SS_SAFE_FORMAT
3992 astrand 930
3993 astrand 933 template <> struct FmtArg <CStdStringA >
3994 astrand 930 {
3995 astrand 933 explicit FmtArg(const CStdStringA & arg):a_(arg)
3996     {
3997     }
3998     PCSTR operator() () const
3999     {
4000     return a_.c_str();
4001     }
4002     const CStdStringA & a_;
4003     private:
4004     FmtArg < CStdStringA > &operator=(const FmtArg < CStdStringA > &)
4005     {
4006     return *this;
4007     }
4008 astrand 931 };
4009 astrand 933 template <> struct FmtArg <CStdStringW >
4010 astrand 931 {
4011 astrand 933 explicit FmtArg(const CStdStringW & arg):a_(arg)
4012     {
4013     }
4014     PCWSTR operator() () const
4015     {
4016     return a_.c_str();
4017     }
4018     const CStdStringW & a_;
4019     private:
4020     FmtArg < CStdStringW > &operator=(const FmtArg < CStdStringW > &)
4021     {
4022     return *this;
4023     }
4024 astrand 931 };
4025 astrand 930
4026 astrand 933 template <> struct FmtArg <std::string >
4027 astrand 930 {
4028 astrand 933 explicit FmtArg(const std::string & arg):a_(arg)
4029     {
4030     }
4031     PCSTR operator() () const
4032     {
4033     return a_.c_str();
4034     }
4035     const std::string & a_;
4036     private:
4037     FmtArg < std::string > &operator=(const FmtArg < std::string > &)
4038     {
4039     return *this;
4040     }
4041 astrand 931 };
4042 astrand 933 template <> struct FmtArg <std::wstring >
4043 astrand 931 {
4044 astrand 933 explicit FmtArg(const std::wstring & arg):a_(arg)
4045     {
4046     }
4047     PCWSTR operator() () const
4048     {
4049     return a_.c_str();
4050     }
4051     const std::wstring & a_;
4052     private:
4053     FmtArg < std::wstring > &operator=(const FmtArg < std::wstring > &)
4054     {
4055     return *this;
4056     }
4057 astrand 931 };
4058     #endif // #ifdef SS_SAFEFORMAT
4059 astrand 930
4060     #ifndef SS_ANSI
4061 astrand 933 // SSResourceHandle: our MFC-like resource handle
4062     inline HMODULE & SSResourceHandle()
4063     {
4064     static HMODULE hModuleSS = GetModuleHandle(0);
4065     return hModuleSS;
4066     }
4067 astrand 930 #endif
4068    
4069    
4070     // In MFC builds, define some global serialization operators
4071     // Special operators that allow us to serialize CStdStrings to CArchives.
4072     // Note that we use an intermediate CString object in order to ensure that
4073     // we use the exact same format.
4074    
4075     #ifdef _MFC_VER
4076 astrand 933 inline CArchive & AFXAPI operator<<(CArchive & ar, const CStdStringA & strA)
4077     {
4078     CString strTemp = strA;
4079     return ar << strTemp;
4080     }
4081 astrand 930
4082 astrand 933 inline CArchive & AFXAPI operator<<(CArchive & ar, const CStdStringW & strW)
4083     {
4084     CString strTemp = strW;
4085     return ar << strTemp;
4086     }
4087 astrand 930
4088 astrand 933 inline CArchive & AFXAPI operator>>(CArchive & ar, CStdStringA & strA)
4089     {
4090     CString strTemp;
4091     ar >> strTemp;
4092     strA = strTemp;
4093     return ar;
4094     }
4095 astrand 930
4096 astrand 933 inline CArchive & AFXAPI operator>>(CArchive & ar, CStdStringW & strW)
4097     {
4098     CString strTemp;
4099     ar >> strTemp;
4100     strW = strTemp;
4101     return ar;
4102     }
4103     #endif // #ifdef _MFC_VER -- (i.e. is this MFC?)
4104 astrand 930
4105 astrand 933
4106    
4107 astrand 930 // -----------------------------------------------------------------------------
4108     // GLOBAL FUNCTION: WUFormat
4109 astrand 933 // CStdStringA WUFormat(UINT nId, ...);
4110     // CStdStringA WUFormat(PCSTR szFormat, ...);
4111 astrand 930 //
4112     // REMARKS:
4113 astrand 933 // This function allows the caller for format and return a CStdStringA
4114     // object with a single line of code.
4115 astrand 930 // -----------------------------------------------------------------------------
4116 astrand 931
4117     inline CStdStringA WUFormatA(PCSTR szFormat, ...)
4118     {
4119 astrand 933 va_list argList;
4120     va_start(argList, szFormat);
4121     CStdStringA strOut;
4122     strOut.FormatV(szFormat, argList);
4123     va_end(argList);
4124     return strOut;
4125 astrand 931 }
4126     inline CStdStringW WUFormatW(PCWSTR szwFormat, ...)
4127     {
4128 astrand 933 va_list argList;
4129     va_start(argList, szwFormat);
4130     CStdStringW strOut;
4131     strOut.FormatV(szwFormat, argList);
4132     va_end(argList);
4133     return strOut;
4134 astrand 931 }
4135 astrand 933
4136 astrand 930 #ifdef SS_ANSI
4137     #else
4138 astrand 933 inline CStdStringA WUFormatA(UINT nId, ...)
4139     {
4140     va_list argList;
4141     va_start(argList, nId);
4142 astrand 930
4143 astrand 933 CStdStringA strFmt;
4144     CStdStringA strOut;
4145     if (strFmt.Load(nId))
4146     strOut.FormatV(strFmt, argList);
4147 astrand 930
4148 astrand 933 va_end(argList);
4149     return strOut;
4150     }
4151 astrand 930
4152 astrand 933 inline CStdStringW WUFormatW(UINT nId, ...)
4153     {
4154     va_list argList;
4155     va_start(argList, nId);
4156 astrand 930
4157 astrand 933 CStdStringW strFmt;
4158     CStdStringW strOut;
4159     if (strFmt.Load(nId))
4160     strOut.FormatV(strFmt, argList);
4161 astrand 930
4162 astrand 933 va_end(argList);
4163     return strOut;
4164     }
4165 astrand 930 #endif // #ifdef SS_ANSI
4166    
4167 astrand 931
4168    
4169     #if defined(SS_WIN32) && !defined (SS_ANSI)
4170 astrand 933 // -------------------------------------------------------------------------
4171     // FUNCTION: WUSysMessage
4172     // CStdStringA WUSysMessageA(DWORD dwError, DWORD dwLangId=SS_DEFLANGID);
4173     // CStdStringW WUSysMessageW(DWORD dwError, DWORD dwLangId=SS_DEFLANGID);
4174     //
4175     // DESCRIPTION:
4176     // This function simplifies the process of obtaining a string equivalent
4177     // of a system error code returned from GetLastError(). You simply
4178     // supply the value returned by GetLastError() to this function and the
4179     // corresponding system string is returned in the form of a CStdStringA.
4180     //
4181     // PARAMETERS:
4182     // dwError - a DWORD value representing the error code to be translated
4183     // dwLangId - the language id to use. defaults to english.
4184     //
4185     // RETURN VALUE:
4186     // a CStdStringA equivalent of the error code. Currently, this function
4187     // only returns either English of the system default language strings.
4188     // -------------------------------------------------------------------------
4189     #define SS_DEFLANGID MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT)
4190     inline CStdStringA WUSysMessageA(DWORD dwError, DWORD dwLangId = SS_DEFLANGID)
4191     {
4192     CHAR szBuf[512];
4193 astrand 930
4194 astrand 933 if (0 !=::FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError,
4195     dwLangId, szBuf, 511, NULL))
4196     return WUFormatA("%s (0x%X)", szBuf, dwError);
4197     else
4198     return WUFormatA("Unknown error (0x%X)", dwError);
4199     }
4200     inline CStdStringW WUSysMessageW(DWORD dwError, DWORD dwLangId = SS_DEFLANGID)
4201     {
4202     WCHAR szBuf[512];
4203 astrand 930
4204 astrand 933 if (0 !=::FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError,
4205     dwLangId, szBuf, 511, NULL))
4206     return WUFormatW(L"%s (0x%X)", szBuf, dwError);
4207     else
4208     return WUFormatW(L"Unknown error (0x%X)", dwError);
4209     }
4210 astrand 930 #endif
4211    
4212     // Define TCHAR based friendly names for some of these functions
4213    
4214     #ifdef UNICODE
4215 astrand 933 //#define CStdString CStdStringW
4216     typedef CStdStringW CStdString;
4217     #define WUSysMessage WUSysMessageW
4218     #define WUFormat WUFormatW
4219 astrand 930 #else
4220 astrand 933 //#define CStdString CStdStringA
4221     typedef CStdStringA CStdString;
4222     #define WUSysMessage WUSysMessageA
4223     #define WUFormat WUFormatA
4224 astrand 930 #endif
4225    
4226     // ...and some shorter names for the space-efficient
4227    
4228     #define WUSysMsg WUSysMessage
4229     #define WUSysMsgA WUSysMessageA
4230     #define WUSysMsgW WUSysMessageW
4231     #define WUFmtA WUFormatA
4232     #define WUFmtW WUFormatW
4233     #define WUFmt WUFormat
4234     #define WULastErrMsg() WUSysMessage(::GetLastError())
4235     #define WULastErrMsgA() WUSysMessageA(::GetLastError())
4236     #define WULastErrMsgW() WUSysMessageW(::GetLastError())
4237    
4238    
4239     // -----------------------------------------------------------------------------
4240     // FUNCTIONAL COMPARATORS:
4241     // REMARKS:
4242 astrand 933 // These structs are derived from the std::binary_function template. They
4243     // give us functional classes (which may be used in Standard C++ Library
4244     // collections and algorithms) that perform case-insensitive comparisons of
4245     // CStdString objects. This is useful for maps in which the key may be the
4246     // proper string but in the wrong case.
4247 astrand 930 // -----------------------------------------------------------------------------
4248 astrand 933 #define StdStringLessNoCaseW SSLNCW // avoid VC compiler warning 4786
4249     #define StdStringEqualsNoCaseW SSENCW
4250     #define StdStringLessNoCaseA SSLNCA
4251     #define StdStringEqualsNoCaseA SSENCA
4252 astrand 930
4253     #ifdef UNICODE
4254 astrand 933 #define StdStringLessNoCase SSLNCW
4255     #define StdStringEqualsNoCase SSENCW
4256 astrand 930 #else
4257 astrand 933 #define StdStringLessNoCase SSLNCA
4258     #define StdStringEqualsNoCase SSENCA
4259 astrand 930 #endif
4260    
4261 astrand 933 struct StdStringLessNoCaseW:std::binary_function < CStdStringW, CStdStringW,
4262     bool >
4263 astrand 930 {
4264 astrand 933 inline
4265     bool operator() (const CStdStringW & sLeft,
4266     const CStdStringW & sRight) const
4267     {
4268     return ssicmp(sLeft.c_str(), sRight.c_str()) < 0;
4269     }
4270 astrand 930 };
4271 astrand 933 struct StdStringEqualsNoCaseW:std::binary_function < CStdStringW, CStdStringW,
4272     bool >
4273 astrand 930 {
4274 astrand 933 inline
4275     bool operator() (const CStdStringW & sLeft,
4276     const CStdStringW & sRight) const
4277     {
4278     return ssicmp(sLeft.c_str(), sRight.c_str()) == 0;
4279     }
4280 astrand 930 };
4281 astrand 933 struct StdStringLessNoCaseA:std::binary_function < CStdStringA, CStdStringA,
4282     bool >
4283 astrand 930 {
4284 astrand 933 inline
4285     bool operator() (const CStdStringA & sLeft,
4286     const CStdStringA & sRight) const
4287     {
4288     return ssicmp(sLeft.c_str(), sRight.c_str()) < 0;
4289     }
4290 astrand 930 };
4291 astrand 933 struct StdStringEqualsNoCaseA:std::binary_function < CStdStringA, CStdStringA,
4292     bool >
4293 astrand 930 {
4294 astrand 933 inline
4295     bool operator() (const CStdStringA & sLeft,
4296     const CStdStringA & sRight) const
4297     {
4298     return ssicmp(sLeft.c_str(), sRight.c_str()) == 0;
4299     }
4300 astrand 930 };
4301    
4302     // If we had to define our own version of TRACE above, get rid of it now
4303    
4304     #ifdef TRACE_DEFINED_HERE
4305 astrand 933 #undef TRACE
4306     #undef TRACE_DEFINED_HERE
4307 astrand 930 #endif
4308    
4309    
4310 astrand 931 // These std::swap specializations come courtesy of Mike Crusader.
4311    
4312     //namespace std
4313     //{
4314 astrand 933 // inline void swap(CStdStringA& s1, CStdStringA& s2) throw()
4315     // {
4316     // s1.swap(s2);
4317     // }
4318     // template<>
4319     // inline void swap(CStdStringW& s1, CStdStringW& s2) throw()
4320     // {
4321     // s1.swap(s2);
4322     // }
4323 astrand 931 //}
4324    
4325     // Turn back on any Borland warnings we turned off.
4326    
4327     #ifdef __BORLANDC__
4328 astrand 933 #pragma option pop // Turn back on inline function warnings
4329     // #pragma warn +inl // Turn back on inline function warnings
4330 astrand 931 #endif
4331    
4332 astrand 933 #endif // #ifndef STDSTRING_H

  ViewVC Help
Powered by ViewVC 1.1.26