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