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';
258 g_pStrWork = new char[1];
259 g_pStrWork[0] = '\0';
264 const char* Right( std::size_t n ){
267 g_pStrWork = new char[n + 1];
268 std::size_t nStart = GetLength() - n;
269 strncpy( g_pStrWork, &m_pStr[nStart], n );
270 g_pStrWork[n] = '\0';
274 g_pStrWork = new char[1];
275 g_pStrWork[0] = '\0';
280 const char* Mid( std::size_t nFirst ) const {
281 return Mid( nFirst, strlen( m_pStr ) - nFirst );
284 const char* Mid( std::size_t first, std::size_t n ) const {
287 g_pStrWork = new char[n + 1];
288 strncpy( g_pStrWork, m_pStr + first, n );
289 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 const 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 );