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