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

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

  ViewVC Help
Powered by ViewVC 1.1.26