Main Page | Namespace List | Class Hierarchy | Class List | File List | Namespace Members | Class Members | File Members

StdString.h

Go to the documentation of this file.
00001 // ============================================================================= 00002 // FILE: StdString.h 00003 // AUTHOR: Joe O'Leary (with outside help noted in comments) 00004 // REMARKS: 00005 // This header file declares the CStdStr template. This template derives 00006 // the Standard C++ Library basic_string<> template and add to it the 00007 // the following conveniences: 00008 // - The full MFC CString set of functions (including implicit cast) 00009 // - writing to/reading from COM IStream interfaces 00010 // - Functional objects for use in STL algorithms 00011 // 00012 // From this template, we intstantiate two classes: CStdStringA and 00013 // CStdStringW. The name "CStdString" is just a #define of one of these, 00014 // based upone the _UNICODE macro setting 00015 // 00016 // This header also declares our own version of the MFC/ATL UNICODE-MBCS 00017 // conversion macros. Our version looks exactly like the Microsoft's to 00018 // facilitate portability. 00019 // 00020 // NOTE: 00021 // If you you use this in an MFC or ATL build, you should include either 00022 // afx.h or atlbase.h first, as appropriate. 00023 // 00024 // PEOPLE WHO HAVE CONTRIBUTED TO THIS CLASS: 00025 // 00026 // Several people have helped me iron out problems and othewise improve 00027 // this class. OK, this is a long list but in my own defense, this code 00028 // has undergone two major rewrites. Many of the improvements became 00029 // necessary after I rewrote the code as a template. Others helped me 00030 // improve the CString facade. 00031 // 00032 // Anyway, these people are (in chronological order): 00033 // 00034 // - Pete the Plumber (???) 00035 // - Julian Selman 00036 // - Chris (of Melbsys) 00037 // - Dave Plummer 00038 // - John C Sipos 00039 // - Chris Sells 00040 // - Nigel Nunn 00041 // - Fan Xia 00042 // - Matthew Williams 00043 // - Carl Engman 00044 // - Mark Zeren 00045 // - Craig Watson 00046 // - Rich Zuris 00047 // - Karim Ratib 00048 // - Chris Conti 00049 // - Baptiste Lepilleur 00050 // - Greg Pickles 00051 // - Jim Cline 00052 // - Jeff Kohn 00053 // - Todd Heckel 00054 // - Ullrich Pollähne 00055 // - Joe Vitaterna 00056 // - Joe Woodbury 00057 // - Aaron (no last name) 00058 // - Joldakowski (???) 00059 // - Scott Hathaway 00060 // - Eric Nitzche 00061 // - Pablo Presedo 00062 // - Farrokh Nejadlotfi 00063 // - Jason Mills 00064 // - Igor Kholodov 00065 // - Mike Crusader 00066 // - John James 00067 // - Wang Haifeng 00068 // - Tim Dowty 00069 // - Arnt Witteveen 00070 // 00071 // REVISION HISTORY 00072 // 2002-JUN-26 - Thanks to Arnt Witteveen for pointing out that I was using 00073 // static_cast<> in a place in which I should have been using 00074 // reinterpret_cast<> (the ctor for unsigned char strings). 00075 // That's what happens when I don't unit-test properly! 00076 // Arnt also noticed that CString was silently correcting the 00077 // 'nCount' argument to Left() and Right() where CStdString was 00078 // not (and crashing if it was bad). That is also now fixed! 00079 // 2002-FEB-25 - Thanks to Tim Dowty for pointing out (and giving me the fix 00080 // for) a conversion problem with non-ASCII MBCS characters. 00081 // CStdString is now used in my favorite commercial MP3 player! 00082 // 2001-DEC-06 - Thanks to Wang Haifeng for spotting a problem in one of the 00083 // assignment operators (for _bstr_t) that would cause compiler 00084 // errors when refcounting protection was turned off. 00085 // 2001-NOV-27 - Remove calls to operator!= which involve reverse_iterators 00086 // due to a conflict with the rel_ops operator!=. Thanks to 00087 // John James for pointing this out. 00088 // 2001-OCT-29 - Added a minor range checking fix for the Mid function to 00089 // make it as forgiving as CString's version is. Thanks to 00090 // Igor Kholodov for noticing this. 00091 // - Added a specialization of std::swap for CStdString. Thanks 00092 // to Mike Crusader for suggesting this! It's commented out 00093 // because you're not supposed to inject your own code into the 00094 // 'std' namespace. But if you don't care about that, it's 00095 // there if you want it 00096 // - Thanks to Jason Mills for catching a case where CString was 00097 // more forgiving in the Delete() function than I was. 00098 // 2001-JUN-06 - I was violating the Standard name lookup rules stated 00099 // in [14.6.2(3)]. None of the compilers I've tried so 00100 // far apparently caught this but HP-UX aCC 3.30 did. The 00101 // fix was to add 'this->' prefixes in many places. 00102 // Thanks to Farrokh Nejadlotfi for this! 00103 // 00104 // 2001-APR-27 - StreamLoad was calculating the number of BYTES in one 00105 // case, not characters. Thanks to Pablo Presedo for this. 00106 // 00107 // 2001-FEB-23 - Replace() had a bug which caused infinite loops if the 00108 // source string was empty. Fixed thanks to Eric Nitzsche. 00109 // 00110 // 2001-FEB-23 - Scott Hathaway was a huge help in providing me with the 00111 // ability to build CStdString on Sun Unix systems. He 00112 // sent me detailed build reports about what works and what 00113 // does not. If CStdString compiles on your Unix box, you 00114 // can thank Scott for it. 00115 // 00116 // 2000-DEC-29 - Joldakowski noticed one overload of Insert failed to do 00117 // range check as CString's does. Now fixed -- thanks! 00118 // 00119 // 2000-NOV-07 - Aaron pointed out that I was calling static member 00120 // functions of char_traits via a temporary. This was not 00121 // technically wrong, but it was unnecessary and caused 00122 // problems for poor old buggy VC5. Thanks Aaron! 00123 // 00124 // 2000-JUL-11 - Joe Woodbury noted that the CString::Find docs don't match 00125 // what the CString::Find code really ends up doing. I was 00126 // trying to match the docs. Now I match the CString code 00127 // - Joe also caught me truncating strings for GetBuffer() calls 00128 // when the supplied length was less than the current length. 00129 // 00130 // 2000-MAY-25 - Better support for STLPORT's Standard library distribution 00131 // - Got rid of the NSP macro - it interfered with Koenig lookup 00132 // - Thanks to Joe Woodbury for catching a TrimLeft() bug that 00133 // I introduced in January. Empty strings were not getting 00134 // trimmed 00135 // 00136 // 2000-APR-17 - Thanks to Joe Vitaterna for pointing out that ReverseFind 00137 // is supposed to be a const function. 00138 // 00139 // 2000-MAR-07 - Thanks to Ullrich Pollähne for catching a range bug in one 00140 // of the overloads of assign. 00141 // 00142 // 2000-FEB-01 - You can now use CStdString on the Mac with CodeWarrior! 00143 // Thanks to Todd Heckel for helping out with this. 00144 // 00145 // 2000-JAN-23 - Thanks to Jim Cline for pointing out how I could make the 00146 // Trim() function more efficient. 00147 // - Thanks to Jeff Kohn for prompting me to find and fix a typo 00148 // in one of the addition operators that takes _bstr_t. 00149 // - Got rid of the .CPP file - you only need StdString.h now! 00150 // 00151 // 1999-DEC-22 - Thanks to Greg Pickles for helping me identify a problem 00152 // with my implementation of CStdString::FormatV in which 00153 // resulting string might not be properly NULL terminated. 00154 // 00155 // 1999-DEC-06 - Chris Conti pointed yet another basic_string<> assignment 00156 // bug that MS has not fixed. CStdString did nothing to fix 00157 // it either but it does now! The bug was: create a string 00158 // longer than 31 characters, get a pointer to it (via c_str()) 00159 // and then assign that pointer to the original string object. 00160 // The resulting string would be empty. Not with CStdString! 00161 // 00162 // 1999-OCT-06 - BufferSet was erasing the string even when it was merely 00163 // supposed to shrink it. Fixed. Thanks to Chris Conti. 00164 // - Some of the Q172398 fixes were not checking for assignment- 00165 // to-self. Fixed. Thanks to Baptiste Lepilleur. 00166 // 00167 // 1999-AUG-20 - Improved Load() function to be more efficient by using 00168 // SizeOfResource(). Thanks to Rich Zuris for this. 00169 // - Corrected resource ID constructor, again thanks to Rich. 00170 // - Fixed a bug that occurred with UNICODE characters above 00171 // the first 255 ANSI ones. Thanks to Craig Watson. 00172 // - Added missing overloads of TrimLeft() and TrimRight(). 00173 // Thanks to Karim Ratib for pointing them out 00174 // 00175 // 1999-JUL-21 - Made all calls to GetBuf() with no args check length first. 00176 // 00177 // 1999-JUL-10 - Improved MFC/ATL independence of conversion macros 00178 // - Added SS_NO_REFCOUNT macro to allow you to disable any 00179 // reference-counting your basic_string<> impl. may do. 00180 // - Improved ReleaseBuffer() to be as forgiving as CString. 00181 // Thanks for Fan Xia for helping me find this and to 00182 // Matthew Williams for pointing it out directly. 00183 // 00184 // 1999-JUL-06 - Thanks to Nigel Nunn for catching a very sneaky bug in 00185 // ToLower/ToUpper. They should call GetBuf() instead of 00186 // data() in order to ensure the changed string buffer is not 00187 // reference-counted (in those implementations that refcount). 00188 // 00189 // 1999-JUL-01 - Added a true CString facade. Now you can use CStdString as 00190 // a drop-in replacement for CString. If you find this useful, 00191 // you can thank Chris Sells for finally convincing me to give 00192 // in and implement it. 00193 // - Changed operators << and >> (for MFC CArchive) to serialize 00194 // EXACTLY as CString's do. So now you can send a CString out 00195 // to a CArchive and later read it in as a CStdString. I have 00196 // no idea why you would want to do this but you can. 00197 // 00198 // 1999-JUN-21 - Changed the CStdString class into the CStdStr template. 00199 // - Fixed FormatV() to correctly decrement the loop counter. 00200 // This was harmless bug but a bug nevertheless. Thanks to 00201 // Chris (of Melbsys) for pointing it out 00202 // - Changed Format() to try a normal stack-based array before 00203 // using to _alloca(). 00204 // - Updated the text conversion macros to properly use code 00205 // pages and to fit in better in MFC/ATL builds. In other 00206 // words, I copied Microsoft's conversion stuff again. 00207 // - Added equivalents of CString::GetBuffer, GetBufferSetLength 00208 // - a Trim() function that combines TrimRight() and TrimLeft(). 00209 // 00210 // 1999-MAR-13 - Corrected the "NotSpace" functional object to use _istpace() 00211 // instead of _isspace() Thanks to Dave Plummer for this. 00212 // 00213 // 1999-FEB-26 - Removed errant line (left over from testing) that #defined 00214 // _MFC_VER. Thanks to John C Sipos for noticing this. 00215 // 00216 // 1999-FEB-03 - Fixed a bug in a rarely-used overload of operator+() that 00217 // caused infinite recursion and stack overflow 00218 // - Added member functions to simplify the process of 00219 // persisting CStdStrings to/from DCOM IStream interfaces 00220 // - Added functional objects (e.g. StdStringLessNoCase) that 00221 // allow CStdStrings to be used as keys STL map objects with 00222 // case-insensitive comparison 00223 // - Added array indexing operators (i.e. operator[]). I 00224 // originally assumed that these were unnecessary and would be 00225 // inherited from basic_string. However, without them, Visual 00226 // C++ complains about ambiguous overloads when you try to use 00227 // them. Thanks to Julian Selman to pointing this out. 00228 // 00229 // 1998-FEB-?? - Added overloads of assign() function to completely account 00230 // for Q172398 bug. Thanks to "Pete the Plumber" for this 00231 // 00232 // 1998-FEB-?? - Initial submission 00233 // 00234 // COPYRIGHT: 00235 // 1999 Joseph M. O'Leary. This code is free. Use it anywhere you want. 00236 // Rewrite it, restructure it, whatever. Please don't blame me if it makes 00237 // your $30 billion dollar satellite explode in orbit. If you redistribute 00238 // it in any form, I'd appreciate it if you would leave this notice here. 00239 // 00240 // If you find any bugs, please let me know: 00241 // 00242 // jmoleary@earthlink.net 00243 // http://home.earthlink.net/~jmoleary 00244 // ============================================================================= 00245 00246 // Turn off browser references 00247 // Turn off unavoidable compiler warnings 00248 00249 00250 #if defined(_MSC_VER) && (_MSC_VER > 1100) 00251 #pragma component(browser, off, references, "CStdString") 00252 #pragma warning (push) 00253 #pragma warning (disable : 4290) // C++ Exception Specification ignored 00254 #pragma warning (disable : 4127) // Conditional expression is constant 00255 #pragma warning (disable : 4097) // typedef name used as synonym for class name 00256 #pragma warning (disable : 4512) // assignment operator could not be generated 00257 #endif 00258 00259 #ifndef STDSTRING_H 00260 #define STDSTRING_H 00261 00262 // If they want us to use only standard C++ stuff (no Win32 stuff) 00263 00264 typedef const char* PCSTR; 00265 typedef char* PSTR; 00266 00267 // Standard headers needed 00268 #include <string> // basic_string 00269 #include <algorithm> // for_each, etc. 00270 #include <functional> // for StdStringLessNoCase, et al 00271 00272 #if defined(WIN32) 00273 #include <malloc.h> // _alloca 00274 #endif 00275 00276 #include <cstdarg> 00277 00278 #include <cstdio> 00279 #include <cctype> 00280 #include <cstdlib> 00281 #include <cstdarg> 00282 00283 // a very shorthand way of applying the fix for KB problem Q172398 00284 // (basic_string assignment bug) 00285 00286 #if defined ( _MSC_VER ) && ( _MSC_VER < 1200 ) 00287 #define Q172398(x) (x).erase() 00288 #else 00289 #define Q172398(x) 00290 #endif 00291 00292 // ============================================================================= 00293 // INLINE FUNCTIONS ON WHICH CSTDSTRING RELIES 00294 // 00295 // Usually for generic text mapping, we rely on preprocessor macro definitions 00296 // to map to string functions. However the CStdStr<> template cannot use 00297 // macro-based generic text mappings because its character types do not get 00298 // resolved until template processing which comes AFTER macro processing. In 00299 // other words, UNICODE is of little help to us in the CStdStr template 00300 // 00301 // Therefore, to keep the CStdStr declaration simple, we have these inline 00302 // functions. The template calls them often. Since they are inline (and NOT 00303 // exported when this is built as a DLL), they will probably be resolved away 00304 // to nothing. 00305 // 00306 // Without these functions, the CStdStr<> template would probably have to broken 00307 // out into two, almost identical classes. Either that or it would be a huge, 00308 // convoluted mess, with tons of "if" statements all over the place checking the 00309 // size of template parameter CT. 00310 // 00311 // In several cases, you will see two versions of each function. One version is 00312 // the more portable, standard way of doing things, while the other is the 00313 // non-standard, but often significantly faster Visual C++ way. 00314 // ============================================================================= 00315 00316 // ----------------------------------------------------------------------------- 00317 // sslen: strlen/wcslen wrappers 00318 // ----------------------------------------------------------------------------- 00319 template<typename CT> inline int sslen(const CT* pT) 00320 { 00321 return 0 == pT ? 0 : std::basic_string<CT>::traits_type::length(pT); 00322 } 00323 inline int sslen(const std::string& s) 00324 { 00325 return s.length(); 00326 } 00327 00328 // ----------------------------------------------------------------------------- 00329 // sstolower/sstoupper -- convert characters to upper/lower case 00330 // ----------------------------------------------------------------------------- 00331 //inline char sstoupper(char ch) { return (char)::toupper(ch); } 00332 //inline char sstolower(char ch) { return (char)::tolower(ch); } 00333 /* Our strings are UTF-8; instead of having to play around with locales, 00334 * let's just manually toupper ASCII only. If we really want to play with 00335 * Unicode cases, we can do it ourself in RageUtil. */ 00336 inline char sstoupper(char ch) { return (ch >= 'a' && ch <= 'z')? char(ch + 'A' - 'a'): ch; } 00337 inline char sstolower(char ch) { return (ch >= 'A' && ch <= 'Z')? char(ch + 'a' - 'A'): ch; } 00338 00339 // ----------------------------------------------------------------------------- 00340 // ssasn: assignment functions -- assign "sSrc" to "sDst" 00341 // ----------------------------------------------------------------------------- 00342 typedef std::string::size_type SS_SIZETYPE; // just for shorthand, really 00343 typedef std::string::pointer SS_PTRTYPE; 00344 00345 inline void ssasn(std::string& sDst, const std::string& sSrc) 00346 { 00347 if ( sDst.c_str() != sSrc.c_str() ) 00348 { 00349 sDst.erase(); 00350 sDst.assign(sSrc); 00351 } 00352 } 00353 inline void ssasn(std::string& sDst, PCSTR pA) 00354 { 00355 // Watch out for NULLs, as always. 00356 00357 if ( 0 == pA ) 00358 { 00359 sDst.erase(); 00360 } 00361 00362 // If pA actually points to part of sDst, we must NOT erase(), but 00363 // rather take a substring 00364 00365 else if ( pA >= sDst.c_str() && pA <= sDst.c_str() + sDst.size() ) 00366 { 00367 sDst =sDst.substr(static_cast<SS_SIZETYPE>(pA-sDst.c_str())); 00368 } 00369 00370 // Otherwise (most cases) apply the assignment bug fix, if applicable 00371 // and do the assignment 00372 00373 else 00374 { 00375 Q172398(sDst); 00376 sDst.assign(pA); 00377 } 00378 } 00379 inline void ssasn(std::string& sDst, const int nNull) 00380 { 00381 sDst.erase(); 00382 } 00383 #undef StrSizeType 00384 00385 00386 // ----------------------------------------------------------------------------- 00387 // ssadd: string object concatenation -- add second argument to first 00388 // ----------------------------------------------------------------------------- 00389 inline void ssadd(std::string& sDst, const std::string& sSrc) 00390 { 00391 if ( &sDst == &sSrc ) 00392 sDst.reserve(2*sDst.size()); 00393 00394 sDst.append(sSrc.c_str()); 00395 } 00396 inline void ssadd(std::string& sDst, PCSTR pA) 00397 { 00398 if ( pA ) 00399 { 00400 // If the string being added is our internal string or a part of our 00401 // internal string, then we must NOT do any reallocation without 00402 // first copying that string to another object (since we're using a 00403 // direct pointer) 00404 00405 if ( pA >= sDst.c_str() && pA <= sDst.c_str()+sDst.length()) 00406 { 00407 if ( sDst.capacity() <= sDst.size()+sslen(pA) ) 00408 sDst.append(std::string(pA)); 00409 else 00410 sDst.append(pA); 00411 } 00412 else 00413 { 00414 sDst.append(pA); 00415 } 00416 } 00417 } 00418 00419 // ----------------------------------------------------------------------------- 00420 // ssicmp: comparison (case insensitive ) 00421 // ----------------------------------------------------------------------------- 00422 template<typename CT> 00423 inline int ssicmp(const CT* pA1, const CT* pA2) 00424 { 00425 CT f; 00426 CT l; 00427 00428 do 00429 { 00430 f = sstolower(*(pA1++)); 00431 l = sstolower(*(pA2++)); 00432 } while ( (f) && (f == l) ); 00433 00434 return (int)(f - l); 00435 } 00436 00437 // ----------------------------------------------------------------------------- 00438 // ssupr/sslwr: Uppercase/Lowercase conversion functions 00439 // ----------------------------------------------------------------------------- 00440 template<typename CT> 00441 inline void sslwr(CT* pT, size_t nLen) 00442 { 00443 for ( CT* p = pT; static_cast<size_t>(p - pT) < nLen; ++p) 00444 *p = (CT)sstolower(*p); 00445 } 00446 template<typename CT> 00447 inline void ssupr(CT* pT, size_t nLen) 00448 { 00449 for ( CT* p = pT; static_cast<size_t>(p - pT) < nLen; ++p) 00450 *p = (CT)sstoupper(*p); 00451 } 00452 // ----------------------------------------------------------------------------- 00453 // vsprintf/vswprintf or _vsnprintf/_vsnwprintf equivalents. In standard 00454 // builds we can't use _vsnprintf/_vsnwsprintf because they're MS extensions. 00455 // ----------------------------------------------------------------------------- 00456 inline int ssvsprintf(PSTR pA, size_t nCount, PCSTR pFmtA, va_list vl) 00457 { 00458 #if defined(WIN32) 00459 return _vsnprintf(pA, nCount, pFmtA, vl); 00460 #else 00461 return vsnprintf(pA, nCount, pFmtA, vl); 00462 #endif 00463 } 00464 00465 00466 // Now we can define the template (finally!) 00467 // ============================================================================= 00468 // TEMPLATE: CStdStr 00469 // template<typename CT> class CStdStr : public std::basic_string<CT> 00470 // 00471 // REMARKS: 00472 // This template derives from basic_string<CT> and adds some MFC CString- 00473 // like functionality 00474 // 00475 // Basically, this is my attempt to make Standard C++ library strings as 00476 // easy to use as the MFC CString class. 00477 // 00478 // Note that although this is a template, it makes the assumption that the 00479 // template argument (CT, the character type) is either char or wchar_t. 00480 // ============================================================================= 00481 00482 //#define CStdStr _SS // avoid compiler warning 4786 00483 template<typename CT> 00484 class CStdStr; 00485 00486 template<typename CT> 00487 inline 00488 CStdStr<CT> operator+(const CStdStr<CT>& str1, const CStdStr<CT>& str2) 00489 { 00490 CStdStr<CT> strRet(str1); 00491 strRet.append(str2); 00492 return strRet; 00493 } 00494 00495 template<typename CT> 00496 inline 00497 CStdStr<CT> operator+(const CStdStr<CT>& str, CT t) 00498 { 00499 // this particular overload is needed for disabling reference counting 00500 // though it's only an issue from line 1 to line 2 00501 00502 CStdStr<CT> strRet(str); // 1 00503 strRet.append(1, t); // 2 00504 return strRet; 00505 } 00506 00507 template<typename CT> 00508 inline 00509 CStdStr<CT> operator+(const CStdStr<CT>& str, PCSTR pA) 00510 { 00511 return CStdStr<CT>(str) + CStdStr<CT>(pA); 00512 } 00513 00514 template<typename CT> 00515 inline 00516 CStdStr<CT> operator+(PCSTR pA, const CStdStr<CT>& str) 00517 { 00518 CStdStr<CT> strRet(pA); 00519 strRet.append(str); 00520 return strRet; 00521 } 00522 00523 00524 00525 template<typename CT> 00526 class CStdStr : public std::basic_string<CT> 00527 { 00528 // Typedefs for shorter names. Using these names also appears to help 00529 // us avoid some ambiguities that otherwise arise on some platforms 00530 00531 typedef typename std::basic_string<CT> MYBASE; // my base class 00532 typedef CStdStr<CT> MYTYPE; // myself 00533 typedef typename MYBASE::const_pointer PCMYSTR; // PCSTR 00534 typedef typename MYBASE::pointer PMYSTR; // PSTR 00535 typedef typename MYBASE::iterator MYITER; // my iterator type 00536 typedef typename MYBASE::const_iterator MYCITER; // you get the idea... 00537 typedef typename MYBASE::reverse_iterator MYRITER; 00538 typedef typename MYBASE::size_type MYSIZE; 00539 typedef typename MYBASE::value_type MYVAL; 00540 typedef typename MYBASE::allocator_type MYALLOC; 00541 00542 public: 00543 00544 // CStdStr inline constructors 00545 CStdStr() 00546 { 00547 } 00548 00549 CStdStr(const MYTYPE& str) : MYBASE(str) 00550 { 00551 } 00552 00553 CStdStr(const std::string& str) 00554 { 00555 ssasn(*this, str); 00556 } 00557 00558 CStdStr(PCMYSTR pT, MYSIZE n) : MYBASE(pT, n) 00559 { 00560 } 00561 00562 CStdStr(PCSTR pA) 00563 { 00564 *this = pA; 00565 } 00566 00567 CStdStr(MYCITER first, MYCITER last) 00568 : MYBASE(first, last) 00569 { 00570 } 00571 00572 CStdStr(MYSIZE nSize, MYVAL ch, const MYALLOC& al=MYALLOC()) 00573 : MYBASE(nSize, ch, al) 00574 { 00575 } 00576 00577 // CStdStr inline assignment operators -- the ssasn function now takes care 00578 // of fixing the MSVC assignment bug (see knowledge base article Q172398). 00579 MYTYPE& operator=(const MYTYPE& str) 00580 { 00581 ssasn(*this, str); 00582 return *this; 00583 } 00584 00585 MYTYPE& operator=(const std::string& str) 00586 { 00587 ssasn(*this, str); 00588 return *this; 00589 } 00590 00591 MYTYPE& operator=(PCSTR pA) 00592 { 00593 ssasn(*this, pA); 00594 return *this; 00595 } 00596 00597 MYTYPE& operator=(CT t) 00598 { 00599 Q172398(*this); 00600 this->assign(1, t); 00601 return *this; 00602 } 00603 00604 // Overloads also needed to fix the MSVC assignment bug (KB: Q172398) 00605 // *** Thanks to Pete The Plumber for catching this one *** 00606 // They also are compiled if you have explicitly turned off refcounting 00607 #if ( defined(_MSC_VER) && ( _MSC_VER < 1200 ) ) 00608 00609 MYTYPE& assign(const MYTYPE& str) 00610 { 00611 ssasn(*this, str); 00612 return *this; 00613 } 00614 00615 MYTYPE& assign(const MYTYPE& str, MYSIZE nStart, MYSIZE nChars) 00616 { 00617 // This overload of basic_string::assign is supposed to assign up to 00618 // <nChars> or the NULL terminator, whichever comes first. Since we 00619 // are about to call a less forgiving overload (in which <nChars> 00620 // must be a valid length), we must adjust the length here to a safe 00621 // value. Thanks to Ullrich Pollähne for catching this bug 00622 00623 nChars = min(nChars, str.length() - nStart); 00624 00625 // Watch out for assignment to self 00626 00627 if ( this == &str ) 00628 { 00629 MYTYPE strTemp(str.c_str()+nStart, nChars); 00630 MYBASE::assign(strTemp); 00631 } 00632 else 00633 { 00634 Q172398(*this); 00635 MYBASE::assign(str.c_str()+nStart, nChars); 00636 } 00637 return *this; 00638 } 00639 00640 MYTYPE& assign(const MYBASE& str) 00641 { 00642 ssasn(*this, str); 00643 return *this; 00644 } 00645 00646 MYTYPE& assign(const MYBASE& str, MYSIZE nStart, MYSIZE nChars) 00647 { 00648 // This overload of basic_string::assign is supposed to assign up to 00649 // <nChars> or the NULL terminator, whichever comes first. Since we 00650 // are about to call a less forgiving overload (in which <nChars> 00651 // must be a valid length), we must adjust the length here to a safe 00652 // value. Thanks to Ullrich Pollähne for catching this bug 00653 00654 nChars = min(nChars, str.length() - nStart); 00655 00656 // Watch out for assignment to self 00657 00658 if ( this == &str ) // watch out for assignment to self 00659 { 00660 MYTYPE strTemp(str.c_str() + nStart, nChars); 00661 MYBASE::assign(strTemp); 00662 } 00663 else 00664 { 00665 Q172398(*this); 00666 MYBASE::assign(str.c_str()+nStart, nChars); 00667 } 00668 return *this; 00669 } 00670 00671 MYTYPE& assign(const CT* pC, MYSIZE nChars) 00672 { 00673 // Q172398 only fix -- erase before assigning, but not if we're 00674 // assigning from our own buffer 00675 00676 #if defined ( _MSC_VER ) && ( _MSC_VER < 1200 ) 00677 if ( !this->empty() && 00678 ( pC < this->data() || pC > this->data() + this->capacity() ) ) 00679 { 00680 this->erase(); 00681 } 00682 #endif 00683 MYBASE::assign(pC, nChars); 00684 return *this; 00685 } 00686 00687 MYTYPE& assign(MYSIZE nChars, MYVAL val) 00688 { 00689 Q172398(*this); 00690 MYBASE::assign(nChars, val); 00691 return *this; 00692 } 00693 00694 MYTYPE& assign(const CT* pT) 00695 { 00696 return this->assign(pT, MYBASE::traits_type::length(pT)); 00697 } 00698 00699 MYTYPE& assign(MYCITER iterFirst, MYCITER iterLast) 00700 { 00701 #if defined ( _MSC_VER ) && ( _MSC_VER < 1200 ) 00702 // Q172398 fix. don't call erase() if we're assigning from ourself 00703 if ( iterFirst < this->begin() || iterFirst > this->begin() + this->size() ) 00704 this->erase() 00705 #endif 00706 this->replace(this->begin(), this->end(), iterFirst, iterLast); 00707 return *this; 00708 } 00709 #endif 00710 00711 00712 // ------------------------------------------------------------------------- 00713 // CStdStr inline concatenation. 00714 // ------------------------------------------------------------------------- 00715 MYTYPE& operator+=(const MYTYPE& str) 00716 { 00717 ssadd(*this, str); 00718 return *this; 00719 } 00720 00721 MYTYPE& operator+=(const std::string& str) 00722 { 00723 ssadd(*this, str); 00724 return *this; 00725 } 00726 00727 MYTYPE& operator+=(PCSTR pA) 00728 { 00729 ssadd(*this, pA); 00730 return *this; 00731 } 00732 00733 MYTYPE& operator+=(CT t) 00734 { 00735 this->append(1, t); 00736 return *this; 00737 } 00738 00739 00740 // addition operators -- global friend functions. 00741 00742 #if defined(_MSC_VER) && _MSC_VER < 1300 /* VC6, not VC7 */ 00743 /* work around another stupid vc6 bug */ 00744 #define EMP_TEMP 00745 #else 00746 #define EMP_TEMP <> 00747 #endif 00748 friend MYTYPE operator+ EMP_TEMP(const MYTYPE& str1, const MYTYPE& str2); 00749 friend MYTYPE operator+ EMP_TEMP(const MYTYPE& str, CT t); 00750 friend MYTYPE operator+ EMP_TEMP(const MYTYPE& str, PCSTR sz); 00751 friend MYTYPE operator+ EMP_TEMP(PCSTR pA, const MYTYPE& str); 00752 00753 // ------------------------------------------------------------------------- 00754 // Case changing functions 00755 // ------------------------------------------------------------------------- 00756 // ------------------------------------------------------------------------- 00757 MYTYPE& ToUpper() 00758 { 00759 // Strictly speaking, this would be about the most portable way 00760 00761 // std::transform(begin(), 00762 // end(), 00763 // begin(), 00764 // std::bind2nd(SSToUpper<CT>(), std::locale())); 00765 00766 // But practically speaking, this works faster 00767 00768 if ( !this->empty() ) 00769 ssupr(GetBuf(), this->size()); 00770 00771 return *this; 00772 } 00773 00774 00775 00776 MYTYPE& ToLower() 00777 { 00778 // Strictly speaking, this would be about the most portable way 00779 00780 // std::transform(begin(), 00781 // end(), 00782 // begin(), 00783 // std::bind2nd(SSToLower<CT>(), std::locale())); 00784 00785 // But practically speaking, this works faster 00786 00787 if ( !this->empty() ) 00788 sslwr(GetBuf(), this->size()); 00789 00790 return *this; 00791 } 00792 00793 00794 00795 // ------------------------------------------------------------------------- 00796 // CStdStr -- Direct access to character buffer. In the MS' implementation, 00797 // the at() function that we use here also calls _Freeze() providing us some 00798 // protection from multithreading problems associated with ref-counting. 00799 // ------------------------------------------------------------------------- 00800 CT* GetBuf(int nMinLen=-1) 00801 { 00802 if ( static_cast<int>(this->size()) < nMinLen ) 00803 this->resize(static_cast<MYSIZE>(nMinLen)); 00804 00805 return this->empty() ? const_cast<CT*>(this->data()) : &(this->at(0)); 00806 } 00807 00808 void RelBuf(int nNewLen=-1) 00809 { 00810 this->resize(static_cast<MYSIZE>(nNewLen > -1 ? nNewLen : sslen(this->c_str()))); 00811 } 00812 00813 // ------------------------------------------------------------------------- 00814 // FUNCTION: CStdStr::Format 00815 // void _cdecl Formst(CStdStringA& PCSTR szFormat, ...) 00816 // void _cdecl Format(PCSTR szFormat); 00817 // 00818 // DESCRIPTION: 00819 // This function does sprintf/wsprintf style formatting on CStdStringA 00820 // objects. It looks a lot like MFC's CString::Format. Some people 00821 // might even call this identical. Fortunately, these people are now 00822 // dead. 00823 // 00824 // PARAMETERS: 00825 // nId - ID of string resource holding the format string 00826 // szFormat - a PCSTR holding the format specifiers 00827 // argList - a va_list holding the arguments for the format specifiers. 00828 // 00829 // RETURN VALUE: None. 00830 // ------------------------------------------------------------------------- 00831 // formatting (using wsprintf style formatting) 00832 00833 // If they want a Format() function that safely handles string objects 00834 // without casting 00835 00836 00837 void Format(const CT* szFmt, ...) 00838 { 00839 va_list argList; 00840 va_start(argList, szFmt); 00841 FormatV(szFmt, argList); 00842 va_end(argList); 00843 } 00844 00845 #define MAX_FMT_TRIES 5 // #of times we try 00846 #define FMT_BLOCK_SIZE 2048 // # of bytes to increment per try 00847 #define BUFSIZE_1ST 256 00848 #define BUFSIZE_2ND 512 00849 #define STD_BUF_SIZE 1024 00850 00851 // ------------------------------------------------------------------------- 00852 // FUNCTION: FormatV 00853 // void FormatV(PCSTR szFormat, va_list, argList); 00854 // 00855 // DESCRIPTION: 00856 // This function formats the string with sprintf style format-specs. 00857 // It makes a general guess at required buffer size and then tries 00858 // successively larger buffers until it finds one big enough or a 00859 // threshold (MAX_FMT_TRIES) is exceeded. 00860 // 00861 // PARAMETERS: 00862 // szFormat - a PCSTR holding the format of the output 00863 // argList - a Microsoft specific va_list for variable argument lists 00864 // 00865 // RETURN VALUE: 00866 // ------------------------------------------------------------------------- 00867 00868 void FormatV(const CT* szFormat, va_list argList) 00869 { 00870 #if defined(WIN32) 00871 CT* pBuf = NULL; 00872 int nChars = 1; 00873 int nUsed = 0; 00874 size_type nActual = 0; 00875 int nTry = 0; 00876 00877 do 00878 { 00879 // Grow more than linearly (e.g. 512, 1536, 3072, etc) 00880 00881 nChars += ((nTry+1) * FMT_BLOCK_SIZE); 00882 pBuf = reinterpret_cast<CT*>(_alloca(sizeof(CT)*nChars)); 00883 nUsed = ssvsprintf(pBuf, nChars-1, szFormat, argList); 00884 00885 // Ensure proper NULL termination. 00886 00887 nActual = nUsed == -1 ? nChars-1 : min(nUsed, nChars-1); 00888 pBuf[nActual+1]= '\0'; 00889 } while ( nUsed < 0 && nTry++ < MAX_FMT_TRIES ); 00890 00891 // assign whatever we managed to format 00892 00893 this->assign(pBuf, nActual); 00894 #else 00895 static bool bExactSizeSupported; 00896 static bool bInitialized = false; 00897 if( !bInitialized ) 00898 { 00899 /* Some systems return the actual size required when snprintf 00900 * doesn't have enough space. This lets us avoid wasting time 00901 * iterating, and wasting memory. */ 00902 bInitialized = true; 00903 char ignore; 00904 bExactSizeSupported = ( snprintf( &ignore, 0, "Hello World" ) == 11 ); 00905 } 00906 00907 if( bExactSizeSupported ) 00908 { 00909 va_list tmp; 00910 va_copy( tmp, argList ); 00911 char ignore; 00912 int iNeeded = ssvsprintf( &ignore, 0, szFormat, tmp ); 00913 va_end(tmp); 00914 00915 char *buf = GetBuffer( iNeeded+1 ); 00916 ssvsprintf( buf, iNeeded+1, szFormat, argList ); 00917 ReleaseBuffer( iNeeded ); 00918 return; 00919 } 00920 00921 int nChars = FMT_BLOCK_SIZE; 00922 int nTry = 1; 00923 do 00924 { 00925 // Grow more than linearly (e.g. 512, 1536, 3072, etc) 00926 char *buf = GetBuffer(nChars); 00927 int nUsed = ssvsprintf(buf, nChars-1, szFormat, argList); 00928 00929 if(nUsed == -1) 00930 { 00931 nChars += ((nTry+1) * FMT_BLOCK_SIZE); 00932 ReleaseBuffer(); 00933 continue; 00934 } 00935 00936 /* OK */ 00937 ReleaseBuffer(nUsed); 00938 break; 00939 } while ( nTry++ < MAX_FMT_TRIES ); 00940 #endif 00941 } 00942 00943 00944 // ------------------------------------------------------------------------- 00945 // CString Facade Functions: 00946 // 00947 // The following methods are intended to allow you to use this class as a 00948 // drop-in replacement for CString. 00949 // ------------------------------------------------------------------------- 00950 int CompareNoCase(PCMYSTR szThat) const 00951 { 00952 return ssicmp(this->c_str(), szThat); 00953 } 00954 00955 int Find(CT ch) const 00956 { 00957 MYSIZE nIdx = this->find_first_of(ch); 00958 return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx); 00959 } 00960 00961 int Find(PCMYSTR szSub) const 00962 { 00963 MYSIZE nIdx = this->find(szSub); 00964 return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx); 00965 } 00966 00967 int Find(CT ch, int nStart) const 00968 { 00969 // CString::Find docs say add 1 to nStart when it's not zero 00970 // CString::Find code doesn't do that however. We'll stick 00971 // with what the code does 00972 00973 MYSIZE nIdx = this->find_first_of(ch, static_cast<MYSIZE>(nStart)); 00974 return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx); 00975 } 00976 00977 int Find(PCMYSTR szSub, int nStart) const 00978 { 00979 // CString::Find docs say add 1 to nStart when it's not zero 00980 // CString::Find code doesn't do that however. We'll stick 00981 // with what the code does 00982 00983 MYSIZE nIdx = this->find(szSub, static_cast<MYSIZE>(nStart)); 00984 return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx); 00985 } 00986 00987 // ------------------------------------------------------------------------- 00988 // GetXXXX -- Direct access to character buffer 00989 // ------------------------------------------------------------------------- 00990 CT* GetBuffer(int nMinLen=-1) 00991 { 00992 return GetBuf(nMinLen); 00993 } 00994 00995 // GetLength() -- MFC docs say this is the # of BYTES but 00996 // in truth it is the number of CHARACTERs (chars or wchar_ts) 00997 int GetLength() const 00998 { 00999 return static_cast<int>(this->length()); 01000 } 01001 01002 01003 int Insert(int nIdx, CT ch) 01004 { 01005 if ( static_cast<MYSIZE>(nIdx) > this->size() -1 ) 01006 this->append(1, ch); 01007 else 01008 this->insert(static_cast<MYSIZE>(nIdx), 1, ch); 01009 01010 return GetLength(); 01011 } 01012 int Insert(int nIdx, PCMYSTR sz) 01013 { 01014 if ( nIdx >= this->size() ) 01015 this->append(sz, sslen(sz)); 01016 else 01017 this->insert(static_cast<MYSIZE>(nIdx), sz); 01018 01019 return GetLength(); 01020 } 01021 01022 MYTYPE Left(int nCount) const 01023 { 01024 // Range check the count. 01025 01026 nCount = max(0, min(nCount, static_cast<int>(this->size()))); 01027 return this->substr(0, static_cast<MYSIZE>(nCount)); 01028 } 01029 01030 void MakeLower() 01031 { 01032 ToLower(); 01033 } 01034 01035 void MakeReverse() 01036 { 01037 std::reverse(this->begin(), this->end()); 01038 } 01039 01040 void MakeUpper() 01041 { 01042 ToUpper(); 01043 } 01044 01045 void ReleaseBuffer(int nNewLen=-1) 01046 { 01047 RelBuf(nNewLen); 01048 } 01049 01050 int Remove(CT ch) 01051 { 01052 MYSIZE nIdx = 0; 01053 int nRemoved = 0; 01054 while ( (nIdx=this->find_first_of(ch)) != MYBASE::npos ) 01055 { 01056 this->erase(nIdx, 1); 01057 nRemoved++; 01058 } 01059 return nRemoved; 01060 } 01061 01062 int Replace(CT chOld, CT chNew) 01063 { 01064 int nReplaced = 0; 01065 for ( MYITER iter=this->begin(); iter != this->end(); iter++ ) 01066 { 01067 if ( *iter == chOld ) 01068 { 01069 *iter = chNew; 01070 nReplaced++; 01071 } 01072 } 01073 return nReplaced; 01074 } 01075 01076 int Replace(PCMYSTR szOld, PCMYSTR szNew) 01077 { 01078 int nReplaced = 0; 01079 MYSIZE nIdx = 0; 01080 MYSIZE nOldLen = sslen(szOld); 01081 if ( 0 == nOldLen ) 01082 return 0; 01083 01084 static const CT ch = CT(0); 01085 MYSIZE nNewLen = sslen(szNew); 01086 PCMYSTR szRealNew = szNew == 0 ? &ch : szNew; 01087 01088 while ( (nIdx=this->find(szOld, nIdx)) != MYBASE::npos ) 01089 { 01090 replace(this->begin()+nIdx, this->begin()+nIdx+nOldLen, szRealNew); 01091 nReplaced++; 01092 nIdx += nNewLen; 01093 } 01094 return nReplaced; 01095 } 01096 01097 int ReverseFind(CT ch) const 01098 { 01099 MYSIZE nIdx = this->find_last_of(ch); 01100 return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx); 01101 } 01102 01103 MYTYPE Right(int nCount) const 01104 { 01105 // Range check the count. 01106 01107 nCount = max(0, min(nCount, static_cast<int>(this->size()))); 01108 return this->substr(this->size()-static_cast<MYSIZE>(nCount)); 01109 } 01110 01111 // Array-indexing operators. Required because we defined an implicit cast 01112 // to operator const CT* (Thanks to Julian Selman for pointing this out) 01113 CT& operator[](int nIdx) 01114 { 01115 return MYBASE::operator[](static_cast<MYSIZE>(nIdx)); 01116 } 01117 01118 const CT& operator[](int nIdx) const 01119 { 01120 return MYBASE::operator[](static_cast<MYSIZE>(nIdx)); 01121 } 01122 01123 CT& operator[](unsigned int nIdx) 01124 { 01125 return MYBASE::operator[](static_cast<MYSIZE>(nIdx)); 01126 } 01127 01128 const CT& operator[](unsigned int nIdx) const 01129 { 01130 return MYBASE::operator[](static_cast<MYSIZE>(nIdx)); 01131 } 01132 01133 CT& operator[](long unsigned int nIdx){ 01134 return MYBASE::operator[](static_cast<MYSIZE>(nIdx)); 01135 } 01136 01137 const CT& operator[](long unsigned int nIdx) const { 01138 return MYBASE::operator[](static_cast<MYSIZE>(nIdx)); 01139 } 01140 #ifndef SS_NO_IMPLICIT_CASTS 01141 operator const CT*() const 01142 { 01143 return this->c_str(); 01144 } 01145 #endif 01146 }; 01147 01148 01149 01150 // ----------------------------------------------------------------------------- 01151 // CStdStr friend addition functions defined as inline 01152 // ----------------------------------------------------------------------------- 01153 01154 01155 01156 01157 // ----------------------------------------------------------------------------- 01158 // These versions of operator+ provided by Scott Hathaway in order to allow 01159 // CStdString to build on Sun Unix systems. 01160 // ----------------------------------------------------------------------------- 01161 01162 #if defined(__SUNPRO_CC_COMPAT) || defined(__SUNPRO_CC) 01163 01164 inline 01165 CStdStr<char> operator+(const CStdStr<char>& str1, const CStdStr<char>& str2) 01166 { 01167 CStdStr<char> strRet(str1); 01168 strRet.append(str2); 01169 return strRet; 01170 } 01171 01172 inline 01173 CStdStr<char> operator+(const CStdStr<char>& str, char t) 01174 { 01175 // this particular overload is needed for disabling reference counting 01176 // though it's only an issue from line 1 to line 2 01177 01178 CStdStr<char> strRet(str); // 1 01179 strRet.append(1, t); // 2 01180 return strRet; 01181 } 01182 01183 inline 01184 CStdStr<char> operator+(const CStdStr<char>& str, PCSTR pA) 01185 { 01186 return CStdStr<char>(str) + CStdStr<char>(pA); 01187 } 01188 01189 inline 01190 CStdStr<char> operator+(PCSTR pA, const CStdStr<char>& str) 01191 { 01192 CStdStr<char> strRet(pA); 01193 strRet.append(str); 01194 return strRet; 01195 } 01196 01197 #endif // defined(__SUNPRO_CC_COMPAT) || defined(__SUNPRO_CC) 01198 01199 01200 // ============================================================================= 01201 // END OF CStdStr INLINE FUNCTION DEFINITIONS 01202 // ============================================================================= 01203 01204 // Now typedef our class names based upon this humongous template 01205 01206 typedef CStdStr<char> CStdStringA; // a better std::string 01207 01208 01209 01210 // ----------------------------------------------------------------------------- 01211 // HOW TO EXPORT CSTDSTRING FROM A DLL 01212 // 01213 // If you want to export CStdStringA and CStdStringW from a DLL, then all you 01214 // need to 01215 // 1. make sure that all components link to the same DLL version 01216 // of the CRT (not the static one). 01217 // 2. Uncomment the 3 lines of code below 01218 // 3. #define 2 macros per the instructions in MS KnowledgeBase 01219 // article Q168958. The macros are: 01220 // 01221 // MACRO DEFINTION WHEN EXPORTING DEFINITION WHEN IMPORTING 01222 // ----- ------------------------ ------------------------- 01223 // SSDLLEXP (nothing, just #define it) extern 01224 // SSDLLSPEC __declspec(dllexport) __declspec(dllimport) 01225 // 01226 // Note that these macros must be available to ALL clients who want to 01227 // link to the DLL and use the class. If they 01228 // ----------------------------------------------------------------------------- 01229 //#pragma warning(disable:4231) // non-standard extension ("extern template") 01230 // SSDLLEXP template class SSDLLSPEC CStdStr<char>; 01231 // SSDLLEXP template class SSDLLSPEC CStdStr<wchar_t>; 01232 01233 01234 // In MFC builds, define some global serialization operators 01235 // Special operators that allow us to serialize CStdStrings to CArchives. 01236 // Note that we use an intermediate CString object in order to ensure that 01237 // we use the exact same format. 01238 01239 #ifdef _MFC_VER 01240 inline CArchive& AFXAPI operator<<(CArchive& ar, const CStdStringA& strA) 01241 { 01242 CString strTemp = strA; 01243 return ar << strTemp; 01244 } 01245 01246 inline CArchive& AFXAPI operator>>(CArchive& ar, CStdStringA& strA) 01247 { 01248 CString strTemp; 01249 ar >> strTemp; 01250 strA = strTemp; 01251 return ar; 01252 } 01253 #endif // #ifdef _MFC_VER -- (i.e. is this MFC?) 01254 01255 // Define friendly names for some of these functions 01256 01257 #define CStdString CStdStringA 01258 01259 // ...and some shorter names for the space-efficient 01260 01261 #define WUFmtA WUFormatA 01262 #define WUFmtW WUFormatW 01263 #define WUFmt WUFormat 01264 01265 01266 // ----------------------------------------------------------------------------- 01267 // FUNCTIONAL COMPARATORS: 01268 // REMARKS: 01269 // These structs are derived from the std::binary_function template. They 01270 // give us functional classes (which may be used in Standard C++ Library 01271 // collections and algorithms) that perform case-insensitive comparisons of 01272 // CStdString objects. This is useful for maps in which the key may be the 01273 // proper string but in the wrong case. 01274 // ----------------------------------------------------------------------------- 01275 #define StdStringLessNoCaseW SSLNCW // avoid VC compiler warning 4786 01276 #define StdStringEqualsNoCaseW SSENCW 01277 #define StdStringLessNoCaseA SSLNCA 01278 #define StdStringEqualsNoCaseA SSENCA 01279 01280 #define StdStringLessNoCase SSLNCA 01281 #define StdStringEqualsNoCase SSENCA 01282 01283 struct StdStringLessNoCaseA 01284 : std::binary_function<CStdStringA, CStdStringA, bool> 01285 { 01286 inline 01287 bool operator()(const CStdStringA& sLeft, const CStdStringA& sRight) const 01288 { return ssicmp(sLeft.c_str(), sRight.c_str()) < 0; } 01289 }; 01290 struct StdStringEqualsNoCaseA 01291 : std::binary_function<CStdStringA, CStdStringA, bool> 01292 { 01293 inline 01294 bool operator()(const CStdStringA& sLeft, const CStdStringA& sRight) const 01295 { return ssicmp(sLeft.c_str(), sRight.c_str()) == 0; } 01296 }; 01297 01298 // These std::swap specializations come courtesy of Mike Crusader. 01299 01300 //namespace std 01301 //{ 01302 // inline void swap(CStdStringA& s1, CStdStringA& s2) throw() 01303 // { 01304 // s1.swap(s2); 01305 // } 01306 //} 01307 01308 #if defined(_MSC_VER) && (_MSC_VER > 1100) 01309 #pragma warning (pop) 01310 #endif 01311 01312 #define CString CStdString 01313 #define CStringArray vector<CString> 01314 01315 #endif // #ifndef STDSTRING_H

Generated on Thu Jan 27 20:57:34 2005 for StepMania by doxygen 1.3.7