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.
34 #include "globaldefs.h"
38 // loose replacement for CString from MFC
49 #if GDEF_COMPILER_MSVC
50 #define strcasecmp strcmpi
52 #define vsnprintf std::vsnprintf
58 // NOTE TTimo __StrDup was initially implemented in pakstuff.cpp
59 // causing a bunch of issues for broader targets that use Str.h (such as plugins and modules)
60 // Q_StrDup should be used now, using a #define __StrDup for easy transition
62 #define __StrDup Q_StrDup
64 inline char* Q_StrDup( const char* pStr ){
69 return strcpy( new char[strlen( pStr ) + 1], pStr );
73 #define strcmpi strcasecmp
74 #define stricmp strcasecmp
75 #define strnicmp strncasecmp
77 inline char* strlwr( char* string ){
79 for ( cp = string; *cp; ++cp )
81 if ( 'A' <= *cp && *cp <= 'Z' ) {
89 inline char* strupr( char* string ){
91 for ( cp = string; *cp; ++cp )
93 if ( 'a' <= *cp && *cp <= 'z' ) {
102 static char *g_pStrWork = 0;
112 m_bIgnoreCase = true;
113 m_pStr = new char[1];
118 m_bIgnoreCase = true;
119 m_pStr = __StrDup( p );
122 Str( const char *p ){
123 m_bIgnoreCase = true;
124 m_pStr = __StrDup( p );
127 Str( const unsigned char *p ){
128 m_bIgnoreCase = true;
129 m_pStr = __StrDup( reinterpret_cast<const char *>( p ) );
133 m_bIgnoreCase = true;
134 m_pStr = new char[2];
139 const char* GetBuffer() const {
148 m_bIgnoreCase = true;
149 m_pStr = __StrDup( s.GetBuffer() );
157 void Allocate( std::size_t n ){
159 m_pStr = new char[n];
164 m_pStr = __StrDup( "" );
169 // NOTE TTimo: someone explain this g_pStrWork to me?
191 while ( *lpsz != '\0' )
193 if ( isspace( *lpsz ) ) {
194 if ( lpszLast == 0 ) {
204 if ( lpszLast != 0 ) {
205 // truncate at trailing space start
211 // find first non-space character
213 while ( isspace( *lpsz ) )
216 // fix up data and length
217 std::size_t nDataLength = GetLength() - ( lpsz - m_pStr );
218 memmove( m_pStr, lpsz, ( nDataLength + 1 ) );
221 char* Find( const char *p ){
222 return strstr( m_pStr, p );
225 // search starting at a given offset
226 char* Find( const char *p, std::size_t offset ){
227 return strstr( m_pStr + offset, p );
230 char* Find( const char ch ){
231 return strchr( m_pStr, ch );
234 char* ReverseFind( const char ch ){
235 return strrchr( m_pStr, ch );
238 int Compare( const char* str ) const {
239 return strcmp( m_pStr, str );
242 int CompareNoCase( const char* str ) const {
243 return strcasecmp( m_pStr, str );
246 std::size_t GetLength(){
247 return ( m_pStr ) ? strlen( m_pStr ) : 0;
250 const char* Left( std::size_t n ){
253 g_pStrWork = new char[n + 1];
254 strncpy( g_pStrWork, m_pStr, n );
255 g_pStrWork[n] = '\0';
259 g_pStrWork = new char[1];
260 g_pStrWork[0] = '\0';
265 const char* Right( std::size_t n ){
268 g_pStrWork = new char[n + 1];
269 std::size_t nStart = GetLength() - n;
270 strncpy( g_pStrWork, &m_pStr[nStart], n );
271 g_pStrWork[n] = '\0';
275 g_pStrWork = new char[1];
276 g_pStrWork[0] = '\0';
281 const char* Mid( std::size_t nFirst ) const {
282 return Mid( nFirst, strlen( m_pStr ) - nFirst );
285 const char* Mid( std::size_t first, std::size_t n ) const {
288 g_pStrWork = new char[n + 1];
289 strncpy( g_pStrWork, m_pStr + first, n );
290 g_pStrWork[n] = '\0';
294 g_pStrWork = new char[1];
295 g_pStrWork[0] = '\0';
300 #if 0 // defined(__G_LIB_H__)
301 void Format( const char* fmt, ... ){
305 va_start( args, fmt );
306 buffer = g_strdup_vprintf( fmt, args );
310 m_pStr = __StrDup( buffer );
314 void Format( const char* fmt, ... ){
319 va_start( args, fmt );
320 vsnprintf( buffer, 1023, fmt, args );
325 m_pStr = __StrDup( buffer );
329 void SetAt( std::size_t n, char ch ){
330 if ( n < GetLength() ) {
335 // NOTE: unlike CString, this looses the pointer
336 void ReleaseBuffer( std::size_t n ){
339 m_pStr = __StrDup( tmp );
342 void ReleaseBuffer(){
343 ReleaseBuffer( GetLength() );
346 char* GetBufferSetLength( std::size_t n ){
347 char *p = new char[n + 1];
348 strncpy( p, m_pStr, n );
355 // char& operator *() { return *m_pStr; }
356 // char& operator *() const { return *const_cast<Str*>(this)->m_pStr; }
363 operator const char*() const { return reinterpret_cast<const char*>( m_pStr ); }
364 operator unsigned char*() {
365 return reinterpret_cast<unsigned char*>( m_pStr );
367 operator const unsigned char*() const { return reinterpret_cast<const unsigned char*>( m_pStr ); }
368 Str& operator =( const Str& rhs ){
369 if ( &rhs != this ) {
371 m_pStr = __StrDup( rhs.m_pStr );
376 Str& operator =( const char* pStr ){
377 if ( m_pStr != pStr ) {
379 m_pStr = __StrDup( pStr );
384 Str& operator +=( const char ch ){
385 std::size_t len = GetLength();
386 char *p = new char[len + 1 + 1];
395 m_pStr[len + 1] = '\0';
400 Str& operator +=( const char *pStr ){
403 char *p = new char[strlen( m_pStr ) + strlen( pStr ) + 1];
411 m_pStr = __StrDup( pStr );
418 bool operator ==( const Str& rhs ) const { return ( m_bIgnoreCase ) ? stricmp( m_pStr, rhs.m_pStr ) == 0 : strcmp( m_pStr, rhs.m_pStr ) == 0; }
419 bool operator ==( char* pStr ) const { return ( m_bIgnoreCase ) ? stricmp( m_pStr, pStr ) == 0 : strcmp( m_pStr, pStr ) == 0; }
420 bool operator ==( const char* pStr ) const { return ( m_bIgnoreCase ) ? stricmp( m_pStr, pStr ) == 0 : strcmp( m_pStr, pStr ) == 0; }
421 bool operator !=( Str& rhs ) const { return ( m_bIgnoreCase ) ? stricmp( m_pStr, rhs.m_pStr ) != 0 : strcmp( m_pStr, rhs.m_pStr ) != 0; }
422 bool operator !=( char* pStr ) const { return ( m_bIgnoreCase ) ? stricmp( m_pStr, pStr ) != 0 : strcmp( m_pStr, pStr ) != 0; }
423 bool operator !=( const char* pStr ) const { return ( m_bIgnoreCase ) ? stricmp( m_pStr, pStr ) != 0 : strcmp( m_pStr, pStr ) != 0; }
424 bool operator <( const Str& rhs ) const { return ( m_bIgnoreCase ) ? stricmp( m_pStr, rhs.m_pStr ) < 0 : strcmp( m_pStr, rhs.m_pStr ) < 0; }
425 bool operator <( char* pStr ) const { return ( m_bIgnoreCase ) ? stricmp( m_pStr, pStr ) < 0 : strcmp( m_pStr, pStr ) < 0; }
426 bool operator <( const char* pStr ) const { return ( m_bIgnoreCase ) ? stricmp( m_pStr, pStr ) < 0 : strcmp( m_pStr, pStr ) < 0; }
427 bool operator >( const Str& rhs ) const { return ( m_bIgnoreCase ) ? stricmp( m_pStr, rhs.m_pStr ) > 0 : strcmp( m_pStr, rhs.m_pStr ) > 0; }
428 bool operator >( char* pStr ) const { return ( m_bIgnoreCase ) ? stricmp( m_pStr, pStr ) > 0 : strcmp( m_pStr, pStr ) > 0; }
429 bool operator >( const char* pStr ) const { return ( m_bIgnoreCase ) ? stricmp( m_pStr, pStr ) > 0 : strcmp( m_pStr, pStr ) > 0; }
430 char& operator []( std::size_t nIndex ) { return m_pStr[nIndex]; }
431 const char& operator []( std::size_t nIndex ) const { return m_pStr[nIndex]; }
432 char GetAt( std::size_t nIndex ) { return m_pStr[nIndex]; }
436 template<typename TextOutputStreamType>
437 inline TextOutputStreamType& ostream_write( TextOutputStreamType& ostream, const Str& str ){
438 return ostream << str.GetBuffer();
442 inline void AddSlash( Str& strPath ){
443 if ( strPath.GetLength() > 0 ) {
444 if ( ( strPath.GetAt( strPath.GetLength() - 1 ) != '/' ) &&
445 ( strPath.GetAt( strPath.GetLength() - 1 ) != '\\' ) ) {
451 inline bool ExtractPath_and_Filename( const char* pPath, Str& strPath, Str& strFilename ){
454 const char* substr = strPathName.ReverseFind( '\\' );
456 // TTimo: try forward slash, some are using forward
457 substr = strPathName.ReverseFind( '/' );
460 std::size_t nSlash = substr - strPathName.GetBuffer();
461 strPath = strPathName.Left( nSlash + 1 );
462 strFilename = strPathName.Right( strPathName.GetLength() - nSlash - 1 );