1 /*
2 ===========================================================================
3
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
6
7 This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code").
8
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
21
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
23
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
25
26 ===========================================================================
27 */
28
29 #ifndef __STR_H__
30 #define __STR_H__
31
32 #include "idlib/CmdArgs.h"
33
34 /*
35 ===============================================================================
36
37 Character string
38
39 ===============================================================================
40 */
41
42 // these library functions should not be used for cross platform compatibility
43 #ifndef IDSTR_NO_REDIRECT
44 #define strcmp idStr::Cmp // use_idStr_Cmp
45 #define strncmp use_idStr_Cmpn
46
47 #if defined( StrCmpN )
48 #undef StrCmpN
49 #endif
50 #define StrCmpN use_idStr_Cmpn
51
52 #if defined( strcmpi )
53 #undef strcmpi
54 #endif
55 #define strcmpi use_idStr_Icmp
56
57 #if defined( StrCmpI )
58 #undef StrCmpI
59 #endif
60 #define StrCmpI use_idStr_Icmp
61
62 #if defined( StrCmpNI )
63 #undef StrCmpNI
64 #endif
65 #define StrCmpNI use_idStr_Icmpn
66
67 #if defined( stricmp )
68 #undef stricmp
69 #endif
70 #define stricmp idStr::Icmp // use_idStr_Icmp
71 #define _stricmp use_idStr_Icmp
72 #if defined( strcasecmp )
73 #undef strcasecmp
74 #endif
75 #define strcasecmp use_idStr_Icmp
76 #if defined( strnicmp )
77 #undef strnicmp
78 #endif
79 #define strnicmp use_idStr_Icmpn
80 #define _strnicmp use_idStr_Icmpn
81 #define _memicmp use_idStr_Icmpn
82 #define snprintf use_idStr_snPrintf
83 #define _snprintf use_idStr_snPrintf
84 #define vsnprintf use_idStr_vsnPrintf
85 #define _vsnprintf use_idStr_vsnPrintf
86 #endif
87
88 class idVec4;
89
90 #ifndef FILE_HASH_SIZE
91 #define FILE_HASH_SIZE 1024
92 #endif
93
94 // color escape character
95 const int C_COLOR_ESCAPE = '^';
96 const int C_COLOR_DEFAULT = '0';
97 const int C_COLOR_RED = '1';
98 const int C_COLOR_GREEN = '2';
99 const int C_COLOR_YELLOW = '3';
100 const int C_COLOR_BLUE = '4';
101 const int C_COLOR_CYAN = '5';
102 const int C_COLOR_MAGENTA = '6';
103 const int C_COLOR_WHITE = '7';
104 const int C_COLOR_GRAY = '8';
105 const int C_COLOR_BLACK = '9';
106
107 // color escape string
108 #define S_COLOR_DEFAULT "^0"
109 #define S_COLOR_RED "^1"
110 #define S_COLOR_GREEN "^2"
111 #define S_COLOR_YELLOW "^3"
112 #define S_COLOR_BLUE "^4"
113 #define S_COLOR_CYAN "^5"
114 #define S_COLOR_MAGENTA "^6"
115 #define S_COLOR_WHITE "^7"
116 #define S_COLOR_GRAY "^8"
117 #define S_COLOR_BLACK "^9"
118
119 // make idStr a multiple of 16 bytes long
120 // don't make too large to keep memory requirements to a minimum
121 const int STR_ALLOC_BASE = 20;
122 const int STR_ALLOC_GRAN = 32;
123
124 typedef enum {
125 MEASURE_SIZE = 0,
126 MEASURE_BANDWIDTH
127 } Measure_t;
128
129 class idStr {
130
131 public:
132 idStr( void );
133 idStr( const idStr &text );
134 idStr( const idStr &text, int start, int end );
135 idStr( const char *text );
136 idStr( const char *text, int start, int end );
137 explicit idStr( const bool b );
138 explicit idStr( const char c );
139 explicit idStr( const int i );
140 explicit idStr( const unsigned u );
141 explicit idStr( const float f );
142 ~idStr( void );
143
144 size_t Size( void ) const;
145 const char * c_str( void ) const;
146 operator const char *( void ) const;
147 operator const char *( void );
148
149 char operator[]( int index ) const;
150 char & operator[]( int index );
151
152 void operator=( const idStr &text );
153 void operator=( const char *text );
154
155 friend idStr operator+( const idStr &a, const idStr &b );
156 friend idStr operator+( const idStr &a, const char *b );
157 friend idStr operator+( const char *a, const idStr &b );
158
159 friend idStr operator+( const idStr &a, const float b );
160 friend idStr operator+( const idStr &a, const int b );
161 friend idStr operator+( const idStr &a, const unsigned b );
162 friend idStr operator+( const idStr &a, const bool b );
163 friend idStr operator+( const idStr &a, const char b );
164
165 idStr & operator+=( const idStr &a );
166 idStr & operator+=( const char *a );
167 idStr & operator+=( const float a );
168 idStr & operator+=( const char a );
169 idStr & operator+=( const int a );
170 idStr & operator+=( const unsigned a );
171 idStr & operator+=( const bool a );
172
173 // case sensitive compare
174 friend bool operator==( const idStr &a, const idStr &b );
175 friend bool operator==( const idStr &a, const char *b );
176 friend bool operator==( const char *a, const idStr &b );
177
178 // case sensitive compare
179 friend bool operator!=( const idStr &a, const idStr &b );
180 friend bool operator!=( const idStr &a, const char *b );
181 friend bool operator!=( const char *a, const idStr &b );
182
183 // case sensitive compare
184 int Cmp( const char *text ) const;
185 int Cmpn( const char *text, int n ) const;
186 int CmpPrefix( const char *text ) const;
187
188 // case insensitive compare
189 int Icmp( const char *text ) const;
190 int Icmpn( const char *text, int n ) const;
191 int IcmpPrefix( const char *text ) const;
192
193 // case insensitive compare ignoring color
194 int IcmpNoColor( const char *text ) const;
195
196 // compares paths and makes sure folders come first
197 int IcmpPath( const char *text ) const;
198 int IcmpnPath( const char *text, int n ) const;
199 int IcmpPrefixPath( const char *text ) const;
200
201 int Length( void ) const;
202 int Allocated( void ) const;
203 void Empty( void );
204 bool IsEmpty( void ) const;
205 void Clear( void );
206 void Append( const char a );
207 void Append( const idStr &text );
208 void Append( const char *text );
209 void Append( const char *text, int len );
210 void Insert( const char a, int index );
211 void Insert( const char *text, int index );
212 void ToLower( void );
213 void ToUpper( void );
214 bool IsNumeric( void ) const;
215 bool IsColor( void ) const;
216 bool HasLower( void ) const;
217 bool HasUpper( void ) const;
218 int LengthWithoutColors( void ) const;
219 idStr & RemoveColors( void );
220 void CapLength( int );
221 void Fill( const char ch, int newlen );
222
223 int Find( const char c, int start = 0, int end = -1 ) const;
224 int Find( const char *text, bool casesensitive = true, int start = 0, int end = -1 ) const;
225 bool Filter( const char *filter, bool casesensitive ) const;
226 int Last( const char c ) const; // return the index to the last occurance of 'c', returns -1 if not found
227 const char * Left( int len, idStr &result ) const; // store the leftmost 'len' characters in the result
228 const char * Right( int len, idStr &result ) const; // store the rightmost 'len' characters in the result
229 const char * Mid( int start, int len, idStr &result ) const; // store 'len' characters starting at 'start' in result
230 idStr Left( int len ) const; // return the leftmost 'len' characters
231 idStr Right( int len ) const; // return the rightmost 'len' characters
232 idStr Mid( int start, int len ) const; // return 'len' characters starting at 'start'
233 void StripLeading( const char c ); // strip char from front as many times as the char occurs
234 void StripLeading( const char *string ); // strip string from front as many times as the string occurs
235 bool StripLeadingOnce( const char *string ); // strip string from front just once if it occurs
236 void StripTrailing( const char c ); // strip char from end as many times as the char occurs
237 void StripTrailing( const char *string ); // strip string from end as many times as the string occurs
238 bool StripTrailingOnce( const char *string ); // strip string from end just once if it occurs
239 void Strip( const char c ); // strip char from front and end as many times as the char occurs
240 void Strip( const char *string ); // strip string from front and end as many times as the string occurs
241 void StripTrailingWhitespace( void ); // strip trailing white space characters
242 idStr & StripQuotes( void ); // strip quotes around string
243 void Replace( const char *old, const char *nw );
244
245 // file name methods
246 int FileNameHash( void ) const; // hash key for the filename (skips extension)
247 idStr & BackSlashesToSlashes( void ); // convert slashes
248 idStr & SetFileExtension( const char *extension ); // set the given file extension
249 idStr & StripFileExtension( void ); // remove any file extension
250 idStr & StripAbsoluteFileExtension( void ); // remove any file extension looking from front (useful if there are multiple .'s)
251 idStr & DefaultFileExtension( const char *extension ); // if there's no file extension use the default
252 idStr & DefaultPath( const char *basepath ); // if there's no path use the default
253 void AppendPath( const char *text ); // append a partial path
254 idStr & StripFilename( void ); // remove the filename from a path
255 idStr & StripPath( void ); // remove the path from the filename
256 void ExtractFilePath( idStr &dest ) const; // copy the file path to another string
257 void ExtractFileName( idStr &dest ) const; // copy the filename to another string
258 void ExtractFileBase( idStr &dest ) const; // copy the filename minus the extension to another string
259 void ExtractFileExtension( idStr &dest ) const; // copy the file extension to another string
260 bool CheckExtension( const char *ext );
261
262 // char * methods to replace library functions
263 static int Length( const char *s );
264 static char * ToLower( char *s );
265 static char * ToUpper( char *s );
266 static bool IsNumeric( const char *s );
267 static bool IsColor( const char *s );
268 static bool HasLower( const char *s );
269 static bool HasUpper( const char *s );
270 static int LengthWithoutColors( const char *s );
271 static char * RemoveColors( char *s );
272 static int Cmp( const char *s1, const char *s2 );
273 static int Cmpn( const char *s1, const char *s2, int n );
274 static int Icmp( const char *s1, const char *s2 );
275 static int Icmpn( const char *s1, const char *s2, int n );
276 static int IcmpNoColor( const char *s1, const char *s2 );
277 static int IcmpPath( const char *s1, const char *s2 ); // compares paths and makes sure folders come first
278 static int IcmpnPath( const char *s1, const char *s2, int n ); // compares paths and makes sure folders come first
279 static void Append( char *dest, int size, const char *src );
280 static void Copynz( char *dest, const char *src, int destsize );
281 static int snPrintf( char *dest, int size, const char *fmt, ... ) id_attribute((format(printf,3,4)));
282 static int vsnPrintf( char *dest, int size, const char *fmt, va_list argptr );
283 static int FindChar( const char *str, const char c, int start = 0, int end = -1 );
284 static int FindText( const char *str, const char *text, bool casesensitive = true, int start = 0, int end = -1 );
285 static bool Filter( const char *filter, const char *name, bool casesensitive );
286 static void StripMediaName( const char *name, idStr &mediaName );
287 static bool CheckExtension( const char *name, const char *ext );
288 static const char * FloatArrayToString( const float *array, const int length, const int precision );
289
290 // hash keys
291 static int Hash( const char *string );
292 static int Hash( const char *string, int length );
293 static int IHash( const char *string ); // case insensitive
294 static int IHash( const char *string, int length ); // case insensitive
295
296 // character methods
297 static char ToLower( char c );
298 static char ToUpper( char c );
299 static bool CharIsPrintable( int c );
300 static bool CharIsLower( int c );
301 static bool CharIsUpper( int c );
302 static bool CharIsAlpha( int c );
303 static bool CharIsNumeric( int c );
304 static bool CharIsNewLine( char c );
305 static bool CharIsTab( char c );
306 static int ColorIndex( int c );
307 static idVec4 & ColorForIndex( int i );
308
309 friend int sprintf( idStr &dest, const char *fmt, ... );
310 friend int vsprintf( idStr &dest, const char *fmt, va_list ap );
311
312 void ReAllocate( int amount, bool keepold ); // reallocate string data buffer
313 void FreeData( void ); // free allocated string memory
314
315 // format value in the given measurement with the best unit, returns the best unit
316 int BestUnit( const char *format, float value, Measure_t measure );
317 // format value in the requested unit and measurement
318 void SetUnit( const char *format, float value, int unit, Measure_t measure );
319
320 static void InitMemory( void );
321 static void ShutdownMemory( void );
322 static void PurgeMemory( void );
323 static void ShowMemoryUsage_f( const idCmdArgs &args );
324
325 int DynamicMemoryUsed() const;
326 static idStr FormatNumber( int number );
327
328 protected:
329 int len;
330 char * data;
331 int alloced;
332 char baseBuffer[ STR_ALLOC_BASE ];
333
334 void Init( void ); // initialize string using base buffer
335 void EnsureAlloced( int amount, bool keepold = true ); // ensure string data buffer is large anough
336 };
337
338 char * va( const char *fmt, ... ) id_attribute((format(printf,1,2)));
339
340
EnsureAlloced(int amount,bool keepold)341 ID_INLINE void idStr::EnsureAlloced( int amount, bool keepold ) {
342 if ( amount > alloced ) {
343 ReAllocate( amount, keepold );
344 }
345 }
346
Init(void)347 ID_INLINE void idStr::Init( void ) {
348 len = 0;
349 alloced = STR_ALLOC_BASE;
350 data = baseBuffer;
351 data[ 0 ] = '\0';
352 #ifdef ID_DEBUG_UNINITIALIZED_MEMORY
353 memset( baseBuffer, 0, sizeof( baseBuffer ) );
354 #endif
355 }
356
idStr(void)357 ID_INLINE idStr::idStr( void ) {
358 Init();
359 }
360
idStr(const idStr & text)361 ID_INLINE idStr::idStr( const idStr &text ) {
362 int l;
363
364 Init();
365 l = text.Length();
366 EnsureAlloced( l + 1 );
367 strcpy( data, text.data );
368 len = l;
369 }
370
idStr(const idStr & text,int start,int end)371 ID_INLINE idStr::idStr( const idStr &text, int start, int end ) {
372 int i;
373 int l;
374
375 Init();
376 if ( end > text.Length() ) {
377 end = text.Length();
378 }
379 if ( start > text.Length() ) {
380 start = text.Length();
381 } else if ( start < 0 ) {
382 start = 0;
383 }
384
385 l = end - start;
386 if ( l < 0 ) {
387 l = 0;
388 }
389
390 EnsureAlloced( l + 1 );
391
392 for ( i = 0; i < l; i++ ) {
393 data[ i ] = text[ start + i ];
394 }
395
396 data[ l ] = '\0';
397 len = l;
398 }
399
idStr(const char * text)400 ID_INLINE idStr::idStr( const char *text ) {
401 int l;
402
403 Init();
404 if ( text ) {
405 l = strlen( text );
406 EnsureAlloced( l + 1 );
407 strcpy( data, text );
408 len = l;
409 }
410 }
411
idStr(const char * text,int start,int end)412 ID_INLINE idStr::idStr( const char *text, int start, int end ) {
413 int i;
414 int l = strlen( text );
415
416 Init();
417 if ( end > l ) {
418 end = l;
419 }
420 if ( start > l ) {
421 start = l;
422 } else if ( start < 0 ) {
423 start = 0;
424 }
425
426 l = end - start;
427 if ( l < 0 ) {
428 l = 0;
429 }
430
431 EnsureAlloced( l + 1 );
432
433 for ( i = 0; i < l; i++ ) {
434 data[ i ] = text[ start + i ];
435 }
436
437 data[ l ] = '\0';
438 len = l;
439 }
440
idStr(const bool b)441 ID_INLINE idStr::idStr( const bool b ) {
442 Init();
443 EnsureAlloced( 2 );
444 data[ 0 ] = b ? '1' : '0';
445 data[ 1 ] = '\0';
446 len = 1;
447 }
448
idStr(const char c)449 ID_INLINE idStr::idStr( const char c ) {
450 Init();
451 EnsureAlloced( 2 );
452 data[ 0 ] = c;
453 data[ 1 ] = '\0';
454 len = 1;
455 }
456
idStr(const int i)457 ID_INLINE idStr::idStr( const int i ) {
458 char text[ 64 ];
459 int l;
460
461 Init();
462 l = sprintf( text, "%d", i );
463 EnsureAlloced( l + 1 );
464 strcpy( data, text );
465 len = l;
466 }
467
idStr(const unsigned u)468 ID_INLINE idStr::idStr( const unsigned u ) {
469 char text[ 64 ];
470 int l;
471
472 Init();
473 l = sprintf( text, "%u", u );
474 EnsureAlloced( l + 1 );
475 strcpy( data, text );
476 len = l;
477 }
478
idStr(const float f)479 ID_INLINE idStr::idStr( const float f ) {
480 char text[ 64 ];
481 int l;
482
483 Init();
484 l = idStr::snPrintf( text, sizeof( text ), "%f", f );
485 while( l > 0 && text[l-1] == '0' ) text[--l] = '\0';
486 while( l > 0 && text[l-1] == '.' ) text[--l] = '\0';
487 EnsureAlloced( l + 1 );
488 strcpy( data, text );
489 len = l;
490 }
491
~idStr(void)492 ID_INLINE idStr::~idStr( void ) {
493 FreeData();
494 }
495
Size(void)496 ID_INLINE size_t idStr::Size( void ) const {
497 return sizeof( *this ) + Allocated();
498 }
499
c_str(void)500 ID_INLINE const char *idStr::c_str( void ) const {
501 return data;
502 }
503
504 ID_INLINE idStr::operator const char *( void ) {
505 return c_str();
506 }
507
508 ID_INLINE idStr::operator const char *( void ) const {
509 return c_str();
510 }
511
512 #pragma GCC diagnostic push
513 // shut up GCC's stupid "warning: assuming signed overflow does not occur when assuming that
514 // (X - c) > X is always false [-Wstrict-overflow]"
515 #pragma GCC diagnostic ignored "-Wstrict-overflow"
516 ID_INLINE char idStr::operator[]( int index ) const {
517 assert( ( index >= 0 ) && ( index <= len ) );
518 return data[ index ];
519 }
520
521 ID_INLINE char &idStr::operator[]( int index ) {
522 assert( ( index >= 0 ) && ( index <= len ) );
523 return data[ index ];
524 }
525 #pragma GCC diagnostic pop
526
527 ID_INLINE void idStr::operator=( const idStr &text ) {
528 if (&text == this) {
529 return;
530 }
531
532 int l;
533
534 l = text.Length();
535 EnsureAlloced( l + 1, false );
536 memcpy( data, text.data, l );
537 data[l] = '\0';
538 len = l;
539 }
540
541 ID_INLINE idStr operator+( const idStr &a, const idStr &b ) {
542 idStr result( a );
543 result.Append( b );
544 return result;
545 }
546
547 ID_INLINE idStr operator+( const idStr &a, const char *b ) {
548 idStr result( a );
549 result.Append( b );
550 return result;
551 }
552
553 ID_INLINE idStr operator+( const char *a, const idStr &b ) {
554 idStr result( a );
555 result.Append( b );
556 return result;
557 }
558
559 ID_INLINE idStr operator+( const idStr &a, const bool b ) {
560 idStr result( a );
561 result.Append( b ? "true" : "false" );
562 return result;
563 }
564
565 ID_INLINE idStr operator+( const idStr &a, const char b ) {
566 idStr result( a );
567 result.Append( b );
568 return result;
569 }
570
571 ID_INLINE idStr operator+( const idStr &a, const float b ) {
572 char text[ 64 ];
573 idStr result( a );
574
575 sprintf( text, "%f", b );
576 result.Append( text );
577
578 return result;
579 }
580
581 ID_INLINE idStr operator+( const idStr &a, const int b ) {
582 char text[ 64 ];
583 idStr result( a );
584
585 sprintf( text, "%d", b );
586 result.Append( text );
587
588 return result;
589 }
590
591 ID_INLINE idStr operator+( const idStr &a, const unsigned b ) {
592 char text[ 64 ];
593 idStr result( a );
594
595 sprintf( text, "%u", b );
596 result.Append( text );
597
598 return result;
599 }
600
601 ID_INLINE idStr &idStr::operator+=( const float a ) {
602 char text[ 64 ];
603
604 sprintf( text, "%f", a );
605 Append( text );
606
607 return *this;
608 }
609
610 ID_INLINE idStr &idStr::operator+=( const int a ) {
611 char text[ 64 ];
612
613 sprintf( text, "%d", a );
614 Append( text );
615
616 return *this;
617 }
618
619 ID_INLINE idStr &idStr::operator+=( const unsigned a ) {
620 char text[ 64 ];
621
622 sprintf( text, "%u", a );
623 Append( text );
624
625 return *this;
626 }
627
628 ID_INLINE idStr &idStr::operator+=( const idStr &a ) {
629 Append( a );
630 return *this;
631 }
632
633 ID_INLINE idStr &idStr::operator+=( const char *a ) {
634 Append( a );
635 return *this;
636 }
637
638 ID_INLINE idStr &idStr::operator+=( const char a ) {
639 Append( a );
640 return *this;
641 }
642
643 ID_INLINE idStr &idStr::operator+=( const bool a ) {
644 Append( a ? "true" : "false" );
645 return *this;
646 }
647
648 ID_INLINE bool operator==( const idStr &a, const idStr &b ) {
649 return ( !idStr::Cmp( a.data, b.data ) );
650 }
651
652 ID_INLINE bool operator==( const idStr &a, const char *b ) {
653 assert( b );
654 return ( !idStr::Cmp( a.data, b ) );
655 }
656
657 ID_INLINE bool operator==( const char *a, const idStr &b ) {
658 assert( a );
659 return ( !idStr::Cmp( a, b.data ) );
660 }
661
662 ID_INLINE bool operator!=( const idStr &a, const idStr &b ) {
663 return !( a == b );
664 }
665
666 ID_INLINE bool operator!=( const idStr &a, const char *b ) {
667 return !( a == b );
668 }
669
670 ID_INLINE bool operator!=( const char *a, const idStr &b ) {
671 return !( a == b );
672 }
673
Cmp(const char * text)674 ID_INLINE int idStr::Cmp( const char *text ) const {
675 assert( text );
676 return idStr::Cmp( data, text );
677 }
678
Cmpn(const char * text,int n)679 ID_INLINE int idStr::Cmpn( const char *text, int n ) const {
680 assert( text );
681 return idStr::Cmpn( data, text, n );
682 }
683
CmpPrefix(const char * text)684 ID_INLINE int idStr::CmpPrefix( const char *text ) const {
685 assert( text );
686 return idStr::Cmpn( data, text, strlen( text ) );
687 }
688
Icmp(const char * text)689 ID_INLINE int idStr::Icmp( const char *text ) const {
690 assert( text );
691 return idStr::Icmp( data, text );
692 }
693
Icmpn(const char * text,int n)694 ID_INLINE int idStr::Icmpn( const char *text, int n ) const {
695 assert( text );
696 return idStr::Icmpn( data, text, n );
697 }
698
IcmpPrefix(const char * text)699 ID_INLINE int idStr::IcmpPrefix( const char *text ) const {
700 assert( text );
701 return idStr::Icmpn( data, text, strlen( text ) );
702 }
703
IcmpNoColor(const char * text)704 ID_INLINE int idStr::IcmpNoColor( const char *text ) const {
705 assert( text );
706 return idStr::IcmpNoColor( data, text );
707 }
708
IcmpPath(const char * text)709 ID_INLINE int idStr::IcmpPath( const char *text ) const {
710 assert( text );
711 return idStr::IcmpPath( data, text );
712 }
713
IcmpnPath(const char * text,int n)714 ID_INLINE int idStr::IcmpnPath( const char *text, int n ) const {
715 assert( text );
716 return idStr::IcmpnPath( data, text, n );
717 }
718
IcmpPrefixPath(const char * text)719 ID_INLINE int idStr::IcmpPrefixPath( const char *text ) const {
720 assert( text );
721 return idStr::IcmpnPath( data, text, strlen( text ) );
722 }
723
Length(void)724 ID_INLINE int idStr::Length( void ) const {
725 return len;
726 }
727
Allocated(void)728 ID_INLINE int idStr::Allocated( void ) const {
729 if ( data != baseBuffer ) {
730 return alloced;
731 } else {
732 return 0;
733 }
734 }
735
Empty(void)736 ID_INLINE void idStr::Empty( void ) {
737 EnsureAlloced( 1 );
738 data[ 0 ] = '\0';
739 len = 0;
740 }
741
IsEmpty(void)742 ID_INLINE bool idStr::IsEmpty( void ) const {
743 return ( idStr::Cmp( data, "" ) == 0 );
744 }
745
Clear(void)746 ID_INLINE void idStr::Clear( void ) {
747 FreeData();
748 Init();
749 }
750
Append(const char a)751 ID_INLINE void idStr::Append( const char a ) {
752 EnsureAlloced( len + 2 );
753 data[ len ] = a;
754 len++;
755 data[ len ] = '\0';
756 }
757
Append(const idStr & text)758 ID_INLINE void idStr::Append( const idStr &text ) {
759 int newLen;
760 int i;
761
762 newLen = len + text.Length();
763 EnsureAlloced( newLen + 1 );
764 for ( i = 0; i < text.len; i++ ) {
765 data[ len + i ] = text[ i ];
766 }
767 len = newLen;
768 data[ len ] = '\0';
769 }
770
Append(const char * text)771 ID_INLINE void idStr::Append( const char *text ) {
772 int newLen;
773 int i;
774
775 if ( text ) {
776 newLen = len + strlen( text );
777 EnsureAlloced( newLen + 1 );
778 for ( i = 0; text[ i ]; i++ ) {
779 data[ len + i ] = text[ i ];
780 }
781 len = newLen;
782 data[ len ] = '\0';
783 }
784 }
785
Append(const char * text,int l)786 ID_INLINE void idStr::Append( const char *text, int l ) {
787 int newLen;
788 int i;
789
790 if ( text && l ) {
791 newLen = len + l;
792 EnsureAlloced( newLen + 1 );
793 for ( i = 0; text[ i ] && i < l; i++ ) {
794 data[ len + i ] = text[ i ];
795 }
796 len = newLen;
797 data[ len ] = '\0';
798 }
799 }
800
Insert(const char a,int index)801 ID_INLINE void idStr::Insert( const char a, int index ) {
802 int i, l;
803
804 if ( index < 0 ) {
805 index = 0;
806 } else if ( index > len ) {
807 index = len;
808 }
809
810 l = 1;
811 EnsureAlloced( len + l + 1 );
812 for ( i = len; i >= index; i-- ) {
813 data[i+l] = data[i];
814 }
815 data[index] = a;
816 len++;
817 }
818
Insert(const char * text,int index)819 ID_INLINE void idStr::Insert( const char *text, int index ) {
820 int i, l;
821
822 if ( index < 0 ) {
823 index = 0;
824 } else if ( index > len ) {
825 index = len;
826 }
827
828 l = strlen( text );
829 EnsureAlloced( len + l + 1 );
830 for ( i = len; i >= index; i-- ) {
831 data[i+l] = data[i];
832 }
833 for ( i = 0; i < l; i++ ) {
834 data[index+i] = text[i];
835 }
836 len += l;
837 }
838
ToLower(void)839 ID_INLINE void idStr::ToLower( void ) {
840 for (int i = 0; data[i]; i++ ) {
841 if ( CharIsUpper( data[i] ) ) {
842 data[i] += ( 'a' - 'A' );
843 }
844 }
845 }
846
ToUpper(void)847 ID_INLINE void idStr::ToUpper( void ) {
848 for (int i = 0; data[i]; i++ ) {
849 if ( CharIsLower( data[i] ) ) {
850 data[i] -= ( 'a' - 'A' );
851 }
852 }
853 }
854
IsNumeric(void)855 ID_INLINE bool idStr::IsNumeric( void ) const {
856 return idStr::IsNumeric( data );
857 }
858
IsColor(void)859 ID_INLINE bool idStr::IsColor( void ) const {
860 return idStr::IsColor( data );
861 }
862
HasLower(void)863 ID_INLINE bool idStr::HasLower( void ) const {
864 return idStr::HasLower( data );
865 }
866
HasUpper(void)867 ID_INLINE bool idStr::HasUpper( void ) const {
868 return idStr::HasUpper( data );
869 }
870
RemoveColors(void)871 ID_INLINE idStr &idStr::RemoveColors( void ) {
872 idStr::RemoveColors( data );
873 len = Length( data );
874 return *this;
875 }
876
LengthWithoutColors(void)877 ID_INLINE int idStr::LengthWithoutColors( void ) const {
878 return idStr::LengthWithoutColors( data );
879 }
880
CapLength(int newlen)881 ID_INLINE void idStr::CapLength( int newlen ) {
882 if ( len <= newlen ) {
883 return;
884 }
885 data[ newlen ] = 0;
886 len = newlen;
887 }
888
Fill(const char ch,int newlen)889 ID_INLINE void idStr::Fill( const char ch, int newlen ) {
890 EnsureAlloced( newlen + 1 );
891 len = newlen;
892 memset( data, ch, len );
893 data[ len ] = 0;
894 }
895
Find(const char c,int start,int end)896 ID_INLINE int idStr::Find( const char c, int start, int end ) const {
897 if ( end == -1 ) {
898 end = len;
899 }
900 return idStr::FindChar( data, c, start, end );
901 }
902
Find(const char * text,bool casesensitive,int start,int end)903 ID_INLINE int idStr::Find( const char *text, bool casesensitive, int start, int end ) const {
904 if ( end == -1 ) {
905 end = len;
906 }
907 return idStr::FindText( data, text, casesensitive, start, end );
908 }
909
Filter(const char * filter,bool casesensitive)910 ID_INLINE bool idStr::Filter( const char *filter, bool casesensitive ) const {
911 return idStr::Filter( filter, data, casesensitive );
912 }
913
Left(int len,idStr & result)914 ID_INLINE const char *idStr::Left( int len, idStr &result ) const {
915 return Mid( 0, len, result );
916 }
917
Right(int len,idStr & result)918 ID_INLINE const char *idStr::Right( int len, idStr &result ) const {
919 if ( len >= Length() ) {
920 result = *this;
921 return result;
922 }
923 return Mid( Length() - len, len, result );
924 }
925
Left(int len)926 ID_INLINE idStr idStr::Left( int len ) const {
927 return Mid( 0, len );
928 }
929
930 #pragma GCC diagnostic push
931 // shut up GCC's stupid "warning: assuming signed overflow does not occur when assuming that
932 // (X - c) > X is always false [-Wstrict-overflow]"
933 #pragma GCC diagnostic ignored "-Wstrict-overflow"
Right(int len)934 ID_INLINE idStr idStr::Right( int len ) const {
935 if ( len >= Length() ) {
936 return *this;
937 }
938 return Mid( Length() - len, len );
939 }
940 #pragma GCC diagnostic pop
941
Strip(const char c)942 ID_INLINE void idStr::Strip( const char c ) {
943 StripLeading( c );
944 StripTrailing( c );
945 }
946
Strip(const char * string)947 ID_INLINE void idStr::Strip( const char *string ) {
948 StripLeading( string );
949 StripTrailing( string );
950 }
951
CheckExtension(const char * ext)952 ID_INLINE bool idStr::CheckExtension( const char *ext ) {
953 return idStr::CheckExtension( data, ext );
954 }
955
Length(const char * s)956 ID_INLINE int idStr::Length( const char *s ) {
957 int i;
958 for ( i = 0; s[i]; i++ ) {}
959 return i;
960 }
961
ToLower(char * s)962 ID_INLINE char *idStr::ToLower( char *s ) {
963 for ( int i = 0; s[i]; i++ ) {
964 if ( CharIsUpper( s[i] ) ) {
965 s[i] += ( 'a' - 'A' );
966 }
967 }
968 return s;
969 }
970
ToUpper(char * s)971 ID_INLINE char *idStr::ToUpper( char *s ) {
972 for ( int i = 0; s[i]; i++ ) {
973 if ( CharIsLower( s[i] ) ) {
974 s[i] -= ( 'a' - 'A' );
975 }
976 }
977 return s;
978 }
979
Hash(const char * string)980 ID_INLINE int idStr::Hash( const char *string ) {
981 int i, hash = 0;
982 for ( i = 0; *string != '\0'; i++ ) {
983 hash += ( *string++ ) * ( i + 119 );
984 }
985 return hash;
986 }
987
Hash(const char * string,int length)988 ID_INLINE int idStr::Hash( const char *string, int length ) {
989 int i, hash = 0;
990 for ( i = 0; i < length; i++ ) {
991 hash += ( *string++ ) * ( i + 119 );
992 }
993 return hash;
994 }
995
IHash(const char * string)996 ID_INLINE int idStr::IHash( const char *string ) {
997 int i, hash = 0;
998 for( i = 0; *string != '\0'; i++ ) {
999 hash += ToLower( *string++ ) * ( i + 119 );
1000 }
1001 return hash;
1002 }
1003
IHash(const char * string,int length)1004 ID_INLINE int idStr::IHash( const char *string, int length ) {
1005 int i, hash = 0;
1006 for ( i = 0; i < length; i++ ) {
1007 hash += ToLower( *string++ ) * ( i + 119 );
1008 }
1009 return hash;
1010 }
1011
IsColor(const char * s)1012 ID_INLINE bool idStr::IsColor( const char *s ) {
1013 return ( s[0] == C_COLOR_ESCAPE && s[1] != '\0' && s[1] != ' ' );
1014 }
1015
ToLower(char c)1016 ID_INLINE char idStr::ToLower( char c ) {
1017 if ( c <= 'Z' && c >= 'A' ) {
1018 return ( c + ( 'a' - 'A' ) );
1019 }
1020 return c;
1021 }
1022
ToUpper(char c)1023 ID_INLINE char idStr::ToUpper( char c ) {
1024 if ( c >= 'a' && c <= 'z' ) {
1025 return ( c - ( 'a' - 'A' ) );
1026 }
1027 return c;
1028 }
1029
CharIsPrintable(int c)1030 ID_INLINE bool idStr::CharIsPrintable( int c ) {
1031 // test for regular ascii and western European high-ascii chars
1032 return ( c >= 0x20 && c <= 0x7E ) || ( c >= 0xA1 && c <= 0xFF );
1033 }
1034
CharIsLower(int c)1035 ID_INLINE bool idStr::CharIsLower( int c ) {
1036 // test for regular ascii and western European high-ascii chars
1037 return ( c >= 'a' && c <= 'z' ) || ( c >= 0xE0 && c <= 0xFF );
1038 }
1039
CharIsUpper(int c)1040 ID_INLINE bool idStr::CharIsUpper( int c ) {
1041 // test for regular ascii and western European high-ascii chars
1042 return ( c <= 'Z' && c >= 'A' ) || ( c >= 0xC0 && c <= 0xDF );
1043 }
1044
CharIsAlpha(int c)1045 ID_INLINE bool idStr::CharIsAlpha( int c ) {
1046 // test for regular ascii and western European high-ascii chars
1047 return ( ( c >= 'a' && c <= 'z' ) || ( c >= 'A' && c <= 'Z' ) ||
1048 ( c >= 0xC0 && c <= 0xFF ) );
1049 }
1050
CharIsNumeric(int c)1051 ID_INLINE bool idStr::CharIsNumeric( int c ) {
1052 return ( c <= '9' && c >= '0' );
1053 }
1054
CharIsNewLine(char c)1055 ID_INLINE bool idStr::CharIsNewLine( char c ) {
1056 return ( c == '\n' || c == '\r' || c == '\v' );
1057 }
1058
CharIsTab(char c)1059 ID_INLINE bool idStr::CharIsTab( char c ) {
1060 return ( c == '\t' );
1061 }
1062
ColorIndex(int c)1063 ID_INLINE int idStr::ColorIndex( int c ) {
1064 return ( c & 15 );
1065 }
1066
DynamicMemoryUsed()1067 ID_INLINE int idStr::DynamicMemoryUsed() const {
1068 return ( data == baseBuffer ) ? 0 : alloced;
1069 }
1070
1071 #endif /* !__STR_H__ */
1072