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