]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - libs/str.h
uncrustify! now the code is only ugly on the *inside*
[xonotic/netradiant.git] / libs / str.h
1 /*
2    Copyright (c) 2001, Loki software, inc.
3    All rights reserved.
4
5    Redistribution and use in source and binary forms, with or without modification,
6    are permitted provided that the following conditions are met:
7
8    Redistributions of source code must retain the above copyright notice, this list
9    of conditions and the following disclaimer.
10
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.
14
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
17    written permission.
18
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.
29  */
30
31 #ifndef __STR__
32 #define __STR__
33
34 //
35 // class Str
36 // loose replacement for CString from MFC
37 //
38
39 #include <string.h>
40 #include <ctype.h>
41 #include <stdarg.h>
42
43 #ifdef __APPLE__
44   #ifdef NULL
45         #undef NULL
46         #define NULL 0
47   #endif
48 #endif
49
50
51 #ifdef _WIN32
52 #define strcasecmp strcmpi
53 #endif
54
55 // NOTE TTimo __StrDup was initially implemented in pakstuff.cpp
56 //   causing a bunch of issues for broader targets that use Str.h (such as plugins and modules)
57 //   Q_StrDup should be used now, using a #define __StrDup for easy transition
58
59 #define __StrDup Q_StrDup
60
61 inline char* Q_StrDup( char* _pStr ) {
62         const char* pStr = _pStr;
63         if ( pStr == NULL ) {
64                 pStr = "";
65         }
66
67         return strcpy( new char[ strlen( pStr ) + 1 ], pStr );
68 }
69
70 inline char* Q_StrDup( const char* pStr ) {
71         if ( pStr == NULL ) {
72                 pStr = "";
73         }
74
75         return strcpy( new char[strlen( pStr ) + 1], pStr );
76 }
77
78 #if defined ( __linux__ ) || defined ( __APPLE__ )
79 #define strcmpi strcasecmp
80 #define stricmp strcasecmp
81 #define strnicmp strncasecmp
82
83 inline char* strlwr( char* string ){
84         char *cp;
85         for ( cp = string; *cp; ++cp )
86         {
87                 if ( 'A' <= *cp && *cp <= 'Z' ) {
88                         *cp += 'a' - 'A';
89                 }
90         }
91
92         return string;
93 }
94
95 inline char* strupr( char* string ){
96         char *cp;
97         for ( cp = string; *cp; ++cp )
98         {
99                 if ( 'a' <= *cp && *cp <= 'z' ) {
100                         *cp += 'A' - 'a';
101                 }
102         }
103
104         return string;
105 }
106 #endif
107
108 static char *g_pStrWork = NULL;
109
110 class Str
111 {
112 protected:
113 bool m_bIgnoreCase;
114 char *m_pStr;
115
116 public:
117 Str(){
118         m_bIgnoreCase = true;
119         m_pStr = new char[1];
120         m_pStr[0] = '\0';
121 }
122
123 Str( char *p ){
124         m_bIgnoreCase = true;
125         m_pStr = __StrDup( p );
126 }
127
128 Str( const char *p ){
129         m_bIgnoreCase = true;
130         m_pStr = __StrDup( p );
131 }
132
133 Str( const unsigned char *p ){
134         m_bIgnoreCase = true;
135         m_pStr = __StrDup( (const char *)p );
136 }
137
138 Str( const char c ){
139         m_bIgnoreCase = true;
140         m_pStr = new char[2];
141         m_pStr[0] = c;
142         m_pStr[1] = '\0';
143 }
144
145 const char* GetBuffer() const {
146         return m_pStr;
147 }
148
149 Str( const Str &s ){
150         m_bIgnoreCase = true;
151         m_pStr = __StrDup( s.GetBuffer() );
152 }
153
154 void Deallocate(){
155         delete []m_pStr;
156         m_pStr = NULL;
157 }
158
159 void Allocate( int n ){
160         Deallocate();
161         m_pStr = new char[n];
162 }
163
164 void MakeEmpty(){
165         Deallocate();
166         m_pStr = __StrDup( "" );
167 }
168
169 virtual ~Str(){
170         Deallocate();
171         // NOTE TTimo: someone explain this g_pStrWork to me?
172         if ( g_pStrWork ) {
173                 delete []g_pStrWork;
174         }
175         g_pStrWork = NULL;
176 }
177
178 void MakeLower(){
179         if ( m_pStr ) {
180                 strlwr( m_pStr );
181         }
182 }
183
184 void MakeUpper(){
185         if ( m_pStr ) {
186                 strupr( m_pStr );
187         }
188 }
189
190 void TrimRight(){
191         char* lpsz = m_pStr;
192         char* lpszLast = NULL;
193         while ( *lpsz != '\0' )
194         {
195                 if ( isspace( *lpsz ) ) {
196                         if ( lpszLast == NULL ) {
197                                 lpszLast = lpsz;
198                         }
199                 }
200                 else{
201                         lpszLast = NULL;
202                 }
203                 lpsz++;
204         }
205
206         if ( lpszLast != NULL ) {
207                 // truncate at trailing space start
208                 *lpszLast = '\0';
209         }
210 }
211
212 void TrimLeft(){
213         // find first non-space character
214         char* lpsz = m_pStr;
215         while ( isspace( *lpsz ) )
216                 lpsz++;
217
218         // fix up data and length
219         int nDataLength = GetLength() - ( lpsz - m_pStr );
220         memmove( m_pStr, lpsz, ( nDataLength + 1 ) );
221 }
222
223 int Find( const char *p ){
224         char *pf = strstr( m_pStr, p );
225         return ( pf ) ? ( pf - m_pStr ) : -1;
226 }
227
228 // search starting at a given offset
229 int Find( const char *p, int offset ){
230         char *pf = strstr( m_pStr + offset, p );
231         return ( pf ) ? ( pf - m_pStr ) : -1;
232 }
233
234 int Find( const char ch ){
235         char *pf = strchr( m_pStr, ch );
236         return ( pf ) ? ( pf - m_pStr ) : -1;
237 }
238
239 int ReverseFind( const char ch ){
240         char *pf = strrchr( m_pStr, ch );
241         return ( pf ) ? ( pf - m_pStr ) : -1;
242 }
243
244 int Compare( const char* str ) const {
245         return strcmp( m_pStr, str );
246 }
247
248 int CompareNoCase( const char* str ) const {
249         return strcasecmp( m_pStr, str );
250 }
251
252 int GetLength(){
253         return ( m_pStr ) ? strlen( m_pStr ) : 0;
254 }
255
256 const char* Left( int n ){
257         delete []g_pStrWork;
258         if ( n > 0 ) {
259                 g_pStrWork = new char[n + 1];
260                 strncpy( g_pStrWork, m_pStr, n );
261                 g_pStrWork[n] = '\0';
262         }
263         else
264         {
265                 g_pStrWork = new char[1];
266                 g_pStrWork[0] = '\0';
267         }
268         return g_pStrWork;
269 }
270
271 const char* Right( int n ){
272         delete []g_pStrWork;
273         if ( n > 0 ) {
274                 g_pStrWork = new char[n + 1];
275                 int nStart = GetLength() - n;
276                 strncpy( g_pStrWork, &m_pStr[nStart], n );
277                 g_pStrWork[n] = '\0';
278         }
279         else
280         {
281                 g_pStrWork = new char[1];
282                 g_pStrWork[0] = '\0';
283         }
284         return g_pStrWork;
285 }
286
287 const char* Mid( int nFirst ) const {
288         return Mid( nFirst, strlen( m_pStr ) - nFirst );
289 }
290
291 const char* Mid( int first, int n ) const {
292         delete []g_pStrWork;
293         if ( n > 0 ) {
294                 g_pStrWork = new char[n + 1];
295                 strncpy( g_pStrWork, m_pStr + first, n );
296                 g_pStrWork[n] = '\0';
297         }
298         else
299         {
300                 g_pStrWork = new char[1];
301                 g_pStrWork[0] = '\0';
302         }
303         return g_pStrWork;
304 }
305
306 #ifdef __G_LIB_H__
307 void Format( const char* fmt, ... ){
308         va_list args;
309         char *buffer;
310
311         va_start( args, fmt );
312         buffer = g_strdup_vprintf( fmt, args );
313         va_end( args );
314
315         delete[] m_pStr;
316         m_pStr = __StrDup( buffer );
317         g_free( buffer );
318 }
319 #else
320 void Format( const char* fmt, ... ){
321         va_list args;
322         m_pStr = new char[1024];
323
324         va_start( args, fmt );
325         vsprintf( m_pStr, fmt, args );
326         va_end( args );
327 }
328 #endif
329
330 void SetAt( int n, char ch ){
331         if ( n >= 0 && n < GetLength() ) {
332                 m_pStr[n] = ch;
333         }
334 }
335
336 // NOTE: unlike CString, this looses the pointer
337 void ReleaseBuffer( int n = -1 ){
338         if ( n == -1 ) {
339                 n = GetLength();
340         }
341
342         char* tmp = m_pStr;
343         tmp[n] = '\0';
344         m_pStr = __StrDup( tmp );
345         delete []tmp;
346 }
347
348 char* GetBufferSetLength( int n ){
349         if ( n < 0 ) {
350                 n = 0;
351         }
352
353         char *p = new char[n + 1];
354         strncpy( p, m_pStr, n );
355         p[n] = '\0';
356         delete []m_pStr;
357         m_pStr = p;
358         return m_pStr;
359 }
360
361 //  char& operator *() { return *m_pStr; }
362 //  char& operator *() const { return *const_cast<Str*>(this)->m_pStr; }
363 operator void*() {
364         return m_pStr;
365 }
366 operator char*() {
367         return m_pStr;
368 }
369 operator const char*(){
370         return reinterpret_cast<const char*>( m_pStr );
371 }
372 operator unsigned char*() {
373         return reinterpret_cast<unsigned char*>( m_pStr );
374 }
375 operator const unsigned char*() {
376         return reinterpret_cast<const unsigned char*>( m_pStr );
377 }
378 Str& operator =( const Str& rhs ){
379         if ( &rhs != this ) {
380                 delete[] m_pStr;
381                 m_pStr = __StrDup( rhs.m_pStr );
382         }
383         return *this;
384 }
385
386 Str& operator =( const char* pStr ){
387         if ( m_pStr != pStr ) {
388                 delete[] m_pStr;
389                 m_pStr = __StrDup( pStr );
390         }
391         return *this;
392 }
393
394 Str& operator +=( const char ch ){
395         int len = GetLength();
396         char *p = new char[len + 1 + 1];
397
398         if ( m_pStr ) {
399                 strcpy( p, m_pStr );
400                 delete[] m_pStr;
401         }
402
403         m_pStr = p;
404         m_pStr[len] = ch;
405         m_pStr[len + 1] = '\0';
406
407         return *this;
408 }
409
410 Str& operator +=( const char *pStr ){
411         if ( pStr ) {
412                 if ( m_pStr ) {
413                         char *p = new char[strlen( m_pStr ) + strlen( pStr ) + 1];
414                         strcpy( p, m_pStr );
415                         strcat( p, pStr );
416                         delete[] m_pStr;
417                         m_pStr = p;
418                 }
419                 else
420                 {
421                         m_pStr = __StrDup( pStr );
422                 }
423         }
424         return *this;
425 }
426
427
428 bool operator ==( const Str& rhs ) const { return ( m_bIgnoreCase ) ? stricmp( m_pStr, rhs.m_pStr ) == 0 : strcmp( m_pStr, rhs.m_pStr ) == 0; }
429 bool operator ==( char* pStr ) const { return ( m_bIgnoreCase ) ? stricmp( m_pStr, pStr ) == 0 : strcmp( m_pStr, pStr ) == 0; }
430 bool operator ==( const char* pStr ) const { return ( m_bIgnoreCase ) ? stricmp( m_pStr, pStr ) == 0 : strcmp( m_pStr, pStr ) == 0; }
431 bool operator !=( Str& rhs ) const { return ( m_bIgnoreCase ) ? stricmp( m_pStr, rhs.m_pStr ) != 0 : strcmp( m_pStr, rhs.m_pStr ) != 0; }
432 bool operator !=( char* pStr ) const { return ( m_bIgnoreCase ) ? stricmp( m_pStr, pStr ) != 0 : strcmp( m_pStr, pStr ) != 0; }
433 bool operator !=( const char* pStr ) const { return ( m_bIgnoreCase ) ? stricmp( m_pStr, pStr ) != 0 : strcmp( m_pStr, pStr ) != 0; }
434 bool operator <( const Str& rhs ) const { return ( m_bIgnoreCase ) ? stricmp( m_pStr, rhs.m_pStr ) < 0 : strcmp( m_pStr, rhs.m_pStr ) < 0; }
435 bool operator <( char* pStr ) const { return ( m_bIgnoreCase ) ? stricmp( m_pStr, pStr ) < 0 : strcmp( m_pStr, pStr ) < 0; }
436 bool operator <( const char* pStr ) const { return ( m_bIgnoreCase ) ? stricmp( m_pStr, pStr ) < 0 : strcmp( m_pStr, pStr ) < 0; }
437 bool operator >( const Str& rhs ) const { return ( m_bIgnoreCase ) ? stricmp( m_pStr, rhs.m_pStr ) > 0 : strcmp( m_pStr, rhs.m_pStr ) > 0; }
438 bool operator >( char* pStr ) const { return ( m_bIgnoreCase ) ? stricmp( m_pStr, pStr ) > 0 : strcmp( m_pStr, pStr ) > 0; }
439 bool operator >( const char* pStr ) const { return ( m_bIgnoreCase ) ? stricmp( m_pStr, pStr ) > 0 : strcmp( m_pStr, pStr ) > 0; }
440 char& operator []( int nIndex ) { return m_pStr[nIndex]; }
441 char& operator []( int nIndex ) const { return m_pStr[nIndex]; }
442 const char GetAt( int nIndex ) { return m_pStr[nIndex]; }
443 };
444
445
446
447 #endif