/[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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

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

  ViewVC Help
Powered by ViewVC 1.1.26