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