/[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 921 - (show annotations)
Thu Jun 30 09:06:43 2005 UTC (18 years, 11 months ago) by astrand
File MIME type: text/plain
File size: 88302 byte(s)
Renamed solution to seamlessrdp.sln. Converted filenames to lowercase.

1 // =============================================================================
2 // FILE: StdString.h
3 // AUTHOR: Joe O'Leary (with outside help noted in comments)
4 // REMARKS:
5 // This header file declares the CStdStr template. This template derives
6 // the Standard C++ Library basic_string<> template and add to it the
7 // the following conveniences:
8 // - The full MFC CString set of functions (including implicit cast)
9 // - writing to/reading from COM IStream interfaces
10 // - Functional objects for use in STL algorithms
11 //
12 // From this template, we intstantiate two classes: CStdStringA and
13 // CStdStringW. The name "CStdString" is just a #define of one of these,
14 // based upone the _UNICODE macro setting
15 //
16 // This header also declares our own version of the MFC/ATL UNICODE-MBCS
17 // conversion macros. Our version looks exactly like the Microsoft's to
18 // facilitate portability.
19 //
20 // NOTE:
21 // If you you use this in an MFC or ATL build, you should include either
22 // afx.h or atlbase.h first, as appropriate.
23 //
24 // PEOPLE WHO HAVE CONTRIBUTED TO THIS CLASS:
25 //
26 // Several people have helped me iron out problems and othewise improve
27 // this class. OK, this is a long list but in my own defense, this code
28 // has undergone two major rewrites. Many of the improvements became
29 // necessary after I rewrote the code as a template. Others helped me
30 // improve the CString facade.
31 //
32 // Anyway, these people are (in chronological order):
33 //
34 // - Pete the Plumber (???)
35 // - Julian Selman
36 // - Chris (of Melbsys)
37 // - Dave Plummer
38 // - John C Sipos
39 // - Chris Sells
40 // - Nigel Nunn
41 // - Fan Xia
42 // - Matthew Williams
43 // - Carl Engman
44 // - Mark Zeren
45 // - Craig Watson
46 // - Rich Zuris
47 // - Karim Ratib
48 // - Chris Conti
49 // - Baptiste Lepilleur
50 // - Greg Pickles
51 // - Jim Cline
52 // - Jeff Kohn
53 // - Todd Heckel
54 // - Ullrich Pollähne
55 // - Joe Vitaterna
56 // - Joe Woodbury
57 // - Aaron (no last name)
58 // - Joldakowski (???)
59 // - Scott Hathaway
60 // - Eric Nitzche
61 // - Pablo Presedo
62 //
63 // REVISION HISTORY
64 // 2001-APR-27 - StreamLoad was calculating the number of BYTES in one
65 // case, not characters. Thanks to Pablo Presedo for this.
66 //
67 // 2001-FEB-23 - Replace() had a bug which caused infinite loops if the
68 // source string was empty. Fixed thanks to Eric Nitzsche.
69 //
70 // 2001-FEB-23 - Scott Hathaway was a huge help in providing me with the
71 // ability to build CStdString on Sun Unix systems. He
72 // sent me detailed build reports about what works and what
73 // does not. If CStdString compiles on your Unix box, you
74 // can thank Scott for it.
75 //
76 // 2000-DEC-29 - Joldakowski noticed one overload of Insert failed to do
77 // range check as CString's does. Now fixed -- thanks!
78 //
79 // 2000-NOV-07 - Aaron pointed out that I was calling static member
80 // functions of char_traits via a temporary. This was not
81 // technically wrong, but it was unnecessary and caused
82 // problems for poor old buggy VC5. Thanks Aaron!
83 //
84 // 2000-JUL-11 - Joe Woodbury noted that the CString::Find docs don't match
85 // what the CString::Find code really ends up doing. I was
86 // trying to match the docs. Now I match the CString code
87 // - Joe also caught me truncating strings for GetBuffer() calls
88 // when the supplied length was less than the current length.
89 //
90 // 2000-MAY-25 - Better support for STLPORT's Standard library distribution
91 // - Got rid of the NSP macro - it interfered with Koenig lookup
92 // - Thanks to Joe Woodbury for catching a TrimLeft() bug that
93 // I introduced in January. Empty strings were not getting
94 // trimmed
95 //
96 // 2000-APR-17 - Thanks to Joe Vitaterna for pointing out that ReverseFind
97 // is supposed to be a const function.
98 //
99 // 2000-MAR-07 - Thanks to Ullrich Pollähne for catching a range bug in one
100 // of the overloads of assign.
101 //
102 // 2000-FEB-01 - You can now use CStdString on the Mac with CodeWarrior!
103 // Thanks to Todd Heckel for helping out with this.
104 //
105 // 2000-JAN-23 - Thanks to Jim Cline for pointing out how I could make the
106 // Trim() function more efficient.
107 // - Thanks to Jeff Kohn for prompting me to find and fix a typo
108 // in one of the addition operators that takes _bstr_t.
109 // - Got rid of the .CPP file - you only need StdString.h now!
110 //
111 // 1999-DEC-22 - Thanks to Greg Pickles for helping me identify a problem
112 // with my implementation of CStdString::FormatV in which
113 // resulting string might not be properly NULL terminated.
114 //
115 // 1999-DEC-06 - Chris Conti pointed yet another basic_string<> assignment
116 // bug that MS has not fixed. CStdString did nothing to fix
117 // it either but it does now! The bug was: create a string
118 // longer than 31 characters, get a pointer to it (via c_str())
119 // and then assign that pointer to the original string object.
120 // The resulting string would be empty. Not with CStdString!
121 //
122 // 1999-OCT-06 - BufferSet was erasing the string even when it was merely
123 // supposed to shrink it. Fixed. Thanks to Chris Conti.
124 // - Some of the Q172398 fixes were not checking for assignment-
125 // to-self. Fixed. Thanks to Baptiste Lepilleur.
126 //
127 // 1999-AUG-20 - Improved Load() function to be more efficient by using
128 // SizeOfResource(). Thanks to Rich Zuris for this.
129 // - Corrected resource ID constructor, again thanks to Rich.
130 // - Fixed a bug that occurred with UNICODE characters above
131 // the first 255 ANSI ones. Thanks to Craig Watson.
132 // - Added missing overloads of TrimLeft() and TrimRight().
133 // Thanks to Karim Ratib for pointing them out
134 //
135 // 1999-JUL-21 - Made all calls to GetBuf() with no args check length first.
136 //
137 // 1999-JUL-10 - Improved MFC/ATL independence of conversion macros
138 // - Added SS_NO_REFCOUNT macro to allow you to disable any
139 // reference-counting your basic_string<> impl. may do.
140 // - Improved ReleaseBuffer() to be as forgiving as CString.
141 // Thanks for Fan Xia for helping me find this and to
142 // Matthew Williams for pointing it out directly.
143 //
144 // 1999-JUL-06 - Thanks to Nigel Nunn for catching a very sneaky bug in
145 // ToLower/ToUpper. They should call GetBuf() instead of
146 // data() in order to ensure the changed string buffer is not
147 // reference-counted (in those implementations that refcount).
148 //
149 // 1999-JUL-01 - Added a true CString facade. Now you can use CStdString as
150 // a drop-in replacement for CString. If you find this useful,
151 // you can thank Chris Sells for finally convincing me to give
152 // in and implement it.
153 // - Changed operators << and >> (for MFC CArchive) to serialize
154 // EXACTLY as CString's do. So now you can send a CString out
155 // to a CArchive and later read it in as a CStdString. I have
156 // no idea why you would want to do this but you can.
157 //
158 // 1999-JUN-21 - Changed the CStdString class into the CStdStr template.
159 // - Fixed FormatV() to correctly decrement the loop counter.
160 // This was harmless bug but a bug nevertheless. Thanks to
161 // Chris (of Melbsys) for pointing it out
162 // - Changed Format() to try a normal stack-based array before
163 // using to _alloca().
164 // - Updated the text conversion macros to properly use code
165 // pages and to fit in better in MFC/ATL builds. In other
166 // words, I copied Microsoft's conversion stuff again.
167 // - Added equivalents of CString::GetBuffer, GetBufferSetLength
168 // - new sscpy() replacement of CStdString::CopyString()
169 // - a Trim() function that combines TrimRight() and TrimLeft().
170 //
171 // 1999-MAR-13 - Corrected the "NotSpace" functional object to use _istpace()
172 // instead of _isspace() Thanks to Dave Plummer for this.
173 //
174 // 1999-FEB-26 - Removed errant line (left over from testing) that #defined
175 // _MFC_VER. Thanks to John C Sipos for noticing this.
176 //
177 // 1999-FEB-03 - Fixed a bug in a rarely-used overload of operator+() that
178 // caused infinite recursion and stack overflow
179 // - Added member functions to simplify the process of
180 // persisting CStdStrings to/from DCOM IStream interfaces
181 // - Added functional objects (e.g. StdStringLessNoCase) that
182 // allow CStdStrings to be used as keys STL map objects with
183 // case-insensitive comparison
184 // - Added array indexing operators (i.e. operator[]). I
185 // originally assumed that these were unnecessary and would be
186 // inherited from basic_string. However, without them, Visual
187 // C++ complains about ambiguous overloads when you try to use
188 // them. Thanks to Julian Selman to pointing this out.
189 //
190 // 1998-FEB-?? - Added overloads of assign() function to completely account
191 // for Q172398 bug. Thanks to "Pete the Plumber" for this
192 //
193 // 1998-FEB-?? - Initial submission
194 //
195 // COPYRIGHT:
196 // 1999 Joseph M. O'Leary. This code is free. Use it anywhere you want.
197 // Rewrite it, restructure it, whatever. Please don't blame me if it makes
198 // your $30 billion dollar satellite explode in orbit. If you redistribute
199 // it in any form, I'd appreciate it if you would leave this notice here.
200 //
201 // If you find any bugs, please let me know:
202 //
203 // jmoleary@earthlink.net
204 // http://home.earthlink.net/~jmoleary
205 // =============================================================================
206
207 // Avoid multiple inclusion the VC++ way,
208 // Turn off browser references
209 // Turn off unavoidable compiler warnings
210
211 #if defined(_MSC_VER) && (_MSC_VER > 1100)
212 #pragma once
213 #pragma component(browser, off, references, "CStdString")
214 #pragma warning (disable : 4290) // C++ Exception Specification ignored
215 #pragma warning (disable : 4127) // Conditional expression is constant
216 #pragma warning (disable : 4097) // typedef name used as synonym for class name
217 #endif
218
219 #ifndef STDSTRING_H
220 #define STDSTRING_H
221
222 // MACRO: SS_NO_REFCOUNT:
223 // turns off reference counting at the assignment level
224 // I define this by default. comment it out if you don't want it.
225
226 #define SS_NO_REFCOUNT
227
228 // In non-Visual C++ and/or non-Win32 builds, we can't use some cool stuff.
229
230 #if !defined(_MSC_VER) || !defined(_WIN32)
231 #define SS_ANSI
232 #endif
233
234 // Avoid legacy code screw up: if _UNICODE is defined, UNICODE must be as well
235
236 #if defined (_UNICODE) && !defined (UNICODE)
237 #define UNICODE
238 #endif
239 #if defined (UNICODE) && !defined (_UNICODE)
240 #define _UNICODE
241 #endif
242
243 // -----------------------------------------------------------------------------
244 // MIN and MAX. The Standard C++ template versions go by so many names (at
245 // at least in the MS implementation) that you never know what's available
246 // -----------------------------------------------------------------------------
247 template<class Type>
248 inline const Type& SSMIN(const Type& arg1, const Type& arg2)
249 {
250 return arg2 < arg1 ? arg2 : arg1;
251 }
252 template<class Type>
253 inline const Type& SSMAX(const Type& arg1, const Type& arg2)
254 {
255 return arg2 > arg1 ? arg2 : arg1;
256 }
257
258 // If they have not #included W32Base.h (part of my W32 utility library) then
259 // we need to define some stuff. Otherwise, this is all defined there.
260
261 #if !defined(W32BASE_H)
262
263 // If they want us to use only standard C++ stuff (no Win32 stuff)
264
265 #ifdef SS_ANSI
266
267 // On non-Win32 platforms, there is no TCHAR.H so define what we need
268
269 #ifndef _WIN32
270
271 typedef const char* PCSTR;
272 typedef char* PSTR;
273 typedef const wchar_t* PCWSTR;
274 typedef wchar_t* PWSTR;
275 #ifdef UNICODE
276 typedef wchar_t TCHAR;
277 #else
278 typedef char TCHAR;
279 #endif
280 typedef wchar_t OLECHAR;
281
282 #else
283
284 #include <TCHAR.H>
285 #include <WTYPES.H>
286 #ifndef STRICT
287 #define STRICT
288 #endif
289
290 #endif // #ifndef _WIN32
291
292
293 // Make sure ASSERT and verify are defined in an ANSI fashion
294
295 #ifndef ASSERT
296 #include <assert.h>
297 #define ASSERT(f) assert((f))
298 #endif
299 #ifndef VERIFY
300 #ifdef _DEBUG
301 #define VERIFY(x) ASSERT((x))
302 #else
303 #define VERIFY(x) x
304 #endif
305 #endif
306
307 #else // #ifdef SS_ANSI
308
309 #include <TCHAR.H>
310 #include <WTYPES.H>
311 #ifndef STRICT
312 #define STRICT
313 #endif
314
315 // Make sure ASSERT and verify are defined
316
317 #ifndef ASSERT
318 #include <crtdbg.h>
319 #define ASSERT(f) _ASSERTE((f))
320 #endif
321 #ifndef VERIFY
322 #ifdef _DEBUG
323 #define VERIFY(x) ASSERT((x))
324 #else
325 #define VERIFY(x) x
326 #endif
327 #endif
328
329 #endif // #ifdef SS_ANSI
330
331 #ifndef UNUSED
332 #define UNUSED(x) x
333 #endif
334
335 #endif // #ifndef W32BASE_H
336
337 // Standard headers needed
338
339 #include <string> // basic_string
340 #include <algorithm> // for_each, etc.
341 #include <functional> // for StdStringLessNoCase, et al
342 #include <locale> // for various facets
343
344 // If this is a recent enough version of VC include comdef.h, so we can write
345 // member functions to deal with COM types & compiler support classes e.g. _bstr_t
346
347 #if defined (_MSC_VER) && (_MSC_VER >= 1100)
348 #include <comdef.h>
349 #define SS_INC_COMDEF // signal that we #included MS comdef.h file
350 #define STDSTRING_INC_COMDEF
351 #define SS_NOTHROW __declspec(nothrow)
352 #else
353 #define SS_NOTHROW
354 #endif
355
356 #ifndef TRACE
357 #define TRACE_DEFINED_HERE
358 #define TRACE
359 #endif
360
361 // Microsoft defines PCSTR, PCWSTR, etc, but no PCTSTR. I hate to use the
362 // versions with the "L" in front of them because that's a leftover from Win 16
363 // days, even though it evaluates to the same thing. Therefore, Define a PCSTR
364 // as an LPCTSTR.
365
366 #if !defined(PCTSTR) && !defined(PCTSTR_DEFINED)
367 typedef const TCHAR* PCTSTR;
368 #define PCTSTR_DEFINED
369 #endif
370
371 #if !defined(PCOLESTR) && !defined(PCOLESTR_DEFINED)
372 typedef const OLECHAR* PCOLESTR;
373 #define PCOLESTR_DEFINED
374 #endif
375
376 #if !defined(POLESTR) && !defined(POLESTR_DEFINED)
377 typedef OLECHAR* POLESTR;
378 #define POLESTR_DEFINED
379 #endif
380
381 #if !defined(PCUSTR) && !defined(PCUSTR_DEFINED)
382 typedef const unsigned char* PCUSTR;
383 typedef unsigned char* PUSTR;
384 #define PCUSTR_DEFINED
385 #endif
386
387 // SS_USE_FACET macro and why we need it:
388 //
389 // Since I'm a good little Standard C++ programmer, I use locales. Thus, I
390 // need to make use of the use_facet<> template function here. Unfortunately,
391 // this need is complicated by the fact the MS' implementation of the Standard
392 // C++ Library has a non-standard version of use_facet that takes more
393 // arguments than the standard dictates. Since I'm trying to write CStdString
394 // to work with any version of the Standard library, this presents a problem.
395 //
396 // The upshot of this is that I can't do 'use_facet' directly. The MS' docs
397 // tell me that I have to use a macro, _USE() instead. Since _USE obviously
398 // won't be available in other implementations, this means that I have to write
399 // my OWN macro -- SS_USE_FACET -- that evaluates either to _USE or to the
400 // standard, use_facet.
401 //
402 // If you are having trouble with the SS_USE_FACET macro, in your implementation
403 // of the Standard C++ Library, you can define your own version of SS_USE_FACET.
404 #ifndef schMSG
405 #define schSTR(x) #x
406 #define schSTR2(x) schSTR(x)
407 #define schMSG(desc) message(__FILE__ "(" schSTR2(__LINE__) "):" #desc)
408 #endif
409
410 #ifndef SS_USE_FACET
411 // STLPort #defines a macro (__STL_NO_EXPLICIT_FUNCTION_TMPL_ARGS) for
412 // all MSVC builds, erroneously in my opinion. It causes problems for
413 // my SS_ANSI builds. In my code, I always comment out that line. You'll
414 // find it in \stlport\config\stl_msvc.h
415 #if defined(__SGI_STL_PORT) && (__SGI_STL_PORT >= 0x400 )
416 #if defined(__STL_NO_EXPLICIT_FUNCTION_TMPL_ARGS) && defined(_MSC_VER)
417 #ifdef SS_ANSI
418 #pragma schMSG(__STL_NO_EXPLICIT_FUNCTION_TMPL_ARGS defined!!)
419 #endif
420 #endif
421 #define SS_USE_FACET(loc, fac) std::use_facet<fac >(loc)
422 #elif defined(_MSC_VER )
423 #define SS_USE_FACET(loc, fac) _USE(loc, fac)
424
425 // ...and
426 #elif defined(_RWSTD_NO_TEMPLATE_ON_RETURN_TYPE)
427 #define SS_USE_FACET(loc, fac) std::use_facet(loc, (fac*)0)
428 #else
429 #define SS_USE_FACET(loc, fac) std::use_facet<fac >(loc)
430 #endif
431 #endif
432
433 // =============================================================================
434 // UNICODE/MBCS conversion macros. Made to work just like the MFC/ATL ones.
435 // =============================================================================
436
437 // First define the conversion helper functions. We define these regardless of
438 // any preprocessor macro settings since their names won't collide.
439
440 #ifdef SS_ANSI // Are we doing things the standard, non-Win32 way?...
441
442 typedef std::codecvt<wchar_t, char, mbstate_t> SSCodeCvt;
443
444 // Not sure if we need all these headers. I believe ANSI says we do.
445
446 #include <stdio.h>
447 #include <stdarg.h>
448 #include <wchar.h>
449 #ifndef va_start
450 #include <varargs.h>
451 #endif
452
453 // StdCodeCvt - made to look like Win32 functions WideCharToMultiByte annd
454 // MultiByteToWideChar but uses locales in SS_ANSI builds
455 inline PWSTR StdCodeCvt(PWSTR pW, PCSTR pA, int nChars,
456 const std::locale& loc=std::locale())
457 {
458 ASSERT(0 != pA);
459 ASSERT(0 != pW);
460 pW[0] = '\0';
461 PCSTR pBadA = 0;
462 PWSTR pBadW = 0;
463 SSCodeCvt::result res = SSCodeCvt::ok;
464 const SSCodeCvt& conv = SS_USE_FACET(loc, SSCodeCvt);
465 SSCodeCvt::state_type st= { 0 };
466 res = conv.in(st,
467 pA, pA + nChars, pBadA,
468 pW, pW + nChars, pBadW);
469 ASSERT(SSCodeCvt::ok == res);
470 return pW;
471 }
472 inline PWSTR StdCodeCvt(PWSTR pW, PCUSTR pA, int nChars,
473 const std::locale& loc=std::locale())
474 {
475 return StdCodeCvt(pW, (PCSTR)pA, nChars, loc);
476 }
477
478 inline PSTR StdCodeCvt(PSTR pA, PCWSTR pW, int nChars,
479 const std::locale& loc=std::locale())
480 {
481 ASSERT(0 != pA);
482 ASSERT(0 != pW);
483 pA[0] = '\0';
484 PSTR pBadA = 0;
485 PCWSTR pBadW = 0;
486 SSCodeCvt::result res = SSCodeCvt::ok;
487 const SSCodeCvt& conv = SS_USE_FACET(loc, SSCodeCvt);
488 SSCodeCvt::state_type st= { 0 };
489 res = conv.out(st,
490 pW, pW + nChars, pBadW,
491 pA, pA + nChars, pBadA);
492 ASSERT(SSCodeCvt::ok == res);
493 return pA;
494 }
495 inline PUSTR StdCodeCvt(PUSTR pA, PCWSTR pW, int nChars,
496 const std::locale& loc=std::locale())
497 {
498 return (PUSTR)StdCodeCvt((PSTR)pA, pW, nChars, loc);
499 }
500
501 #else // ...or are we doing things assuming win32 and Visual C++?
502
503 #include <malloc.h> // needed for _alloca
504
505 inline PWSTR StdCodeCvt(PWSTR pW, PCSTR pA, int nChars, UINT acp=CP_ACP)
506 {
507 ASSERT(0 != pA);
508 ASSERT(0 != pW);
509 pW[0] = '\0';
510 MultiByteToWideChar(acp, 0, pA, -1, pW, nChars);
511 return pW;
512 }
513 inline PWSTR StdCodeCvt(PWSTR pW, PCUSTR pA, int nChars, UINT acp=CP_ACP)
514 {
515 return StdCodeCvt(pW, (PCSTR)pA, nChars, acp);
516 }
517
518 inline PSTR StdCodeCvt(PSTR pA, PCWSTR pW, int nChars, UINT acp=CP_ACP)
519 {
520 ASSERT(0 != pA);
521 ASSERT(0 != pW);
522 pA[0] = '\0';
523 WideCharToMultiByte(acp, 0, pW, -1, pA, nChars, 0, 0);
524 return pA;
525 }
526 inline PUSTR StdCodeCvt(PUSTR pA, PCWSTR pW, int nChars, UINT acp=CP_ACP)
527 {
528 return (PUSTR)StdCodeCvt((PSTR)pA, pW, nChars, acp);
529 }
530
531 // Define our conversion macros to look exactly like Microsoft's to
532 // facilitate using this stuff both with and without MFC/ATL
533
534 #ifdef _CONVERSION_USES_THREAD_LOCALE
535 #ifndef _DEBUG
536 #define SSCVT int _cvt; _cvt; UINT _acp=GetACP(); \
537 _acp; PCWSTR _pw; _pw; PCSTR _pa; _pa
538 #else
539 #define SSCVT int _cvt = 0; _cvt; UINT _acp=GetACP();\
540 _acp; PCWSTR _pw=0; _pw; PCSTR _pa=0; _pa
541 #endif
542 #else
543 #ifndef _DEBUG
544 #define SSCVT int _cvt; _cvt; UINT _acp=CP_ACP; _acp;\
545 PCWSTR _pw; _pw; PCSTR _pa; _pa
546 #else
547 #define SSCVT int _cvt = 0; _cvt; UINT _acp=CP_ACP; \
548 _acp; PCWSTR _pw=0; _pw; PCSTR _pa=0; _pa
549 #endif
550 #endif
551
552 #ifdef _CONVERSION_USES_THREAD_LOCALE
553 #define SSA2W(pa) (\
554 ((_pa = pa) == 0) ? 0 : (\
555 _cvt = (strlen(_pa)+1),\
556 StdCodeCvt((PWSTR) _alloca(_cvt*2), _pa, _cvt, _acp)))
557 #define SSW2A(pw) (\
558 ((_pw = pw) == 0) ? 0 : (\
559 _cvt = (wcslen(_pw)+1)*2,\
560 StdW2AHelper((LPSTR) _alloca(_cvt), _pw, _cvt, _acp)))
561 #else
562 #define SSA2W(pa) (\
563 ((_pa = pa) == 0) ? 0 : (\
564 _cvt = (strlen(_pa)+1),\
565 StdCodeCvt((PWSTR) _alloca(_cvt*2), _pa, _cvt)))
566 #define SSW2A(pw) (\
567 ((_pw = pw) == 0) ? 0 : (\
568 _cvt = (wcslen(_pw)+1)*2,\
569 StdCodeCvt((LPSTR) _alloca(_cvt), _pw, _cvt)))
570 #endif
571
572 #define SSA2CW(pa) ((PCWSTR)SSA2W((pa)))
573 #define SSW2CA(pw) ((PCSTR)SSW2A((pw)))
574
575 #ifdef UNICODE
576 #define SST2A SSW2A
577 #define SSA2T SSA2W
578 #define SST2CA SSW2CA
579 #define SSA2CT SSA2CW
580 inline PWSTR SST2W(PTSTR p) { return p; }
581 inline PTSTR SSW2T(PWSTR p) { return p; }
582 inline PCWSTR SST2CW(PCTSTR p) { return p; }
583 inline PCTSTR SSW2CT(PCWSTR p) { return p; }
584 #else
585 #define SST2W SSA2W
586 #define SSW2T SSW2A
587 #define SST2CW SSA2CW
588 #define SSW2CT SSW2CA
589 inline PSTR SST2A(PTSTR p) { return p; }
590 inline PTSTR SSA2T(PSTR p) { return p; }
591 inline PCSTR SST2CA(PCTSTR p) { return p; }
592 inline PCTSTR SSA2CT(PCSTR p) { return p; }
593 #endif // #ifdef UNICODE
594
595 #if defined(UNICODE)
596 // in these cases the default (TCHAR) is the same as OLECHAR
597 inline PCOLESTR SST2COLE(PCTSTR p) { return p; }
598 inline PCTSTR SSOLE2CT(PCOLESTR p) { return p; }
599 inline POLESTR SST2OLE(PTSTR p) { return p; }
600 inline PTSTR SSOLE2T(POLESTR p) { return p; }
601 #elif defined(OLE2ANSI)
602 // in these cases the default (TCHAR) is the same as OLECHAR
603 inline PCOLESTR SST2COLE(PCTSTR p) { return p; }
604 inline PCTSTR SSOLE2CT(PCOLESTR p) { return p; }
605 inline POLESTR SST2OLE(PTSTR p) { return p; }
606 inline PTSTR SSOLE2T(POLESTR p) { return p; }
607 #else
608 //CharNextW doesn't work on Win95 so we use this
609 #define SST2COLE(pa) SSA2CW((pa))
610 #define SST2OLE(pa) SSA2W((pa))
611 #define SSOLE2CT(po) SSW2CA((po))
612 #define SSOLE2T(po) SSW2A((po))
613 #endif
614
615 #ifdef OLE2ANSI
616 #define SSW2OLE SSW2A
617 #define SSOLE2W SSA2W
618 #define SSW2COLE SSW2CA
619 #define SSOLE2CW SSA2CW
620 inline POLESTR SSA2OLE(PSTR p) { return p; }
621 inline PSTR SSOLE2A(POLESTR p) { return p; }
622 inline PCOLESTR SSA2COLE(PCSTR p) { return p; }
623 inline PCSTR SSOLE2CA(PCOLESTR p){ return p; }
624 #else
625 #define SSA2OLE SSA2W
626 #define SSOLE2A SSW2A
627 #define SSA2COLE SSA2CW
628 #define SSOLE2CA SSW2CA
629 inline POLESTR SSW2OLE(PWSTR p) { return p; }
630 inline PWSTR SSOLE2W(POLESTR p) { return p; }
631 inline PCOLESTR SSW2COLE(PCWSTR p) { return p; }
632 inline PCWSTR SSOLE2CW(PCOLESTR p){ return p; }
633 #endif
634
635 // Above we've defined macros that look like MS' but all have
636 // an 'SS' prefix. Now we need the real macros. We'll either
637 // get them from the macros above or from MFC/ATL. If
638 // SS_NO_CONVERSION is #defined, we'll forgo them
639
640 #ifndef SS_NO_CONVERSION
641
642 #if defined (USES_CONVERSION)
643
644 #define _NO_STDCONVERSION // just to be consistent
645
646 #else
647
648 #ifdef _MFC_VER
649
650 #include <afxconv.h>
651 #define _NO_STDCONVERSION // just to be consistent
652
653 #else
654
655 #define USES_CONVERSION SSCVT
656 #define A2CW SSA2CW
657 #define W2CA SSW2CA
658 #define T2A SST2A
659 #define A2T SSA2T
660 #define T2W SST2W
661 #define W2T SSW2T
662 #define T2CA SST2CA
663 #define A2CT SSA2CT
664 #define T2CW SST2CW
665 #define W2CT SSW2CT
666 #define ocslen sslen
667 #define ocscpy sscpy
668 #define T2COLE SST2COLE
669 #define OLE2CT SSOLE2CT
670 #define T2OLE SST2COLE
671 #define OLE2T SSOLE2CT
672 #define A2OLE SSA2OLE
673 #define OLE2A SSOLE2A
674 #define W2OLE SSW2OLE
675 #define OLE2W SSOLE2W
676 #define A2COLE SSA2COLE
677 #define OLE2CA SSOLE2CA
678 #define W2COLE SSW2COLE
679 #define OLE2CW SSOLE2CW
680
681 #endif // #ifdef _MFC_VER
682 #endif // #ifndef USES_CONVERSION
683 #endif // #ifndef SS_NO_CONVERSION
684
685 // Define ostring - generic name for std::basic_string<OLECHAR>
686
687 #if !defined(ostring) && !defined(OSTRING_DEFINED)
688 typedef std::basic_string<OLECHAR> ostring;
689 #define OSTRING_DEFINED
690 #endif
691
692 #endif // #ifndef SS_ANSI
693
694 // StdCodeCvt when there's no conversion to be done
695 inline PSTR StdCodeCvt(PSTR pDst, PCSTR pSrc, int nChars)
696 {
697 pDst[0] = '\0';
698 std::char_traits<char>::copy(pDst, pSrc, nChars);
699 if ( nChars > 0 )
700 pDst[nChars] = '\0';
701
702 return pDst;
703 }
704 inline PSTR StdCodeCvt(PSTR pDst, PCUSTR pSrc, int nChars)
705 {
706 return StdCodeCvt(pDst, (PCSTR)pSrc, nChars);
707 }
708 inline PUSTR StdCodeCvt(PUSTR pDst, PCSTR pSrc, int nChars)
709 {
710 return (PUSTR)StdCodeCvt((PSTR)pDst, pSrc, nChars);
711 }
712
713 inline PWSTR StdCodeCvt(PWSTR pDst, PCWSTR pSrc, int nChars)
714 {
715 pDst[0] = '\0';
716 std::char_traits<wchar_t>::copy(pDst, pSrc, nChars);
717 if ( nChars > 0 )
718 pDst[nChars] = '\0';
719
720 return pDst;
721 }
722
723
724 // Define tstring -- generic name for std::basic_string<TCHAR>
725
726 #if !defined(tstring) && !defined(TSTRING_DEFINED)
727 typedef std::basic_string<TCHAR> tstring;
728 #define TSTRING_DEFINED
729 #endif
730
731 // a very shorthand way of applying the fix for KB problem Q172398
732 // (basic_string assignment bug)
733
734 #if defined ( _MSC_VER ) && ( _MSC_VER < 1200 )
735 #define Q172398(x) (x).erase()
736 #else
737 #define Q172398(x)
738 #endif
739
740 // =============================================================================
741 // INLINE FUNCTIONS ON WHICH CSTDSTRING RELIES
742 //
743 // Usually for generic text mapping, we rely on preprocessor macro definitions
744 // to map to string functions. However the CStdStr<> template cannot use
745 // macro-based generic text mappings because its character types do not get
746 // resolved until template processing which comes AFTER macro processing. In
747 // other words, UNICODE is of little help to us in the CStdStr template
748 //
749 // Therefore, to keep the CStdStr declaration simple, we have these inline
750 // functions. The template calls them often. Since they are inline (and NOT
751 // exported when this is built as a DLL), they will probably be resolved away
752 // to nothing.
753 //
754 // Without these functions, the CStdStr<> template would probably have to broken
755 // out into two, almost identical classes. Either that or it would be a huge,
756 // convoluted mess, with tons of "if" statements all over the place checking the
757 // size of template parameter CT.
758 //
759 // In several cases, you will see two versions of each function. One version is
760 // the more portable, standard way of doing things, while the other is the
761 // non-standard, but often significantly faster Visual C++ way.
762 // =============================================================================
763
764 // If they defined SS_NO_REFCOUNT, then we must convert all assignments
765
766 #ifdef SS_NO_REFCOUNT
767 #define SSREF(x) (x).c_str()
768 #else
769 #define SSREF(x) (x)
770 #endif
771
772 // -----------------------------------------------------------------------------
773 // sslen: strlen/wcslen wrappers
774 // -----------------------------------------------------------------------------
775 template<typename CT> inline int sslen(const CT* pT)
776 {
777 return 0 == pT ? 0 : std::char_traits<CT>::length(pT);
778 }
779 inline SS_NOTHROW int sslen(const std::string& s)
780 {
781 return s.length();
782 }
783 inline SS_NOTHROW int sslen(const std::wstring& s)
784 {
785 return s.length();
786 }
787
788
789 // -----------------------------------------------------------------------------
790 // ssasn: assignment functions -- assign "sSrc" to "sDst"
791 // -----------------------------------------------------------------------------
792 typedef std::string::size_type SS_SIZETYPE; // just for shorthand, really
793 typedef std::string::pointer SS_PTRTYPE;
794 typedef std::wstring::size_type SW_SIZETYPE;
795 typedef std::wstring::pointer SW_PTRTYPE;
796
797 inline void ssasn(std::string& sDst, const std::string& sSrc)
798 {
799 if ( sDst.c_str() != sSrc.c_str() )
800 {
801 sDst.erase();
802 sDst.assign(SSREF(sSrc));
803 }
804 }
805 inline void ssasn(std::string& sDst, PCSTR pA)
806 {
807 // Watch out for NULLs, as always.
808
809 if ( 0 == pA )
810 {
811 sDst.erase();
812 }
813
814 // If pA actually points to part of sDst, we must NOT erase(), but
815 // rather take a substring
816
817 else if ( pA >= sDst.c_str() && pA <= sDst.c_str() + sDst.size() )
818 {
819 sDst =sDst.substr(static_cast<SS_SIZETYPE>(pA-sDst.c_str()));
820 }
821
822 // Otherwise (most cases) apply the assignment bug fix, if applicable
823 // and do the assignment
824
825 else
826 {
827 Q172398(sDst);
828 sDst.assign(pA);
829 }
830 }
831 inline void ssasn(std::string& sDst, const std::wstring& sSrc)
832 {
833 #ifdef SS_ANSI
834 int nLen = sSrc.size();
835 sDst.resize(0);
836 sDst.resize(nLen);
837 StdCodeCvt(const_cast<SS_PTRTYPE>(sDst.data()), sSrc.c_str(), nLen);
838 #else
839 SSCVT;
840 sDst.assign(SSW2CA(sSrc.c_str()));
841 #endif
842 }
843 inline void ssasn(std::string& sDst, PCWSTR pW)
844 {
845 #ifdef SS_ANSI
846 int nLen = sslen(pW);
847 sDst.resize(0);
848 sDst.resize(nLen);
849 StdCodeCvt(const_cast<SS_PTRTYPE>(sDst.data()), pW, nLen);
850 #else
851 SSCVT;
852 sDst.assign(pW ? SSW2CA(pW) : "");
853 #endif
854 }
855 inline void ssasn(std::string& sDst, const int nNull)
856 {
857 UNUSED(nNull);
858 ASSERT(nNull==0);
859 sDst.assign("");
860 }
861 inline void ssasn(std::wstring& sDst, const std::wstring& sSrc)
862 {
863 if ( sDst.c_str() != sSrc.c_str() )
864 {
865 sDst.erase();
866 sDst.assign(SSREF(sSrc));
867 }
868 }
869 inline void ssasn(std::wstring& sDst, PCWSTR pW)
870 {
871 // Watch out for NULLs, as always.
872
873 if ( 0 == pW )
874 {
875 sDst.erase();
876 }
877
878 // If pW actually points to part of sDst, we must NOT erase(), but
879 // rather take a substring
880
881 else if ( pW >= sDst.c_str() && pW <= sDst.c_str() + sDst.size() )
882 {
883 sDst = sDst.substr(static_cast<SW_SIZETYPE>(pW-sDst.c_str()));
884 }
885
886 // Otherwise (most cases) apply the assignment bug fix, if applicable
887 // and do the assignment
888
889 else
890 {
891 Q172398(sDst);
892 sDst.assign(pW);
893 }
894 }
895 #undef StrSizeType
896 inline void ssasn(std::wstring& sDst, const std::string& sSrc)
897 {
898 #ifdef SS_ANSI
899 int nLen = sSrc.size();
900 sDst.resize(0);
901 sDst.resize(nLen);
902 StdCodeCvt(const_cast<SW_PTRTYPE>(sDst.data()), sSrc.c_str(), nLen);
903 #else
904 SSCVT;
905 sDst.assign(SSA2CW(sSrc.c_str()));
906 #endif
907 }
908 inline void ssasn(std::wstring& sDst, PCSTR pA)
909 {
910 #ifdef SS_ANSI
911 int nLen = sslen(pA);
912 sDst.resize(0);
913 sDst.resize(nLen);
914 StdCodeCvt(const_cast<SW_PTRTYPE>(sDst.data()), pA, nLen);
915 #else
916 SSCVT;
917 sDst.assign(pA ? SSA2CW(pA) : L"");
918 #endif
919 }
920 inline void ssasn(std::wstring& sDst, const int nNull)
921 {
922 UNUSED(nNull);
923 ASSERT(nNull==0);
924 sDst.assign(L"");
925 }
926
927
928 // -----------------------------------------------------------------------------
929 // ssadd: string object concatenation -- add second argument to first
930 // -----------------------------------------------------------------------------
931 inline void ssadd(std::string& sDst, const std::wstring& sSrc)
932 {
933 #ifdef SS_ANSI
934 int nLen = sSrc.size();
935 sDst.resize(sDst.size() + nLen);
936 StdCodeCvt(const_cast<SS_PTRTYPE>(sDst.data()+nLen), sSrc.c_str(), nLen);
937 #else
938 SSCVT;
939 sDst.append(SSW2CA(sSrc.c_str()));
940 #endif
941 }
942 inline void ssadd(std::string& sDst, const std::string& sSrc)
943 {
944 sDst.append(sSrc.c_str());
945 }
946 inline void ssadd(std::string& sDst, PCWSTR pW)
947 {
948 #ifdef SS_ANSI
949 int nLen = sslen(pW);
950 sDst.resize(sDst.size() + nLen);
951 StdCodeCvt(const_cast<SS_PTRTYPE>(sDst.data()+nLen), pW, nLen);
952 #else
953 SSCVT;
954 if ( 0 != pW )
955 sDst.append(SSW2CA(pW));
956 #endif
957 }
958 inline void ssadd(std::string& sDst, PCSTR pA)
959 {
960 if ( pA )
961 sDst.append(pA);
962 }
963 inline void ssadd(std::wstring& sDst, const std::wstring& sSrc)
964 {
965 sDst.append(sSrc.c_str());
966 }
967 inline void ssadd(std::wstring& sDst, const std::string& sSrc)
968 {
969 #ifdef SS_ANSI
970 int nLen = sSrc.size();
971 sDst.resize(sDst.size() + nLen);
972 StdCodeCvt(const_cast<SW_PTRTYPE>(sDst.data()+nLen), sSrc.c_str(), nLen);
973 #else
974 SSCVT;
975 sDst.append(SSA2CW(sSrc.c_str()));
976 #endif
977 }
978 inline void ssadd(std::wstring& sDst, PCSTR pA)
979 {
980 #ifdef SS_ANSI
981 int nLen = sslen(pA);
982 sDst.resize(sDst.size() + nLen);
983 StdCodeCvt(const_cast<SW_PTRTYPE>(sDst.data()+nLen), pA, nLen);
984 #else
985 SSCVT;
986 if ( 0 != pA )
987 sDst.append(SSA2CW(pA));
988 #endif
989 }
990 inline void ssadd(std::wstring& sDst, PCWSTR pW)
991 {
992 if ( pW )
993 sDst.append(pW);
994 }
995
996
997 // -----------------------------------------------------------------------------
998 // ssicmp: comparison (case insensitive )
999 // -----------------------------------------------------------------------------
1000 #ifdef SS_ANSI
1001 template<typename CT>
1002 inline int ssicmp(const CT* pA1, const CT* pA2)
1003 {
1004 std::locale loc;
1005 const std::ctype<CT>& ct = SS_USE_FACET(loc, std::ctype<CT>);
1006 CT f;
1007 CT l;
1008
1009 do
1010 {
1011 f = ct.tolower(*(pA1++));
1012 l = ct.tolower(*(pA2++));
1013 } while ( (f) && (f == l) );
1014
1015 return (int)(f - l);
1016 }
1017 #else
1018 #ifdef _MBCS
1019 inline long sscmp(PCSTR pA1, PCSTR pA2)
1020 {
1021 return _mbscmp((PCUSTR)pA1, (PCUSTR)pA2);
1022 }
1023 inline long ssicmp(PCSTR pA1, PCSTR pA2)
1024 {
1025 return _mbsicmp((PCUSTR)pA1, (PCUSTR)pA2);
1026 }
1027 #else
1028 inline long sscmp(PCSTR pA1, PCSTR pA2)
1029 {
1030 return strcmp(pA1, pA2);
1031 }
1032 inline long ssicmp(PCSTR pA1, PCSTR pA2)
1033 {
1034 return _stricmp(pA1, pA2);
1035 }
1036 #endif
1037 inline long sscmp(PCWSTR pW1, PCWSTR pW2)
1038 {
1039 return wcscmp(pW1, pW2);
1040 }
1041 inline long ssicmp(PCWSTR pW1, PCWSTR pW2)
1042 {
1043 return _wcsicmp(pW1, pW2);
1044 }
1045 #endif
1046
1047 // -----------------------------------------------------------------------------
1048 // ssupr/sslwr: Uppercase/Lowercase conversion functions
1049 // -----------------------------------------------------------------------------
1050 #ifdef SS_ANSI
1051 template<typename CT>
1052 inline void sslwr(CT* pT, size_t nLen)
1053 {
1054 SS_USE_FACET(std::locale(), std::ctype<CT>).tolower(pT, pT+nLen);
1055 }
1056 template<typename CT>
1057 inline void ssupr(CT* pT, size_t nLen)
1058 {
1059 SS_USE_FACET(std::locale(), std::ctype<CT>).toupper(pT, pT+nLen);
1060 }
1061 #else // #else we must be on Win32
1062 #ifdef _MBCS
1063 inline void ssupr(PSTR pA, size_t /*nLen*/)
1064 {
1065 _mbsupr((PUSTR)pA);
1066 }
1067 inline void sslwr(PSTR pA, size_t /*nLen*/)
1068 {
1069 _mbslwr((PUSTR)pA);
1070 }
1071 #else
1072 inline void ssupr(PSTR pA, size_t /*nLen*/)
1073 {
1074 _strupr(pA);
1075 }
1076 inline void sslwr(PSTR pA, size_t /*nLen*/)
1077 {
1078 _strlwr(pA);
1079 }
1080 #endif
1081 inline void ssupr(PWSTR pW, size_t /*nLen*/)
1082 {
1083 _wcsupr(pW);
1084 }
1085 inline void sslwr(PWSTR pW, size_t /*nLen*/)
1086 {
1087 _wcslwr(pW);
1088 }
1089 #endif // #ifdef SS_ANSI
1090
1091 // -----------------------------------------------------------------------------
1092 // vsprintf/vswprintf or _vsnprintf/_vsnwprintf equivalents. In standard
1093 // builds we can't use _vsnprintf/_vsnwsprintf because they're MS extensions.
1094 // -----------------------------------------------------------------------------
1095 #ifdef SS_ANSI
1096 inline int ssvsprintf(PSTR pA, size_t /*nCount*/, PCSTR pFmtA, va_list vl)
1097 {
1098 return vsprintf(pA, pFmtA, vl);
1099 }
1100 inline int ssvsprintf(PWSTR pW, size_t nCount, PCWSTR pFmtW, va_list vl)
1101 {
1102 // JMO: It is beginning to seem like Microsoft Visual C++ is the only
1103 // CRT distribution whose version of vswprintf takes THREE arguments.
1104 // All others seem to take FOUR arguments. Therefore instead of
1105 // checking for every possible distro here, I'll assume that unless
1106 // I am running with Microsoft's CRT, then vswprintf takes four
1107 // arguments. If you get a compilation error here, then you can just
1108 // change this code to call the three-argument version.
1109 // #if !defined(__MWERKS__) && !defined(__SUNPRO_CC_COMPAT) && !defined(__SUNPRO_CC)
1110 #ifndef _MSC_VER
1111 return vswprintf(pW, nCount, pFmtW, vl);
1112 #else
1113 nCount;
1114 return vswprintf(pW, pFmtW, vl);
1115 #endif
1116 }
1117 #else
1118 inline int ssnprintf(PSTR pA, size_t nCount, PCSTR pFmtA, va_list vl)
1119 {
1120 return _vsnprintf(pA, nCount, pFmtA, vl);
1121 }
1122 inline int ssnprintf(PWSTR pW, size_t nCount, PCWSTR pFmtW, va_list vl)
1123 {
1124 return _vsnwprintf(pW, nCount, pFmtW, vl);
1125 }
1126 #endif
1127
1128
1129 // -----------------------------------------------------------------------------
1130 // ssload: Type safe, overloaded ::LoadString wrappers
1131 // There is no equivalent of these in non-Win32-specific builds. However, I'm
1132 // thinking that with the message facet, there might eventually be one
1133 // -----------------------------------------------------------------------------
1134 #ifdef SS_ANSI
1135 #else
1136 inline int ssload(HMODULE hInst, UINT uId, PSTR pBuf, int nMax)
1137 {
1138 return ::LoadStringA(hInst, uId, pBuf, nMax);
1139 }
1140 inline int ssload(HMODULE hInst, UINT uId, PWSTR pBuf, int nMax)
1141 {
1142 return ::LoadStringW(hInst, uId, pBuf, nMax);
1143 }
1144 #endif
1145
1146
1147 // -----------------------------------------------------------------------------
1148 // sscoll/ssicoll: Collation wrappers
1149 // -----------------------------------------------------------------------------
1150 #ifdef SS_ANSI
1151 template <typename CT>
1152 inline int sscoll(const CT* sz1, int nLen1, const CT* sz2, int nLen2)
1153 {
1154 const std::collate<CT>& coll =
1155 SS_USE_FACET(std::locale(), std::collate<CT>);
1156 return coll.compare(sz1, sz1+nLen1, sz2, sz2+nLen2);
1157 }
1158 template <typename CT>
1159 inline int ssicoll(const CT* sz1, int nLen1, const CT* sz2, int nLen2)
1160 {
1161 const std::locale loc;
1162 const std::collate<CT>& coll = SS_USE_FACET(loc, std::collate<CT>);
1163
1164 // Some implementations seem to have trouble using the collate<>
1165 // facet typedefs so we'll just default to basic_string and hope
1166 // that's what the collate facet uses (which it generally should)
1167
1168 // std::collate<CT>::string_type s1(sz1);
1169 // std::collate<CT>::string_type s2(sz2);
1170 std::basic_string<CT> s1(sz1);
1171 std::basic_string<CT> s2(sz2);
1172
1173 sslwr(const_cast<CT*>(s1.c_str()), nLen1);
1174 sslwr(const_cast<CT*>(s2.c_str()), nLen2);
1175 return coll.compare(s1.c_str(), s1.c_str()+nLen1,
1176 s2.c_str(), s2.c_str()+nLen2);
1177 }
1178 #else
1179 #ifdef _MBCS
1180 inline int sscoll(PCSTR sz1, int /*nLen1*/, PCSTR sz2, int /*nLen2*/)
1181 {
1182 return _mbscoll((PCUSTR)sz1, (PCUSTR)sz2);
1183 }
1184 inline int ssicoll(PCSTR sz1, int /*nLen1*/, PCSTR sz2, int /*nLen2*/)
1185 {
1186 return _mbsicoll((PCUSTR)sz1, (PCUSTR)sz2);
1187 }
1188 #else
1189 inline int sscoll(PCSTR sz1, int /*nLen1*/, PCSTR sz2, int /*nLen2*/)
1190 {
1191 return strcoll(sz1, sz2);
1192 }
1193 inline int ssicoll(PCSTR sz1, int /*nLen1*/, PCSTR sz2, int /*nLen2*/)
1194 {
1195 return _stricoll(sz1, sz2);
1196 }
1197 #endif
1198 inline int sscoll(PCWSTR sz1, int /*nLen1*/, PCWSTR sz2, int /*nLen2*/)
1199 {
1200 return wcscoll(sz1, sz2);
1201 }
1202 inline int ssicoll(PCWSTR sz1, int /*nLen1*/, PCWSTR sz2, int /*nLen2*/)
1203 {
1204 return _wcsicoll(sz1, sz2);
1205 }
1206 #endif
1207
1208
1209 // -----------------------------------------------------------------------------
1210 // ssfmtmsg: FormatMessage equivalents. Needed because I added a CString facade
1211 // Again -- no equivalent of these on non-Win32 builds but their might one day
1212 // be one if the message facet gets implemented
1213 // -----------------------------------------------------------------------------
1214 #ifdef SS_ANSI
1215 #else
1216 inline DWORD ssfmtmsg(DWORD dwFlags, LPCVOID pSrc, DWORD dwMsgId,
1217 DWORD dwLangId, PSTR pBuf, DWORD nSize,
1218 va_list* vlArgs)
1219 {
1220 return FormatMessageA(dwFlags, pSrc, dwMsgId, dwLangId,
1221 pBuf, nSize,vlArgs);
1222 }
1223 inline DWORD ssfmtmsg(DWORD dwFlags, LPCVOID pSrc, DWORD dwMsgId,
1224 DWORD dwLangId, PWSTR pBuf, DWORD nSize,
1225 va_list* vlArgs)
1226 {
1227 return FormatMessageW(dwFlags, pSrc, dwMsgId, dwLangId,
1228 pBuf, nSize,vlArgs);
1229 }
1230 #endif
1231
1232
1233
1234 // FUNCTION: sscpy. Copies up to 'nMax' characters from pSrc to pDst.
1235 // -----------------------------------------------------------------------------
1236 // FUNCTION: sscpy
1237 // inline int sscpy(PSTR pDst, PCSTR pSrc, int nMax=-1);
1238 // inline int sscpy(PUSTR pDst, PCSTR pSrc, int nMax=-1)
1239 // inline int sscpy(PSTR pDst, PCWSTR pSrc, int nMax=-1);
1240 // inline int sscpy(PWSTR pDst, PCWSTR pSrc, int nMax=-1);
1241 // inline int sscpy(PWSTR pDst, PCSTR pSrc, int nMax=-1);
1242 //
1243 // DESCRIPTION:
1244 // This function is very much (but not exactly) like strcpy. These
1245 // overloads simplify copying one C-style string into another by allowing
1246 // the caller to specify two different types of strings if necessary.
1247 //
1248 // The strings must NOT overlap
1249 //
1250 // "Character" is expressed in terms of the destination string, not
1251 // the source. If no 'nMax' argument is supplied, then the number of
1252 // characters copied will be sslen(pSrc). A NULL terminator will
1253 // also be added so pDst must actually be big enough to hold nMax+1
1254 // characters. The return value is the number of characters copied,
1255 // not including the NULL terminator.
1256 //
1257 // PARAMETERS:
1258 // pSrc - the string to be copied FROM. May be a char based string, an
1259 // MBCS string (in Win32 builds) or a wide string (wchar_t).
1260 // pSrc - the string to be copied TO. Also may be either MBCS or wide
1261 // nMax - the maximum number of characters to be copied into szDest. Note
1262 // that this is expressed in whatever a "character" means to pDst.
1263 // If pDst is a wchar_t type string than this will be the maximum
1264 // number of wchar_ts that my be copied. The pDst string must be
1265 // large enough to hold least nMaxChars+1 characters.
1266 // If the caller supplies no argument for nMax this is a signal to
1267 // the routine to copy all the characters in pSrc, regardless of
1268 // how long it is.
1269 //
1270 // RETURN VALUE: none
1271 // -----------------------------------------------------------------------------
1272 template<typename CT1, typename CT2>
1273 inline int sscpycvt(CT1* pDst, const CT2* pSrc, int nChars)
1274 {
1275 StdCodeCvt(pDst, pSrc, nChars);
1276 pDst[SSMAX(nChars, 0)] = '\0';
1277 return nChars;
1278 }
1279
1280 template<typename CT1, typename CT2>
1281 inline int sscpy(CT1* pDst, const CT2* pSrc, int nMax, int nLen)
1282 {
1283 return sscpycvt(pDst, pSrc, SSMIN(nMax, nLen));
1284 }
1285 template<typename CT1, typename CT2>
1286 inline int sscpy(CT1* pDst, const CT2* pSrc, int nMax)
1287 {
1288 return sscpycvt(pDst, pSrc, SSMIN(nMax, sslen(pSrc)));
1289 }
1290 template<typename CT1, typename CT2>
1291 inline int sscpy(CT1* pDst, const CT2* pSrc)
1292 {
1293 return sscpycvt(pDst, pSrc, sslen(pSrc));
1294 }
1295 template<typename CT1, typename CT2>
1296 inline int sscpy(CT1* pDst, const std::basic_string<CT2>& sSrc, int nMax)
1297 {
1298 return sscpycvt(pDst, sSrc.c_str(), SSMIN(nMax, (int)sSrc.length()));
1299 }
1300 template<typename CT1, typename CT2>
1301 inline int sscpy(CT1* pDst, const std::basic_string<CT2>& sSrc)
1302 {
1303 return sscpycvt(pDst, sSrc.c_str(), (int)sSrc.length());
1304 }
1305
1306 #ifdef SS_INC_COMDEF
1307 template<typename CT1>
1308 inline int sscpy(CT1* pDst, const _bstr_t& bs, int nMax)
1309 {
1310 return sscpycvt(pDst, static_cast<PCOLESTR>(bs), SSMIN(nMax, (int)bs.length()));
1311 }
1312 template<typename CT1>
1313 inline int sscpy(CT1* pDst, const _bstr_t& bs)
1314 {
1315 return sscpy(pDst, bs, bs.length());
1316 }
1317 #endif
1318
1319
1320 // -----------------------------------------------------------------------------
1321 // Functional objects for changing case. They also let you pass locales
1322 // -----------------------------------------------------------------------------
1323
1324 #ifdef SS_ANSI
1325 template<typename CT>
1326 struct SSToUpper : public std::binary_function<CT, std::locale, CT>
1327 {
1328 inline CT operator()(const CT& t, const std::locale& loc) const
1329 {
1330 return std::toupper<CT>(t, loc);
1331 }
1332 };
1333 template<typename CT>
1334 struct SSToLower : public std::binary_function<CT, std::locale, CT>
1335 {
1336 inline CT operator()(const CT& t, const std::locale& loc) const
1337 {
1338 return std::tolower<CT>(t, loc);
1339 }
1340 };
1341 #endif
1342
1343 // This struct is used for TrimRight() and TrimLeft() function implementations.
1344 //template<typename CT>
1345 //struct NotSpace : public std::unary_function<CT, bool>
1346 //{
1347 // const std::locale& loc;
1348 // inline NotSpace(const std::locale& locArg) : loc(locArg) {}
1349 // inline bool operator() (CT t) { return !std::isspace(t, loc); }
1350 //};
1351 template<typename CT>
1352 struct NotSpace : public std::unary_function<CT, bool>
1353 {
1354 const std::locale& loc;
1355 NotSpace(const std::locale& locArg) : loc(locArg) {}
1356
1357 // DINKUMWARE BUG:
1358 // Note -- using std::isspace in a COM DLL gives us access violations
1359 // because it causes the dynamic addition of a function to be called
1360 // when the library shuts down. Unfortunately the list is maintained
1361 // in DLL memory but the function is in static memory. So the COM DLL
1362 // goes away along with the function that was supposed to be called,
1363 // and then later when the DLL CRT shuts down it unloads the list and
1364 // tries to call the long-gone function.
1365 // This is DinkumWare's implementation problem. Until then, we will
1366 // use good old isspace and iswspace from the CRT unless they
1367 // specify SS_ANSI
1368 #ifdef SS_ANSI
1369 bool operator() (CT t) const { return !std::isspace(t, loc); }
1370 #else
1371 bool ssisp(char c) const { return FALSE != ::isspace((int) c); }
1372 bool ssisp(wchar_t c) const { return FALSE != ::iswspace((wint_t) c); }
1373 bool operator()(CT t) const { return !ssisp(t); }
1374 #endif
1375 };
1376
1377
1378
1379
1380 // Now we can define the template (finally!)
1381 // =============================================================================
1382 // TEMPLATE: CStdStr
1383 // template<typename CT> class CStdStr : public std::basic_string<CT>
1384 //
1385 // REMARKS:
1386 // This template derives from basic_string<CT> and adds some MFC CString-
1387 // like functionality
1388 //
1389 // Basically, this is my attempt to make Standard C++ library strings as
1390 // easy to use as the MFC CString class.
1391 //
1392 // Note that although this is a template, it makes the assumption that the
1393 // template argument (CT, the character type) is either char or wchar_t.
1394 // =============================================================================
1395
1396 //#define CStdStr _SS // avoid compiler warning 4786
1397
1398
1399 template<typename CT>
1400 class CStdStr : public std::basic_string<CT>
1401 {
1402 // Typedefs for shorter names. Using these names also appears to help
1403 // us avoid some ambiguities that otherwise arise on some platforms
1404
1405 typedef typename std::basic_string<CT> MYBASE; // my base class
1406 typedef CStdStr<CT> MYTYPE; // myself
1407 typedef typename MYBASE::const_pointer PCMYSTR; // PCSTR or PCWSTR
1408 typedef typename MYBASE::pointer PMYSTR; // PSTR or PWSTR
1409 typedef typename MYBASE::iterator MYITER; // my iterator type
1410 typedef typename MYBASE::const_iterator MYCITER; // you get the idea...
1411 typedef typename MYBASE::reverse_iterator MYRITER;
1412 typedef typename MYBASE::size_type MYSIZE;
1413 typedef typename MYBASE::value_type MYVAL;
1414 typedef typename MYBASE::allocator_type MYALLOC;
1415
1416 public:
1417
1418 // shorthand conversion from PCTSTR to string resource ID
1419 #define _TRES(pctstr) (LOWORD((DWORD)(pctstr)))
1420
1421 // CStdStr inline constructors
1422 CStdStr()
1423 {
1424 }
1425
1426 CStdStr(const MYTYPE& str) : MYBASE(SSREF(str))
1427 {
1428 }
1429
1430 CStdStr(const std::string& str)
1431 {
1432 ssasn(*this, SSREF(str));
1433 }
1434
1435 CStdStr(const std::wstring& str)
1436 {
1437 ssasn(*this, SSREF(str));
1438 }
1439
1440 CStdStr(PCMYSTR pT, MYSIZE n) : MYBASE(pT, n)
1441 {
1442 }
1443
1444 CStdStr(PCSTR pA)
1445 {
1446 #ifdef SS_ANSI
1447 *this = pA;
1448 #else
1449 if ( 0 != HIWORD(pA) )
1450 *this = pA;
1451 else if ( 0 != pA && !Load(_TRES(pA)) )
1452 TRACE(_T("Can't load string %u\n"), _TRES(pA));
1453 #endif
1454 }
1455
1456 CStdStr(PCWSTR pW)
1457 {
1458 #ifdef SS_ANSI
1459 *this = pW;
1460 #else
1461 if ( 0 != HIWORD(pW) )
1462 *this = pW;
1463 else if ( 0 != pW && !Load(_TRES(pW)) )
1464 TRACE(_T("Can't load string %u\n"), _TRES(pW));
1465 #endif
1466 }
1467
1468 CStdStr(MYCITER first, MYCITER last)
1469 : MYBASE(first, last)
1470 {
1471 }
1472
1473 CStdStr(MYSIZE nSize, MYVAL ch, const MYALLOC& al=MYALLOC())
1474 : MYBASE(nSize, ch, al)
1475 {
1476 }
1477
1478 #ifdef SS_INC_COMDEF
1479 CStdStr(const _bstr_t& bstr)
1480 {
1481 if ( bstr.length() > 0 )
1482 append(static_cast<PCMYSTR>(bstr), bstr.length());
1483 }
1484 #endif
1485
1486 // CStdStr inline assignment operators -- the ssasn function now takes care
1487 // of fixing the MSVC assignment bug (see knowledge base article Q172398).
1488 MYTYPE& operator=(const MYTYPE& str)
1489 {
1490 ssasn(*this, str);
1491 return *this;
1492 }
1493
1494 MYTYPE& operator=(const std::string& str)
1495 {
1496 ssasn(*this, str);
1497 return *this;
1498 }
1499
1500 MYTYPE& operator=(const std::wstring& str)
1501 {
1502 ssasn(*this, str);
1503 return *this;
1504 }
1505
1506 MYTYPE& operator=(PCSTR pA)
1507 {
1508 ssasn(*this, pA);
1509 return *this;
1510 }
1511
1512 MYTYPE& operator=(PCWSTR pW)
1513 {
1514 ssasn(*this, pW);
1515 return *this;
1516 }
1517
1518 MYTYPE& operator=(CT t)
1519 {
1520 Q172398(*this);
1521 MYBASE::assign(1, t);
1522 return *this;
1523 }
1524
1525 #ifdef SS_INC_COMDEF
1526 MYTYPE& operator=(const _bstr_t& bstr)
1527 {
1528 if ( bstr.length() > 0 )
1529 return assign(static_cast<PCMYSTR>(bstr), bstr.length());
1530 else
1531 {
1532 erase();
1533 return *this;
1534 }
1535 }
1536 #endif
1537
1538
1539 // Overloads also needed to fix the MSVC assignment bug (KB: Q172398)
1540 // *** Thanks to Pete The Plumber for catching this one ***
1541 // They also are compiled if you have explicitly turned off refcounting
1542 #if ( defined(_MSC_VER) && ( _MSC_VER < 1200 ) ) || defined(SS_NO_REFCOUNT)
1543
1544 MYTYPE& assign(const MYTYPE& str)
1545 {
1546 ssasn(*this, str);
1547 return *this;
1548 }
1549
1550 MYTYPE& assign(const MYTYPE& str, MYSIZE nStart, MYSIZE nChars)
1551 {
1552 // This overload of basic_string::assign is supposed to assign up to
1553 // <nChars> or the NULL terminator, whichever comes first. Since we
1554 // are about to call a less forgiving overload (in which <nChars>
1555 // must be a valid length), we must adjust the length here to a safe
1556 // value. Thanks to Ullrich Pollähne for catching this bug
1557
1558 nChars = SSMIN(nChars, str.length() - nStart);
1559
1560 // Watch out for assignment to self
1561
1562 if ( this == &str )
1563 {
1564 MYTYPE strTemp(str.c_str()+nStart, nChars);
1565 assign(strTemp);
1566 }
1567 else
1568 {
1569 Q172398(*this);
1570 MYBASE::assign(str.c_str()+nStart, nChars);
1571 }
1572 return *this;
1573 }
1574
1575 MYTYPE& assign(const MYBASE& str)
1576 {
1577 ssasn(*this, str);
1578 return *this;
1579 }
1580
1581 MYTYPE& assign(const MYBASE& str, MYSIZE nStart, MYSIZE nChars)
1582 {
1583 // This overload of basic_string::assign is supposed to assign up to
1584 // <nChars> or the NULL terminator, whichever comes first. Since we
1585 // are about to call a less forgiving overload (in which <nChars>
1586 // must be a valid length), we must adjust the length here to a safe
1587 // value. Thanks to Ullrich Pollähne for catching this bug
1588
1589 nChars = SSMIN(nChars, str.length() - nStart);
1590
1591 // Watch out for assignment to self
1592
1593 if ( this == &str ) // watch out for assignment to self
1594 {
1595 MYTYPE strTemp(str.c_str() + nStart, nChars);
1596 assign(strTemp);
1597 }
1598 else
1599 {
1600 Q172398(*this);
1601 MYBASE::assign(str.c_str()+nStart, nChars);
1602 }
1603 return *this;
1604 }
1605
1606 MYTYPE& assign(const CT* pC, MYSIZE nChars)
1607 {
1608 // Q172398 only fix -- erase before assigning, but not if we're
1609 // assigning from our own buffer
1610
1611 #if defined ( _MSC_VER ) && ( _MSC_VER < 1200 )
1612 if ( !empty() && ( pC < data() || pC > data() + capacity() ) )
1613 erase();
1614 #endif
1615 Q172398(*this);
1616 MYBASE::assign(pC, nChars);
1617 return *this;
1618 }
1619
1620 MYTYPE& assign(MYSIZE nChars, MYVAL val)
1621 {
1622 Q172398(*this);
1623 MYBASE::assign(nChars, val);
1624 return *this;
1625 }
1626
1627 MYTYPE& assign(const CT* pT)
1628 {
1629 return assign(pT, CStdStr::traits_type::length(pT));
1630 }
1631
1632 MYTYPE& assign(MYCITER iterFirst, MYCITER iterLast)
1633 {
1634 #if defined ( _MSC_VER ) && ( _MSC_VER < 1200 )
1635 // Q172398 fix. don't call erase() if we're assigning from ourself
1636 if ( iterFirst < begin() || iterFirst > begin() + size() )
1637 erase()
1638 #endif
1639 replace(begin(), end(), iterFirst, iterLast);
1640 return *this;
1641 }
1642 #endif
1643
1644
1645 // -------------------------------------------------------------------------
1646 // CStdStr inline concatenation.
1647 // -------------------------------------------------------------------------
1648 MYTYPE& operator+=(const MYTYPE& str)
1649 {
1650 ssadd(*this, str);
1651 return *this;
1652 }
1653
1654 MYTYPE& operator+=(const std::string& str)
1655 {
1656 ssadd(*this, str);
1657 return *this;
1658 }
1659
1660 MYTYPE& operator+=(const std::wstring& str)
1661 {
1662 ssadd(*this, str);
1663 return *this;
1664 }
1665
1666 MYTYPE& operator+=(PCSTR pA)
1667 {
1668 ssadd(*this, pA);
1669 return *this;
1670 }
1671
1672 MYTYPE& operator+=(PCWSTR pW)
1673 {
1674 ssadd(*this, pW);
1675 return *this;
1676 }
1677
1678 MYTYPE& operator+=(CT t)
1679 {
1680 append(1, t);
1681 return *this;
1682 }
1683 #ifdef SS_INC_COMDEF // if we have _bstr_t, define a += for it too.
1684 MYTYPE& operator+=(const _bstr_t& bstr)
1685 {
1686 return operator+=(static_cast<PCMYSTR>(bstr));
1687 }
1688 #endif
1689
1690
1691 // addition operators -- global friend functions.
1692
1693 friend MYTYPE operator+(const MYTYPE& str1, const MYTYPE& str2);
1694 friend MYTYPE operator+(const MYTYPE& str, CT t);
1695 friend MYTYPE operator+(const MYTYPE& str, PCSTR sz);
1696 friend MYTYPE operator+(const MYTYPE& str, PCWSTR sz);
1697 friend MYTYPE operator+(PCSTR pA, const MYTYPE& str);
1698 friend MYTYPE operator+(PCWSTR pW, const MYTYPE& str);
1699 #ifdef SS_INC_COMDEF
1700 friend MYTYPE operator+(const _bstr_t& bstr, const MYTYPE& str);
1701 friend MYTYPE operator+(const MYTYPE& str, const _bstr_t& bstr);
1702 #endif
1703
1704 // -------------------------------------------------------------------------
1705 // Case changing functions
1706 // -------------------------------------------------------------------------
1707 // -------------------------------------------------------------------------
1708 MYTYPE& ToUpper()
1709 {
1710 // Strictly speaking, this would be about the most portable way
1711
1712 // std::transform(begin(),
1713 // end(),
1714 // begin(),
1715 // std::bind2nd(SSToUpper<CT>(), std::locale()));
1716
1717 // But practically speaking, this works faster
1718
1719 if ( !empty() )
1720 ssupr(GetBuf(), size());
1721
1722 return *this;
1723 }
1724
1725
1726
1727 MYTYPE& ToLower()
1728 {
1729 // Strictly speaking, this would be about the most portable way
1730
1731 // std::transform(begin(),
1732 // end(),
1733 // begin(),
1734 // std::bind2nd(SSToLower<CT>(), std::locale()));
1735
1736 // But practically speaking, this works faster
1737
1738 if ( !empty() )
1739 sslwr(GetBuf(), size());
1740
1741 return *this;
1742 }
1743
1744
1745
1746 MYTYPE& Normalize()
1747 {
1748 return Trim().ToLower();
1749 }
1750
1751
1752 // -------------------------------------------------------------------------
1753 // CStdStr -- Direct access to character buffer. In the MS' implementation,
1754 // the at() function that we use here also calls _Freeze() providing us some
1755 // protection from multithreading problems associated with ref-counting.
1756 // -------------------------------------------------------------------------
1757 CT* GetBuf(int nMinLen=-1)
1758 {
1759 if ( static_cast<int>(size()) < nMinLen )
1760 resize(static_cast<MYSIZE>(nMinLen));
1761
1762 return empty() ? const_cast<CT*>(data()) : &(at(0));
1763 }
1764
1765 CT* SetBuf(int nLen)
1766 {
1767 nLen = ( nLen > 0 ? nLen : 0 );
1768 if ( capacity() < 1 && nLen == 0 )
1769 resize(1);
1770
1771 resize(static_cast<MYSIZE>(nLen));
1772 return const_cast<CT*>(data());
1773 }
1774 void RelBuf(int nNewLen=-1)
1775 {
1776 resize(static_cast<MYSIZE>(nNewLen > -1 ? nNewLen : sslen(c_str())));
1777 }
1778
1779 void BufferRel() { RelBuf(); } // backwards compatability
1780 CT* Buffer() { return GetBuf(); } // backwards compatability
1781 CT* BufferSet(int nLen) { return SetBuf(nLen);}// backwards compatability
1782
1783 bool Equals(const CT* pT, bool bUseCase=false) const
1784 { // get copy, THEN compare (thread safe)
1785 return bUseCase ? compare(pT) == 0 : ssicmp(MYTYPE(*this), pT) == 0;
1786 }
1787
1788 // -------------------------------------------------------------------------
1789 // FUNCTION: CStdStr::Load
1790 // REMARKS:
1791 // Loads string from resource specified by nID
1792 //
1793 // PARAMETERS:
1794 // nID - resource Identifier. Purely a Win32 thing in this case
1795 //
1796 // RETURN VALUE:
1797 // true if successful, false otherwise
1798 // -------------------------------------------------------------------------
1799 #ifndef SS_ANSI
1800 bool Load(UINT nId, HMODULE hModule=NULL)
1801 {
1802 bool bLoaded = false; // set to true of we succeed.
1803
1804 #ifdef _MFC_VER // When in Rome...
1805
1806 CString strRes;
1807 bLoaded = FALSE != strRes.LoadString(nId);
1808 if ( bLoaded )
1809 *this = strRes;
1810
1811 #else
1812
1813 // Get the resource name and module handle
1814
1815 if ( NULL == hModule )
1816 hModule = GetResourceHandle();
1817
1818 PCTSTR szName = MAKEINTRESOURCE((nId>>4)+1); // lifted
1819 DWORD dwSize = 0;
1820
1821 // No sense continuing if we can't find the resource
1822
1823 HRSRC hrsrc = ::FindResource(hModule, szName, RT_STRING);
1824
1825 if ( NULL == hrsrc )
1826 TRACE(_T("Cannot find resource %d: 0x%X"), nId, ::GetLastError());
1827 else if ( 0 == (dwSize = ::SizeofResource(hModule, hrsrc) / sizeof(CT)))
1828 TRACE(_T("Cant get size of resource %d 0x%X\n"),nId,GetLastError());
1829 else
1830 {
1831 bLoaded = 0 != ssload(hModule, nId, GetBuf(dwSize), dwSize);
1832 ReleaseBuffer();
1833 }
1834
1835 #endif
1836
1837 if ( !bLoaded )
1838 TRACE(_T("String not loaded 0x%X\n"), ::GetLastError());
1839
1840 return bLoaded;
1841 }
1842 #endif
1843
1844 // -------------------------------------------------------------------------
1845 // FUNCTION: CStdStr::Format
1846 // void _cdecl Formst(CStdStringA& PCSTR szFormat, ...)
1847 // void _cdecl Format(PCSTR szFormat);
1848 //
1849 // DESCRIPTION:
1850 // This function does sprintf/wsprintf style formatting on CStdStringA
1851 // objects. It looks a lot like MFC's CString::Format. Some people
1852 // might even call this identical. Fortunately, these people are now
1853 // dead.
1854 //
1855 // PARAMETERS:
1856 // nId - ID of string resource holding the format string
1857 // szFormat - a PCSTR holding the format specifiers
1858 // argList - a va_list holding the arguments for the format specifiers.
1859 //
1860 // RETURN VALUE: None.
1861 // -------------------------------------------------------------------------
1862 // formatting (using wsprintf style formatting)
1863 #ifndef SS_ANSI
1864 void Format(UINT nId, ...)
1865 {
1866 va_list argList;
1867 va_start(argList, nId);
1868 va_start(argList, nId);
1869
1870 MYTYPE strFmt;
1871 if ( strFmt.Load(nId) )
1872 FormatV(strFmt, argList);
1873
1874 va_end(argList);
1875 }
1876 #endif
1877 void Format(const CT* szFmt, ...)
1878 {
1879 va_list argList;
1880 va_start(argList, szFmt);
1881 FormatV(szFmt, argList);
1882 va_end(argList);
1883 }
1884 void AppendFormat(const CT* szFmt, ...)
1885 {
1886 va_list argList;
1887 va_start(argList, szFmt);
1888 AppendFormatV(szFmt, argList);
1889 va_end(argList);
1890 }
1891
1892 #define MAX_FMT_TRIES 5 // #of times we try
1893 #define FMT_BLOCK_SIZE 2048 // # of bytes to increment per try
1894 #define BUFSIZE_1ST 256
1895 #define BUFSIZE_2ND 512
1896 #define STD_BUF_SIZE 1024
1897
1898 // an efficient way to add formatted characters to the string. You may only
1899 // add up to STD_BUF_SIZE characters at a time, though
1900 void AppendFormatV(const CT* szFmt, va_list argList)
1901 {
1902 CT szBuf[STD_BUF_SIZE];
1903 #ifdef SS_ANSI
1904 int nLen = ssvsprintf(szBuf, STD_BUF_SIZE-1, szFmt, argList);
1905 #else
1906 int nLen = ssnprintf(szBuf, STD_BUF_SIZE-1, szFmt, argList);
1907 #endif
1908 if ( 0 < nLen )
1909 append(szBuf, nLen);
1910 }
1911
1912 // -------------------------------------------------------------------------
1913 // FUNCTION: FormatV
1914 // void FormatV(PCSTR szFormat, va_list, argList);
1915 //
1916 // DESCRIPTION:
1917 // This function formats the string with sprintf style format-specs.
1918 // It makes a general guess at required buffer size and then tries
1919 // successively larger buffers until it finds one big enough or a
1920 // threshold (MAX_FMT_TRIES) is exceeded.
1921 //
1922 // PARAMETERS:
1923 // szFormat - a PCSTR holding the format of the output
1924 // argList - a Microsoft specific va_list for variable argument lists
1925 //
1926 // RETURN VALUE:
1927 // -------------------------------------------------------------------------
1928
1929 void FormatV(const CT* szFormat, va_list argList)
1930 {
1931 #ifdef SS_ANSI
1932
1933 int nLen = sslen(szFormat) + STD_BUF_SIZE;
1934 ssvsprintf(GetBuffer(nLen), nLen-1, szFormat, argList);
1935 ReleaseBuffer();
1936
1937 #else
1938
1939 CT* pBuf = NULL;
1940 int nChars = 1;
1941 int nUsed = 0;
1942 size_type nActual = 0;
1943 int nTry = 0;
1944
1945 do
1946 {
1947 // Grow more than linearly (e.g. 512, 1536, 3072, etc)
1948
1949 nChars += ((nTry+1) * FMT_BLOCK_SIZE);
1950 pBuf = reinterpret_cast<CT*>(_alloca(sizeof(CT)*nChars));
1951 nUsed = ssnprintf(pBuf, nChars-1, szFormat, argList);
1952
1953 // Ensure proper NULL termination.
1954
1955 nActual = nUsed == -1 ? nChars-1 : SSMIN(nUsed, nChars-1);
1956 pBuf[nActual+1]= '\0';
1957
1958
1959 } while ( nUsed < 0 && nTry++ < MAX_FMT_TRIES );
1960
1961 // assign whatever we managed to format
1962
1963 assign(pBuf, nActual);
1964
1965 #endif
1966 }
1967
1968
1969 // -------------------------------------------------------------------------
1970 // CString Facade Functions:
1971 //
1972 // The following methods are intended to allow you to use this class as a
1973 // drop-in replacement for CString.
1974 // -------------------------------------------------------------------------
1975 #ifndef SS_ANSI
1976 BSTR AllocSysString() const
1977 {
1978 ostring os;
1979 ssasn(os, *this);
1980 return ::SysAllocString(os.c_str());
1981 }
1982 #endif
1983
1984 int Collate(PCMYSTR szThat) const
1985 {
1986 return sscoll(c_str(), length(), szThat, sslen(szThat));
1987 }
1988
1989 int CollateNoCase(PCMYSTR szThat) const
1990 {
1991 return ssicoll(c_str(), length(), szThat, sslen(szThat));
1992 }
1993
1994 int Compare(PCMYSTR szThat) const
1995 {
1996 return MYBASE::compare(szThat);
1997 }
1998
1999 int CompareNoCase(PCMYSTR szThat) const
2000 {
2001 return ssicmp(c_str(), szThat);
2002 }
2003
2004 int Delete(int nIdx, int nCount=1)
2005 {
2006 if ( nIdx < GetLength() )
2007 erase(static_cast<MYSIZE>(nIdx), static_cast<MYSIZE>(nCount));
2008
2009 return GetLength();
2010 }
2011
2012 void Empty()
2013 {
2014 erase();
2015 }
2016
2017 int Find(CT ch) const
2018 {
2019 MYSIZE nIdx = find_first_of(ch);
2020 return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);
2021 }
2022
2023 int Find(PCMYSTR szSub) const
2024 {
2025 MYSIZE nIdx = find(szSub);
2026 return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);
2027 }
2028
2029 int Find(CT ch, int nStart) const
2030 {
2031 // CString::Find docs say add 1 to nStart when it's not zero
2032 // CString::Find code doesn't do that however. We'll stick
2033 // with what the code does
2034
2035 MYSIZE nIdx = find_first_of(ch, static_cast<MYSIZE>(nStart));
2036 return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);
2037 }
2038
2039 int Find(PCMYSTR szSub, int nStart) const
2040 {
2041 // CString::Find docs say add 1 to nStart when it's not zero
2042 // CString::Find code doesn't do that however. We'll stick
2043 // with what the code does
2044
2045 MYSIZE nIdx = find(szSub, static_cast<MYSIZE>(nStart));
2046 return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);
2047 }
2048
2049 int FindOneOf(PCMYSTR szCharSet) const
2050 {
2051 MYSIZE nIdx = find_first_of(szCharSet);
2052 return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);
2053 }
2054
2055 #ifndef SS_ANSI
2056 void FormatMessage(PCMYSTR szFormat, ...) throw(std::exception)
2057 {
2058 va_list argList;
2059 va_start(argList, szFormat);
2060 PMYSTR szTemp;
2061 if ( ssfmtmsg(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ALLOCATE_BUFFER,
2062 szFormat, 0, 0,
2063 reinterpret_cast<PMYSTR>(&szTemp), 0, &argList) == 0 ||
2064 szTemp == 0 )
2065 {
2066 throw std::runtime_error("out of memory");
2067 }
2068 *this = szTemp;
2069 LocalFree(szTemp);
2070 va_end(argList);
2071 }
2072
2073 void FormatMessage(UINT nFormatId, ...) throw(std::exception)
2074 {
2075 MYTYPE sFormat;
2076 VERIFY(sFormat.LoadString(nFormatId) != 0);
2077 va_list argList;
2078 va_start(argList, nFormatId);
2079 PMYSTR szTemp;
2080 if ( ssfmtmsg(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ALLOCATE_BUFFER,
2081 sFormat, 0, 0,
2082 reinterpret_cast<PMYSTR>(&szTemp), 0, &argList) == 0 ||
2083 szTemp == 0)
2084 {
2085 throw std::runtime_error("out of memory");
2086 }
2087 *this = szTemp;
2088 LocalFree(szTemp);
2089 va_end(argList);
2090 }
2091 #endif
2092
2093
2094 // -------------------------------------------------------------------------
2095 // GetXXXX -- Direct access to character buffer
2096 // -------------------------------------------------------------------------
2097 CT GetAt(int nIdx) const
2098 {
2099 return at(static_cast<MYSIZE>(nIdx));
2100 }
2101
2102 CT* GetBuffer(int nMinLen=-1)
2103 {
2104 return GetBuf(nMinLen);
2105 }
2106
2107 CT* GetBufferSetLength(int nLen)
2108 {
2109 return BufferSet(nLen);
2110 }
2111
2112 // GetLength() -- MFC docs say this is the # of BYTES but
2113 // in truth it is the number of CHARACTERs (chars or wchar_ts)
2114 int GetLength() const
2115 {
2116 return static_cast<int>(length());
2117 }
2118
2119
2120 int Insert(int nIdx, CT ch)
2121 {
2122 if ( static_cast<MYSIZE>(nIdx) > size() -1 )
2123 append(1, ch);
2124 else
2125 insert(static_cast<MYSIZE>(nIdx), 1, ch);
2126
2127 return GetLength();
2128 }
2129 int Insert(int nIdx, PCMYSTR sz)
2130 {
2131 if ( nIdx >= size() )
2132 append(sz, sslen(sz));
2133 else
2134 insert(static_cast<MYSIZE>(nIdx), sz);
2135
2136 return GetLength();
2137 }
2138
2139 bool IsEmpty() const
2140 {
2141 return empty();
2142 }
2143
2144 MYTYPE Left(int nCount) const
2145 {
2146 return substr(0, static_cast<MYSIZE>(nCount));
2147 }
2148
2149 #ifndef SS_ANSI
2150 bool LoadString(UINT nId)
2151 {
2152 return this->Load(nId);
2153 }
2154 #endif
2155
2156 void MakeLower()
2157 {
2158 ToLower();
2159 }
2160
2161 void MakeReverse()
2162 {
2163 std::reverse(begin(), end());
2164 }
2165
2166 void MakeUpper()
2167 {
2168 ToUpper();
2169 }
2170
2171 MYTYPE Mid(int nFirst ) const
2172 {
2173 return substr(static_cast<MYSIZE>(nFirst));
2174 }
2175
2176 MYTYPE Mid(int nFirst, int nCount) const
2177 {
2178 return substr(static_cast<MYSIZE>(nFirst), static_cast<MYSIZE>(nCount));
2179 }
2180
2181 void ReleaseBuffer(int nNewLen=-1)
2182 {
2183 RelBuf(nNewLen);
2184 }
2185
2186 int Remove(CT ch)
2187 {
2188 MYSIZE nIdx = 0;
2189 int nRemoved = 0;
2190 while ( (nIdx=find_first_of(ch)) != MYBASE::npos )
2191 {
2192 erase(nIdx, 1);
2193 nRemoved++;
2194 }
2195 return nRemoved;
2196 }
2197
2198 int Replace(CT chOld, CT chNew)
2199 {
2200 int nReplaced = 0;
2201 for ( MYITER iter=begin(); iter != end(); iter++ )
2202 {
2203 if ( *iter == chOld )
2204 {
2205 *iter = chNew;
2206 nReplaced++;
2207 }
2208 }
2209 return nReplaced;
2210 }
2211
2212 int Replace(PCMYSTR szOld, PCMYSTR szNew)
2213 {
2214 int nReplaced = 0;
2215 MYSIZE nIdx = 0;
2216 MYSIZE nOldLen = sslen(szOld);
2217 if ( 0 == nOldLen )
2218 return 0;
2219
2220 static const CT ch = CT(0);
2221 MYSIZE nNewLen = sslen(szNew);
2222 PCMYSTR szRealNew = szNew == 0 ? &ch : szNew;
2223
2224 while ( (nIdx=find(szOld, nIdx)) != MYBASE::npos )
2225 {
2226 replace(begin()+nIdx, begin()+nIdx+nOldLen, szRealNew);
2227 nReplaced++;
2228 nIdx += nNewLen;
2229 }
2230 return nReplaced;
2231 }
2232
2233 int ReverseFind(CT ch) const
2234 {
2235 MYSIZE nIdx = find_last_of(ch);
2236 return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);
2237 }
2238
2239 // ReverseFind overload that's not in CString but might be useful
2240 int ReverseFind(PCMYSTR szFind, MYSIZE pos=MYBASE::npos) const
2241 {
2242 MYSIZE nIdx = rfind(0 == szFind ? MYTYPE() : szFind, pos);
2243 return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);
2244 }
2245
2246 MYTYPE Right(int nCount) const
2247 {
2248 nCount = SSMIN(nCount, static_cast<int>(size()));
2249 return substr(size()-static_cast<MYSIZE>(nCount));
2250 }
2251
2252 void SetAt(int nIndex, CT ch)
2253 {
2254 ASSERT(size() > static_cast<MYSIZE>(nIndex));
2255 at(static_cast<MYSIZE>(nIndex)) = ch;
2256 }
2257
2258 #ifndef SS_ANSI
2259 BSTR SetSysString(BSTR* pbstr) const
2260 {
2261 ostring os;
2262 ssasn(os, *this);
2263 if ( !::SysReAllocStringLen(pbstr, os.c_str(), os.length()) )
2264 throw std::runtime_error("out of memory");
2265
2266 ASSERT(*pbstr != 0);
2267 return *pbstr;
2268 }
2269 #endif
2270
2271 MYTYPE SpanExcluding(PCMYSTR szCharSet) const
2272 {
2273 return Left(find_first_of(szCharSet));
2274 }
2275
2276 MYTYPE SpanIncluding(PCMYSTR szCharSet) const
2277 {
2278 return Left(find_first_not_of(szCharSet));
2279 }
2280
2281 #if !defined(UNICODE) && !defined(SS_ANSI)
2282
2283 // CString's OemToAnsi and AnsiToOem functions are available only in
2284 // Unicode builds. However since we're a template we also need a
2285 // runtime check of CT and a reinterpret_cast to account for the fact
2286 // that CStdStringW gets instantiated even in non-Unicode builds.
2287
2288 void AnsiToOem()
2289 {
2290 if ( sizeof(CT) == sizeof(char) && !empty() )
2291 {
2292 ::CharToOem(reinterpret_cast<PCSTR>(c_str()),
2293 reinterpret_cast<PSTR>(GetBuf()));
2294 }
2295 else
2296 {
2297 ASSERT(false);
2298 }
2299 }
2300
2301 void OemToAnsi()
2302 {
2303 if ( sizeof(CT) == sizeof(char) && !empty() )
2304 {
2305 ::OemToChar(reinterpret_cast<PCSTR>(c_str()),
2306 reinterpret_cast<PSTR>(GetBuf()));
2307 }
2308 else
2309 {
2310 ASSERT(false);
2311 }
2312 }
2313
2314 #endif
2315
2316
2317 // -------------------------------------------------------------------------
2318 // Trim and its variants
2319 // -------------------------------------------------------------------------
2320 MYTYPE& Trim()
2321 {
2322 return TrimLeft().TrimRight();
2323 }
2324
2325 MYTYPE& TrimLeft()
2326 {
2327 erase(begin(), std::find_if(begin(),end(),NotSpace<CT>(std::locale())));
2328 return *this;
2329 }
2330
2331 MYTYPE& TrimLeft(CT tTrim)
2332 {
2333 erase(0, find_first_not_of(tTrim));
2334 return *this;
2335 }
2336
2337 MYTYPE& TrimLeft(PCMYSTR szTrimChars)
2338 {
2339 erase(0, find_first_not_of(szTrimChars));
2340 return *this;
2341 }
2342
2343 MYTYPE& TrimRight()
2344 {
2345 std::locale loc;
2346 MYRITER it = std::find_if(rbegin(), rend(), NotSpace<CT>(loc));
2347 if ( rend() != it )
2348 erase(rend() - it);
2349
2350 erase(it != rend() ? find_last_of(*it) + 1 : 0);
2351 return *this;
2352 }
2353
2354 MYTYPE& TrimRight(CT tTrim)
2355 {
2356 MYSIZE nIdx = find_last_not_of(tTrim);
2357 erase(MYBASE::npos == nIdx ? 0 : ++nIdx);
2358 return *this;
2359 }
2360
2361 MYTYPE& TrimRight(PCMYSTR szTrimChars)
2362 {
2363 MYSIZE nIdx = find_last_not_of(szTrimChars);
2364 erase(MYBASE::npos == nIdx ? 0 : ++nIdx);
2365 return *this;
2366 }
2367
2368 void FreeExtra()
2369 {
2370 MYTYPE mt;
2371 swap(mt);
2372 if ( !mt.empty() )
2373 assign(mt.c_str(), mt.size());
2374 }
2375
2376 // I have intentionally not implemented the following CString
2377 // functions. You cannot make them work without taking advantage
2378 // of implementation specific behavior. However if you absolutely
2379 // MUST have them, uncomment out these lines for "sort-of-like"
2380 // their behavior. You're on your own.
2381
2382 // CT* LockBuffer() { return GetBuf(); }// won't really lock
2383 // void UnlockBuffer(); { } // why have UnlockBuffer w/o LockBuffer?
2384
2385 // Array-indexing operators. Required because we defined an implicit cast
2386 // to operator const CT* (Thanks to Julian Selman for pointing this out)
2387 CT& operator[](int nIdx)
2388 {
2389 return MYBASE::operator[](static_cast<MYSIZE>(nIdx));
2390 }
2391
2392 const CT& operator[](int nIdx) const
2393 {
2394 return MYBASE::operator[](static_cast<MYSIZE>(nIdx));
2395 }
2396
2397 CT& operator[](unsigned int nIdx)
2398 {
2399 return MYBASE::operator[](static_cast<MYSIZE>(nIdx));
2400 }
2401
2402 const CT& operator[](unsigned int nIdx) const
2403 {
2404 return MYBASE::operator[](static_cast<MYSIZE>(nIdx));
2405 }
2406
2407 operator const CT*() const
2408 {
2409 return c_str();
2410 }
2411
2412 // IStream related functions. Useful in IPersistStream implementations
2413
2414 #ifdef SS_INC_COMDEF
2415
2416 // struct SSSHDR - useful for non Std C++ persistence schemes.
2417 typedef struct SSSHDR
2418 {
2419 BYTE byCtrl;
2420 ULONG nChars;
2421 } SSSHDR; // as in "Standard String Stream Header"
2422
2423 #define SSSO_UNICODE 0x01 // the string is a wide string
2424 #define SSSO_COMPRESS 0x02 // the string is compressed
2425
2426 // -------------------------------------------------------------------------
2427 // FUNCTION: StreamSize
2428 // REMARKS:
2429 // Returns how many bytes it will take to StreamSave() this CStdString
2430 // object to an IStream.
2431 // -------------------------------------------------------------------------
2432 ULONG StreamSize() const
2433 {
2434 // Control header plus string
2435 ASSERT(size()*sizeof(CT) < 0xffffffffUL - sizeof(SSSHDR));
2436 return (size() * sizeof(CT)) + sizeof(SSSHDR);
2437 }
2438
2439 // -------------------------------------------------------------------------
2440 // FUNCTION: StreamSave
2441 // REMARKS:
2442 // Saves this CStdString object to a COM IStream.
2443 // -------------------------------------------------------------------------
2444 HRESULT StreamSave(IStream* pStream) const
2445 {
2446 ASSERT(size()*sizeof(CT) < 0xffffffffUL - sizeof(SSSHDR));
2447 HRESULT hr = E_FAIL;
2448 ASSERT(pStream != 0);
2449 SSSHDR hdr;
2450 hdr.byCtrl = sizeof(CT) == 2 ? SSSO_UNICODE : 0;
2451 hdr.nChars = size();
2452
2453
2454 if ( FAILED(hr=pStream->Write(&hdr, sizeof(SSSHDR), 0)) )
2455 TRACE(_T("StreamSave: Cannot write control header, ERR=0x%X\n"),hr);
2456 else if ( empty() )
2457 ; // nothing to write
2458 else if ( FAILED(hr=pStream->Write(c_str(), size()*sizeof(CT), 0)) )
2459 TRACE(_T("StreamSave: Cannot write string to stream 0x%X\n"), hr);
2460
2461 return hr;
2462 }
2463
2464
2465 // -------------------------------------------------------------------------
2466 // FUNCTION: StreamLoad
2467 // REMARKS:
2468 // This method loads the object from an IStream.
2469 // -------------------------------------------------------------------------
2470 HRESULT StreamLoad(IStream* pStream)
2471 {
2472 ASSERT(pStream != 0);
2473 SSSHDR hdr;
2474 HRESULT hr = E_FAIL;
2475
2476 if ( FAILED(hr=pStream->Read(&hdr, sizeof(SSSHDR), 0)) )
2477 {
2478 TRACE(_T("StreamLoad: Cant read control header, ERR=0x%X\n"), hr);
2479 }
2480 else if ( hdr.nChars > 0 )
2481 {
2482 ULONG nRead = 0;
2483 PMYSTR pMyBuf = BufferSet(hdr.nChars);
2484
2485 // If our character size matches the character size of the string
2486 // we're trying to read, then we can read it directly into our
2487 // buffer. Otherwise, we have to read into an intermediate buffer
2488 // and convert.
2489
2490 if ( (hdr.byCtrl & SSSO_UNICODE) != 0 )
2491 {
2492 ULONG nBytes = hdr.nChars * sizeof(wchar_t);
2493 if ( sizeof(CT) == sizeof(wchar_t) )
2494 {
2495 if ( FAILED(hr=pStream->Read(pMyBuf, nBytes, &nRead)) )
2496 TRACE(_T("StreamLoad: Cannot read string: 0x%X\n"), hr);
2497 }
2498 else
2499 {
2500 PWSTR pBufW = reinterpret_cast<PWSTR>(_alloca((nBytes)+1));
2501 if ( FAILED(hr=pStream->Read(pBufW, nBytes, &nRead)) )
2502 TRACE(_T("StreamLoad: Cannot read string: 0x%X\n"), hr);
2503 else
2504 sscpy(pMyBuf, pBufW, hdr.nChars);
2505 }
2506 }
2507 else
2508 {
2509 ULONG nBytes = hdr.nChars * sizeof(char);
2510 if ( sizeof(CT) == sizeof(char) )
2511 {
2512 if ( FAILED(hr=pStream->Read(pMyBuf, nBytes, &nRead)) )
2513 TRACE(_T("StreamLoad: Cannot read string: 0x%X\n"), hr);
2514 }
2515 else
2516 {
2517 PSTR pBufA = reinterpret_cast<PSTR>(_alloca(nBytes));
2518 if ( FAILED(hr=pStream->Read(pBufA, hdr.nChars, &nRead)) )
2519 TRACE(_T("StreamLoad: Cannot read string: 0x%X\n"), hr);
2520 else
2521 sscpy(pMyBuf, pBufA, hdr.nChars);
2522 }
2523 }
2524 }
2525 else
2526 {
2527 this->erase();
2528 }
2529 return hr;
2530 }
2531 #endif // #ifdef SS_INC_COMDEF
2532
2533 #ifndef SS_ANSI
2534
2535 // SetResourceHandle/GetResourceHandle. In MFC builds, these map directly
2536 // to AfxSetResourceHandle and AfxGetResourceHandle. In non-MFC builds they
2537 // point to a single static HINST so that those who call the member
2538 // functions that take resource IDs can provide an alternate HINST of a DLL
2539 // to search. This is not exactly the list of HMODULES that MFC provides
2540 // but it's better than nothing.
2541
2542 #ifdef _MFC_VER
2543 static void SetResourceHandle(HMODULE hNew)
2544 {
2545 AfxSetResourceHandle(hNew);
2546 }
2547 static HMODULE GetResourceHandle()
2548 {
2549 return AfxGetResourceHandle();
2550 }
2551 #else
2552 static void SetResourceHandle(HMODULE hNew)
2553 {
2554 SSResourceHandle() = hNew;
2555 }
2556 static HMODULE GetResourceHandle()
2557 {
2558 return SSResourceHandle();
2559 }
2560 #endif
2561
2562 #endif
2563 };
2564
2565
2566
2567 // -----------------------------------------------------------------------------
2568 // CStdStr friend addition functions defined as inline
2569 // -----------------------------------------------------------------------------
2570 template<typename CT>
2571 inline
2572 CStdStr<CT> operator+(const CStdStr<CT>& str1, const CStdStr<CT>& str2)
2573 {
2574 CStdStr<CT> strRet(SSREF(str1));
2575 strRet.append(str2);
2576 return strRet;
2577 }
2578
2579 template<typename CT>
2580 inline
2581 CStdStr<CT> operator+(const CStdStr<CT>& str, CT t)
2582 {
2583 // this particular overload is needed for disabling reference counting
2584 // though it's only an issue from line 1 to line 2
2585
2586 CStdStr<CT> strRet(SSREF(str)); // 1
2587 strRet.append(1, t); // 2
2588 return strRet;
2589 }
2590
2591 template<typename CT>
2592 inline
2593 CStdStr<CT> operator+(const CStdStr<CT>& str, PCSTR pA)
2594 {
2595 return CStdStr<CT>(str) + CStdStr<CT>(pA);
2596 }
2597
2598 template<typename CT>
2599 inline
2600 CStdStr<CT> operator+(PCSTR pA, const CStdStr<CT>& str)
2601 {
2602 CStdStr<CT> strRet(pA);
2603 strRet.append(str);
2604 return strRet;
2605 }
2606
2607 template<typename CT>
2608 inline
2609 CStdStr<CT> operator+(const CStdStr<CT>& str, PCWSTR pW)
2610 {
2611 return CStdStr<CT>(SSREF(str)) + CStdStr<CT>(pW);
2612 }
2613
2614 template<typename CT>
2615 inline
2616 CStdStr<CT> operator+(PCWSTR pW, const CStdStr<CT>& str)
2617 {
2618 CStdStr<CT> strRet(pW);
2619 strRet.append(str);
2620 return strRet;
2621 }
2622
2623 #ifdef SS_INC_COMDEF
2624 template<typename CT>
2625 inline
2626 CStdStr<CT> operator+(const _bstr_t& bstr, const CStdStr<CT>& str)
2627 {
2628 return static_cast<const CT*>(bstr) + str;
2629 }
2630
2631 template<typename CT>
2632 inline
2633 CStdStr<CT> operator+(const CStdStr<CT>& str, const _bstr_t& bstr)
2634 {
2635 return str + static_cast<const CT*>(bstr);
2636 }
2637 #endif
2638
2639
2640
2641
2642 // -----------------------------------------------------------------------------
2643 // These versions of operator+ provided by Scott Hathaway in order to allow
2644 // CStdString to build on Sun Unix systems.
2645 // -----------------------------------------------------------------------------
2646
2647 #if defined(__SUNPRO_CC_COMPAT) || defined(__SUNPRO_CC)
2648
2649 // Made non-template versions due to "undefined" errors on Sun Forte compiler
2650 // when linking with friend template functions
2651 inline
2652 CStdStr<wchar_t> operator+(const CStdStr<wchar_t>& str1,
2653 const CStdStr<wchar_t>& str2)
2654 {
2655 CStdStr<wchar_t> strRet(SSREF(str1));
2656 strRet.append(str2);
2657 return strRet;
2658 }
2659
2660 inline
2661 CStdStr<wchar_t> operator+(const CStdStr<wchar_t>& str, wchar_t t)
2662 {
2663 // this particular overload is needed for disabling reference counting
2664 // though it's only an issue from line 1 to line 2
2665
2666 CStdStr<wchar_t> strRet(SSREF(str)); // 1
2667 strRet.append(1, t); // 2
2668 return strRet;
2669 }
2670
2671 inline
2672 CStdStr<wchar_t> operator+(const CStdStr<wchar_t>& str, PCWSTR pW)
2673 {
2674 return CStdStr<wchar_t>(str) + CStdStr<wchar_t>(pW);
2675 }
2676
2677 inline
2678 CStdStr<wchar_t> operator+(PCWSTR pA, const CStdStr<wchar_t>& str)
2679 {
2680 CStdStr<wchar_t> strRet(pA);
2681 strRet.append(str);
2682 return strRet;
2683 }
2684
2685 inline
2686 CStdStr<wchar_t> operator+(const CStdStr<wchar_t>& str, PCSTR pW)
2687 {
2688 return CStdStr<wchar_t>(SSREF(str)) + CStdStr<wchar_t>(pW);
2689 }
2690
2691 inline
2692 CStdStr<wchar_t> operator+(PCSTR pW, const CStdStr<wchar_t>& str)
2693 {
2694 CStdStr<wchar_t> strRet(pW);
2695 strRet.append(str);
2696 return strRet;
2697 }
2698
2699 inline
2700 CStdStr<char> operator+(const CStdStr<char>& str1, const CStdStr<char>& str2)
2701 {
2702 CStdStr<char> strRet(SSREF(str1));
2703 strRet.append(str2);
2704 return strRet;
2705 }
2706
2707 inline
2708 CStdStr<char> operator+(const CStdStr<char>& str, char t)
2709 {
2710 // this particular overload is needed for disabling reference counting
2711 // though it's only an issue from line 1 to line 2
2712
2713 CStdStr<char> strRet(SSREF(str)); // 1
2714 strRet.append(1, t); // 2
2715 return strRet;
2716 }
2717
2718 inline
2719 CStdStr<char> operator+(const CStdStr<char>& str, PCSTR pA)
2720 {
2721 return CStdStr<char>(str) + CStdStr<char>(pA);
2722 }
2723
2724 inline
2725 CStdStr<char> operator+(PCSTR pA, const CStdStr<char>& str)
2726 {
2727 CStdStr<char> strRet(pA);
2728 strRet.append(str);
2729 return strRet;
2730 }
2731
2732 inline
2733 CStdStr<char> operator+(const CStdStr<char>& str, PCWSTR pW)
2734 {
2735 return CStdStr<char>(SSREF(str)) + CStdStr<char>(pW);
2736 }
2737
2738 inline
2739 CStdStr<char> operator+(PCWSTR pW, const CStdStr<char>& str)
2740 {
2741 CStdStr<char> strRet(pW);
2742 strRet.append(str);
2743 return strRet;
2744 }
2745
2746
2747 #endif // defined(__SUNPRO_CC_COMPAT) || defined(__SUNPRO_CC)
2748
2749
2750 // =============================================================================
2751 // END OF CStdStr INLINE FUNCTION DEFINITIONS
2752 // =============================================================================
2753
2754 // Now typedef our class names based upon this humongous template
2755
2756 typedef CStdStr<char> CStdStringA; // a better std::string
2757 typedef CStdStr<wchar_t> CStdStringW; // a better std::wstring
2758 typedef CStdStr<OLECHAR> CStdStringO; // almost always CStdStringW
2759
2760 #ifndef SS_ANSI
2761 // SSResourceHandle: our MFC-like resource handle
2762 inline HMODULE& SSResourceHandle()
2763 {
2764 static HMODULE hModuleSS = GetModuleHandle(0);
2765 return hModuleSS;
2766 }
2767 #endif
2768
2769
2770 // In MFC builds, define some global serialization operators
2771 // Special operators that allow us to serialize CStdStrings to CArchives.
2772 // Note that we use an intermediate CString object in order to ensure that
2773 // we use the exact same format.
2774
2775 #ifdef _MFC_VER
2776 inline CArchive& AFXAPI operator<<(CArchive& ar, const CStdStringA& strA)
2777 {
2778 CString strTemp = strA;
2779 return ar << strTemp;
2780 }
2781 inline CArchive& AFXAPI operator<<(CArchive& ar, const CStdStringW& strW)
2782 {
2783 CString strTemp = strW;
2784 return ar << strTemp;
2785 }
2786
2787 inline CArchive& AFXAPI operator>>(CArchive& ar, CStdStringA& strA)
2788 {
2789 CString strTemp;
2790 ar >> strTemp;
2791 strA = strTemp;
2792 return ar;
2793 }
2794 inline CArchive& AFXAPI operator>>(CArchive& ar, CStdStringW& strW)
2795 {
2796 CString strTemp;
2797 ar >> strTemp;
2798 strW = strTemp;
2799 return ar;
2800 }
2801 #endif // #ifdef _MFC_VER -- (i.e. is this MFC?)
2802
2803
2804
2805 // -----------------------------------------------------------------------------
2806 // HOW TO EXPORT CSTDSTRING FROM A DLL
2807 //
2808 // If you want to export CStdStringA and CStdStringW from a DLL, then all you
2809 // need to
2810 // 1. make sure that all components link to the same DLL version
2811 // of the CRT (not the static one).
2812 // 2. Uncomment the 3 lines of code below
2813 // 3. #define 2 macros per the instructions in MS KnowledgeBase
2814 // article Q168958. The macros are:
2815 //
2816 // MACRO DEFINTION WHEN EXPORTING DEFINITION WHEN IMPORTING
2817 // ----- ------------------------ -------------------------
2818 // SSDLLEXP (nothing, just #define it) extern
2819 // SSDLLSPEC __declspec(dllexport) __declspec(dllimport)
2820 //
2821 // Note that these macros must be available to ALL clients who want to
2822 // link to the DLL and use the class. If they
2823 // -----------------------------------------------------------------------------
2824 //#pragma warning(disable:4231) // non-standard extension ("extern template")
2825 // SSDLLEXP template class SSDLLSPEC CStdStr<char>;
2826 // SSDLLEXP template class SSDLLSPEC CStdStr<wchar_t>;
2827
2828
2829 // -----------------------------------------------------------------------------
2830 // GLOBAL FUNCTION: WUFormat
2831 // CStdStringA WUFormat(UINT nId, ...);
2832 // CStdStringA WUFormat(PCSTR szFormat, ...);
2833 //
2834 // REMARKS:
2835 // This function allows the caller for format and return a CStdStringA
2836 // object with a single line of code.
2837 // -----------------------------------------------------------------------------
2838 #ifdef SS_ANSI
2839 #else
2840 inline CStdStringA WUFormatA(UINT nId, ...)
2841 {
2842 va_list argList;
2843 va_start(argList, nId);
2844
2845 CStdStringA strFmt;
2846 CStdStringA strOut;
2847 if ( strFmt.Load(nId) )
2848 strOut.FormatV(strFmt, argList);
2849
2850 va_end(argList);
2851 return strOut;
2852 }
2853 inline CStdStringA WUFormatA(PCSTR szFormat, ...)
2854 {
2855 va_list argList;
2856 va_start(argList, szFormat);
2857 CStdStringA strOut;
2858 strOut.FormatV(szFormat, argList);
2859 va_end(argList);
2860 return strOut;
2861 }
2862
2863 inline CStdStringW WUFormatW(UINT nId, ...)
2864 {
2865 va_list argList;
2866 va_start(argList, nId);
2867
2868 CStdStringW strFmt;
2869 CStdStringW strOut;
2870 if ( strFmt.Load(nId) )
2871 strOut.FormatV(strFmt, argList);
2872
2873 va_end(argList);
2874 return strOut;
2875 }
2876 inline CStdStringW WUFormatW(PCWSTR szwFormat, ...)
2877 {
2878 va_list argList;
2879 va_start(argList, szwFormat);
2880 CStdStringW strOut;
2881 strOut.FormatV(szwFormat, argList);
2882 va_end(argList);
2883 return strOut;
2884 }
2885 #endif // #ifdef SS_ANSI
2886
2887 #ifdef SS_ANSI
2888 #else
2889 // -------------------------------------------------------------------------
2890 // FUNCTION: WUSysMessage
2891 // CStdStringA WUSysMessageA(DWORD dwError, DWORD dwLangId=SS_DEFLANGID);
2892 // CStdStringW WUSysMessageW(DWORD dwError, DWORD dwLangId=SS_DEFLANGID);
2893 //
2894 // DESCRIPTION:
2895 // This function simplifies the process of obtaining a string equivalent
2896 // of a system error code returned from GetLastError(). You simply
2897 // supply the value returned by GetLastError() to this function and the
2898 // corresponding system string is returned in the form of a CStdStringA.
2899 //
2900 // PARAMETERS:
2901 // dwError - a DWORD value representing the error code to be translated
2902 // dwLangId - the language id to use. defaults to english.
2903 //
2904 // RETURN VALUE:
2905 // a CStdStringA equivalent of the error code. Currently, this function
2906 // only returns either English of the system default language strings.
2907 // -------------------------------------------------------------------------
2908 #define SS_DEFLANGID MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT)
2909 inline CStdStringA WUSysMessageA(DWORD dwError, DWORD dwLangId=SS_DEFLANGID)
2910 {
2911 CHAR szBuf[512];
2912
2913 if ( 0 != ::FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError,
2914 dwLangId, szBuf, 511, NULL) )
2915 return WUFormatA("%s (0x%X)", szBuf, dwError);
2916 else
2917 return WUFormatA("Unknown error (0x%X)", dwError);
2918 }
2919 inline CStdStringW WUSysMessageW(DWORD dwError, DWORD dwLangId=SS_DEFLANGID)
2920 {
2921 WCHAR szBuf[512];
2922
2923 if ( 0 != ::FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError,
2924 dwLangId, szBuf, 511, NULL) )
2925 return WUFormatW(L"%s (0x%X)", szBuf, dwError);
2926 else
2927 return WUFormatW(L"Unknown error (0x%X)", dwError);
2928 }
2929 #endif
2930
2931 // Define TCHAR based friendly names for some of these functions
2932
2933 #ifdef UNICODE
2934 #define CStdString CStdStringW
2935 #define WUSysMessage WUSysMessageW
2936 #define WUFormat WUFormatW
2937 #else
2938 #define CStdString CStdStringA
2939 #define WUSysMessage WUSysMessageA
2940 #define WUFormat WUFormatA
2941 #endif
2942
2943 // ...and some shorter names for the space-efficient
2944
2945 #define WUSysMsg WUSysMessage
2946 #define WUSysMsgA WUSysMessageA
2947 #define WUSysMsgW WUSysMessageW
2948 #define WUFmtA WUFormatA
2949 #define WUFmtW WUFormatW
2950 #define WUFmt WUFormat
2951 #define WULastErrMsg() WUSysMessage(::GetLastError())
2952 #define WULastErrMsgA() WUSysMessageA(::GetLastError())
2953 #define WULastErrMsgW() WUSysMessageW(::GetLastError())
2954
2955
2956 // -----------------------------------------------------------------------------
2957 // FUNCTIONAL COMPARATORS:
2958 // REMARKS:
2959 // These structs are derived from the std::binary_function template. They
2960 // give us functional classes (which may be used in Standard C++ Library
2961 // collections and algorithms) that perform case-insensitive comparisons of
2962 // CStdString objects. This is useful for maps in which the key may be the
2963 // proper string but in the wrong case.
2964 // -----------------------------------------------------------------------------
2965 #define StdStringLessNoCaseW SSLNCW // avoid VC compiler warning 4786
2966 #define StdStringEqualsNoCaseW SSENCW
2967 #define StdStringLessNoCaseA SSLNCA
2968 #define StdStringEqualsNoCaseA SSENCA
2969
2970 #ifdef UNICODE
2971 #define StdStringLessNoCase SSLNCW
2972 #define StdStringEqualsNoCase SSENCW
2973 #else
2974 #define StdStringLessNoCase SSLNCA
2975 #define StdStringEqualsNoCase SSENCA
2976 #endif
2977
2978 struct StdStringLessNoCaseW
2979 : std::binary_function<CStdStringW, CStdStringW, bool>
2980 {
2981 inline
2982 bool operator()(const CStdStringW& sLeft, const CStdStringW& sRight) const
2983 { return ssicmp(sLeft.c_str(), sRight.c_str()) < 0; }
2984 };
2985 struct StdStringEqualsNoCaseW
2986 : std::binary_function<CStdStringW, CStdStringW, bool>
2987 {
2988 inline
2989 bool operator()(const CStdStringW& sLeft, const CStdStringW& sRight) const
2990 { return ssicmp(sLeft.c_str(), sRight.c_str()) == 0; }
2991 };
2992 struct StdStringLessNoCaseA
2993 : std::binary_function<CStdStringA, CStdStringA, bool>
2994 {
2995 inline
2996 bool operator()(const CStdStringA& sLeft, const CStdStringA& sRight) const
2997 { return ssicmp(sLeft.c_str(), sRight.c_str()) < 0; }
2998 };
2999 struct StdStringEqualsNoCaseA
3000 : std::binary_function<CStdStringA, CStdStringA, bool>
3001 {
3002 inline
3003 bool operator()(const CStdStringA& sLeft, const CStdStringA& sRight) const
3004 { return ssicmp(sLeft.c_str(), sRight.c_str()) == 0; }
3005 };
3006
3007 // If we had to define our own version of TRACE above, get rid of it now
3008
3009 #ifdef TRACE_DEFINED_HERE
3010 #undef TRACE
3011 #undef TRACE_DEFINED_HERE
3012 #endif
3013
3014
3015 #endif // #ifndef STDSTRING_H

  ViewVC Help
Powered by ViewVC 1.1.26