2 Copyright (c) 2001, Loki software, inc.
5 Redistribution and use in source and binary forms, with or without modification,
6 are permitted provided that the following conditions are met:
8 Redistributions of source code must retain the above copyright notice, this list
9 of conditions and the following disclaimer.
11 Redistributions in binary form must reproduce the above copyright notice, this
12 list of conditions and the following disclaimer in the documentation and/or
13 other materials provided with the distribution.
15 Neither the name of Loki software nor the names of its contributors may be used
16 to endorse or promote products derived from this software without specific prior
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
20 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
23 DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
26 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 // loose replacement for CString from MFC
48 #define strcasecmp strcmpi
50 #define vsnprintf std::vsnprintf
56 // NOTE TTimo __StrDup was initially implemented in pakstuff.cpp
57 // causing a bunch of issues for broader targets that use Str.h (such as plugins and modules)
58 // Q_StrDup should be used now, using a #define __StrDup for easy transition
60 #define __StrDup Q_StrDup
62 inline char* Q_StrDup( const char* pStr ){
67 return strcpy( new char[strlen( pStr ) + 1], pStr );
71 #define strcmpi strcasecmp
72 #define stricmp strcasecmp
73 #define strnicmp strncasecmp
75 inline char* strlwr( char* string ){
77 for ( cp = string; *cp; ++cp )
79 if ( 'A' <= *cp && *cp <= 'Z' ) {
87 inline char* strupr( char* string ){
89 for ( cp = string; *cp; ++cp )
91 if ( 'a' <= *cp && *cp <= 'z' ) {
100 static char *g_pStrWork = 0;
110 m_bIgnoreCase = true;
111 m_pStr = new char[1];
116 m_bIgnoreCase = true;
117 m_pStr = __StrDup( p );
120 Str( const char *p ){
121 m_bIgnoreCase = true;
122 m_pStr = __StrDup( p );
125 Str( const unsigned char *p ){
126 m_bIgnoreCase = true;
127 m_pStr = __StrDup( reinterpret_cast<const char *>( p ) );
131 m_bIgnoreCase = true;
132 m_pStr = new char[2];
137 const char* GetBuffer() const {
146 m_bIgnoreCase = true;
147 m_pStr = __StrDup( s.GetBuffer() );
155 void Allocate( std::size_t n ){
157 m_pStr = new char[n];
162 m_pStr = __StrDup( "" );
167 // NOTE TTimo: someone explain this g_pStrWork to me?
189 while ( *lpsz != '\0' )
191 if ( isspace( *lpsz ) ) {
192 if ( lpszLast == 0 ) {
202 if ( lpszLast != 0 ) {
203 // truncate at trailing space start
209 // find first non-space character
211 while ( isspace( *lpsz ) )
214 // fix up data and length
215 std::size_t nDataLength = GetLength() - ( lpsz - m_pStr );
216 memmove( m_pStr, lpsz, ( nDataLength + 1 ) );
219 char* Find( const char *p ){
220 return strstr( m_pStr, p );
223 // search starting at a given offset
224 char* Find( const char *p, std::size_t offset ){
225 return strstr( m_pStr + offset, p );
228 char* Find( const char ch ){
229 return strchr( m_pStr, ch );
232 char* ReverseFind( const char ch ){
233 return strrchr( m_pStr, ch );
236 int Compare( const char* str ) const {
237 return strcmp( m_pStr, str );
240 int CompareNoCase( const char* str ) const {
241 return strcasecmp( m_pStr, str );
244 std::size_t GetLength(){
245 return ( m_pStr ) ? strlen( m_pStr ) : 0;
248 const char* Left( std::size_t n ){
251 g_pStrWork = new char[n + 1];
252 strncpy( g_pStrWork, m_pStr, n );
253 g_pStrWork[n] = '\0';
257 g_pStrWork = new char[1];
258 g_pStrWork[0] = '\0';
263 const char* Right( std::size_t n ){
266 g_pStrWork = new char[n + 1];
267 std::size_t nStart = GetLength() - n;
268 strncpy( g_pStrWork, &m_pStr[nStart], n );
269 g_pStrWork[n] = '\0';
273 g_pStrWork = new char[1];
274 g_pStrWork[0] = '\0';
279 const char* Mid( std::size_t nFirst ) const {
280 return Mid( nFirst, strlen( m_pStr ) - nFirst );
283 const char* Mid( std::size_t first, std::size_t n ) const {
286 g_pStrWork = new char[n + 1];
287 strncpy( g_pStrWork, m_pStr + first, n );
288 g_pStrWork[n] = '\0';
292 g_pStrWork = new char[1];
293 g_pStrWork[0] = '\0';
298 #if 0 // defined(__G_LIB_H__)
299 void Format( const char* fmt, ... ){
303 va_start( args, fmt );
304 buffer = g_strdup_vprintf( fmt, args );
308 m_pStr = __StrDup( buffer );
312 void Format( const char* fmt, ... ){
317 va_start( args, fmt );
318 vsnprintf( buffer, 1023, fmt, args );
323 m_pStr = __StrDup( buffer );
327 void SetAt( std::size_t n, char ch ){
328 if ( n < GetLength() ) {
333 // NOTE: unlike CString, this looses the pointer
334 void ReleaseBuffer( std::size_t n ){
337 m_pStr = __StrDup( tmp );
340 void ReleaseBuffer(){
341 ReleaseBuffer( GetLength() );
344 char* GetBufferSetLength( std::size_t n ){
345 char *p = new char[n + 1];
346 strncpy( p, m_pStr, n );
353 // char& operator *() { return *m_pStr; }
354 // char& operator *() const { return *const_cast<Str*>(this)->m_pStr; }
361 operator const char*() const { return reinterpret_cast<const char*>( m_pStr ); }
362 operator unsigned char*() {
363 return reinterpret_cast<unsigned char*>( m_pStr );
365 operator const unsigned char*() const { return reinterpret_cast<const unsigned char*>( m_pStr ); }
366 Str& operator =( const Str& rhs ){
367 if ( &rhs != this ) {
369 m_pStr = __StrDup( rhs.m_pStr );
374 Str& operator =( const char* pStr ){
375 if ( m_pStr != pStr ) {
377 m_pStr = __StrDup( pStr );
382 Str& operator +=( const char ch ){
383 std::size_t len = GetLength();
384 char *p = new char[len + 1 + 1];
393 m_pStr[len + 1] = '\0';
398 Str& operator +=( const char *pStr ){
401 char *p = new char[strlen( m_pStr ) + strlen( pStr ) + 1];
409 m_pStr = __StrDup( pStr );
416 bool operator ==( const Str& rhs ) const { return ( m_bIgnoreCase ) ? stricmp( m_pStr, rhs.m_pStr ) == 0 : strcmp( m_pStr, rhs.m_pStr ) == 0; }
417 bool operator ==( char* pStr ) const { return ( m_bIgnoreCase ) ? stricmp( m_pStr, pStr ) == 0 : strcmp( m_pStr, pStr ) == 0; }
418 bool operator ==( const char* pStr ) const { return ( m_bIgnoreCase ) ? stricmp( m_pStr, pStr ) == 0 : strcmp( m_pStr, pStr ) == 0; }
419 bool operator !=( Str& rhs ) const { return ( m_bIgnoreCase ) ? stricmp( m_pStr, rhs.m_pStr ) != 0 : strcmp( m_pStr, rhs.m_pStr ) != 0; }
420 bool operator !=( char* pStr ) const { return ( m_bIgnoreCase ) ? stricmp( m_pStr, pStr ) != 0 : strcmp( m_pStr, pStr ) != 0; }
421 bool operator !=( const char* pStr ) const { return ( m_bIgnoreCase ) ? stricmp( m_pStr, pStr ) != 0 : strcmp( m_pStr, pStr ) != 0; }
422 bool operator <( const Str& rhs ) const { return ( m_bIgnoreCase ) ? stricmp( m_pStr, rhs.m_pStr ) < 0 : strcmp( m_pStr, rhs.m_pStr ) < 0; }
423 bool operator <( char* pStr ) const { return ( m_bIgnoreCase ) ? stricmp( m_pStr, pStr ) < 0 : strcmp( m_pStr, pStr ) < 0; }
424 bool operator <( const char* pStr ) const { return ( m_bIgnoreCase ) ? stricmp( m_pStr, pStr ) < 0 : strcmp( m_pStr, pStr ) < 0; }
425 bool operator >( const Str& rhs ) const { return ( m_bIgnoreCase ) ? stricmp( m_pStr, rhs.m_pStr ) > 0 : strcmp( m_pStr, rhs.m_pStr ) > 0; }
426 bool operator >( char* pStr ) const { return ( m_bIgnoreCase ) ? stricmp( m_pStr, pStr ) > 0 : strcmp( m_pStr, pStr ) > 0; }
427 bool operator >( const char* pStr ) const { return ( m_bIgnoreCase ) ? stricmp( m_pStr, pStr ) > 0 : strcmp( m_pStr, pStr ) > 0; }
428 char& operator []( std::size_t nIndex ) { return m_pStr[nIndex]; }
429 const char& operator []( std::size_t nIndex ) const { return m_pStr[nIndex]; }
430 char GetAt( std::size_t nIndex ) { return m_pStr[nIndex]; }
434 template<typename TextOutputStreamType>
435 inline TextOutputStreamType& ostream_write( TextOutputStreamType& ostream, const Str& str ){
436 return ostream << str.GetBuffer();
440 inline void AddSlash( Str& strPath ){
441 if ( strPath.GetLength() > 0 ) {
442 if ( ( strPath.GetAt( strPath.GetLength() - 1 ) != '/' ) &&
443 ( strPath.GetAt( strPath.GetLength() - 1 ) != '\\' ) ) {
449 inline bool ExtractPath_and_Filename( const char* pPath, Str& strPath, Str& strFilename ){
452 const char* substr = strPathName.ReverseFind( '\\' );
454 // TTimo: try forward slash, some are using forward
455 substr = strPathName.ReverseFind( '/' );
458 std::size_t nSlash = substr - strPathName.GetBuffer();
459 strPath = strPathName.Left( nSlash + 1 );
460 strFilename = strPathName.Right( strPathName.GetLength() - nSlash - 1 );