util_str.h (13906B)
1 /* 2 =========================================================================== 3 Copyright (C) 1999-2005 Id Software, Inc. 4 5 This file is part of Quake III Arena source code. 6 7 Quake III Arena source code is free software; you can redistribute it 8 and/or modify it under the terms of the GNU General Public License as 9 published by the Free Software Foundation; either version 2 of the License, 10 or (at your option) any later version. 11 12 Quake III Arena source code is distributed in the hope that it will be 13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with Foobar; if not, write to the Free Software 19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 =========================================================================== 21 */ 22 //need to rewrite this 23 24 #ifndef __UTIL_STR_H__ 25 #define __UTIL_STR_H__ 26 27 #include <assert.h> 28 #include <string.h> 29 #include <stdio.h> 30 31 #ifdef _WIN32 32 #pragma warning(disable : 4710) // function 'blah' not inlined 33 #endif 34 35 void TestStringClass (); 36 37 class strdata 38 { 39 public: 40 strdata () : len( 0 ), refcount ( 0 ), data ( NULL ), alloced ( 0 ) {} 41 ~strdata () 42 { 43 if ( data ) 44 delete [] data; 45 } 46 47 void AddRef () { refcount++; } 48 bool DelRef () // True if killed 49 { 50 refcount--; 51 if ( refcount < 0 ) 52 { 53 delete this; 54 return true; 55 } 56 57 return false; 58 } 59 60 int len; 61 int refcount; 62 char *data; 63 int alloced; 64 }; 65 66 class idStr { 67 protected: 68 strdata *m_data; 69 void EnsureAlloced ( int, bool keepold = true ); 70 void EnsureDataWritable (); 71 72 public: 73 ~idStr(); 74 idStr(); 75 idStr( const char *text ); 76 idStr( const idStr& string ); 77 idStr( const idStr string, int start, int end ); 78 idStr( const char ch ); 79 idStr( const int num ); 80 idStr( const float num ); 81 idStr( const unsigned num ); 82 int length( void ) const; 83 int allocated( void ) const; 84 const char * c_str( void ) const; 85 86 void append( const char *text ); 87 void append( const idStr& text ); 88 char operator[]( int index ) const; 89 char& operator[]( int index ); 90 91 void operator=( const idStr& text ); 92 void operator=( const char *text ); 93 94 friend idStr operator+( const idStr& a, const idStr& b ); 95 friend idStr operator+( const idStr& a, const char *b ); 96 friend idStr operator+( const char *a, const idStr& b ); 97 98 friend idStr operator+( const idStr& a, const float b ); 99 friend idStr operator+( const idStr& a, const int b ); 100 friend idStr operator+( const idStr& a, const unsigned b ); 101 friend idStr operator+( const idStr& a, const bool b ); 102 friend idStr operator+( const idStr& a, const char b ); 103 104 idStr& operator+=( const idStr& a ); 105 idStr& operator+=( const char *a ); 106 idStr& operator+=( const float a ); 107 idStr& operator+=( const char a ); 108 idStr& operator+=( const int a ); 109 idStr& operator+=( const unsigned a ); 110 idStr& operator+=( const bool a ); 111 112 friend bool operator==( const idStr& a, const idStr& b ); 113 friend bool operator==( const idStr& a, const char *b ); 114 friend bool operator==( const char *a, const idStr& b ); 115 116 friend bool operator!=( const idStr& a, const idStr& b ); 117 friend bool operator!=( const idStr& a, const char *b ); 118 friend bool operator!=( const char *a, const idStr& b ); 119 120 operator const char * () const; 121 operator const char * (); 122 123 int icmpn( const char *text, int n ) const; 124 int icmpn( const idStr& text, int n ) const; 125 int icmp( const char *text ) const; 126 int icmp( const idStr& text ) const; 127 int cmpn( const char *text, int n ) const; 128 int cmpn( const idStr& text, int n ) const; 129 int cmp( const char *text ) const; 130 int cmp( const idStr& text ) const; 131 132 void tolower( void ); 133 void toupper( void ); 134 135 static char *tolower( char *s1 ); 136 static char *toupper( char *s1 ); 137 138 static int icmpn( const char *s1, const char *s2, int n ); 139 static int icmp( const char *s1, const char *s2 ); 140 static int cmpn( const char *s1, const char *s2, int n ); 141 static int cmp( const char *s1, const char *s2 ); 142 143 static void snprintf ( char *dst, int size, const char *fmt, ... ); 144 145 static bool isNumeric( const char *str ); 146 bool isNumeric( void ) const; 147 148 void CapLength ( int ); 149 150 void BackSlashesToSlashes (); 151 152 }; 153 154 inline idStr::~idStr() 155 { 156 if ( m_data ) 157 { 158 m_data->DelRef (); 159 m_data = NULL; 160 } 161 } 162 163 inline idStr::idStr() : m_data ( NULL ) 164 { 165 EnsureAlloced ( 1 ); 166 m_data->data[ 0 ] = 0; 167 } 168 169 inline idStr::idStr 170 ( 171 const char *text 172 ) : m_data ( NULL ) 173 174 { 175 int len; 176 177 assert( text ); 178 179 if ( text ) 180 { 181 len = strlen( text ); 182 EnsureAlloced ( len + 1 ); 183 strcpy( m_data->data, text ); 184 m_data->len = len; 185 } 186 else 187 { 188 EnsureAlloced ( 1 ); 189 m_data->data[ 0 ] = 0; 190 m_data->len = 0; 191 } 192 } 193 194 inline idStr::idStr 195 ( 196 const idStr& text 197 ) : m_data ( NULL ) 198 199 { 200 m_data = text.m_data; 201 m_data->AddRef (); 202 } 203 204 inline idStr::idStr 205 ( 206 const idStr text, 207 int start, 208 int end 209 ) : m_data ( NULL ) 210 211 { 212 int i; 213 int len; 214 215 if ( end > text.length() ) 216 { 217 end = text.length(); 218 } 219 220 if ( start > text.length() ) 221 { 222 start = text.length(); 223 } 224 225 len = end - start; 226 if ( len < 0 ) 227 { 228 len = 0; 229 } 230 231 EnsureAlloced ( len + 1 ); 232 233 for( i = 0; i < len; i++ ) 234 { 235 m_data->data[ i ] = text[ start + i ]; 236 } 237 238 m_data->data[ len ] = 0; 239 m_data->len = len; 240 } 241 242 inline idStr::idStr 243 ( 244 const char ch 245 ) : m_data ( NULL ) 246 247 { 248 EnsureAlloced ( 2 ); 249 250 m_data->data[ 0 ] = ch; 251 m_data->data[ 1 ] = 0; 252 m_data->len = 1; 253 } 254 255 inline idStr::idStr 256 ( 257 const float num 258 ) : m_data ( NULL ) 259 260 { 261 char text[ 32 ]; 262 int len; 263 264 sprintf( text, "%.3f", num ); 265 len = strlen( text ); 266 EnsureAlloced( len + 1 ); 267 strcpy( m_data->data, text ); 268 m_data->len = len; 269 } 270 271 inline idStr::idStr 272 ( 273 const int num 274 ) : m_data ( NULL ) 275 276 { 277 char text[ 32 ]; 278 int len; 279 280 sprintf( text, "%d", num ); 281 len = strlen( text ); 282 EnsureAlloced( len + 1 ); 283 strcpy( m_data->data, text ); 284 m_data->len = len; 285 } 286 287 inline idStr::idStr 288 ( 289 const unsigned num 290 ) : m_data ( NULL ) 291 292 { 293 char text[ 32 ]; 294 int len; 295 296 sprintf( text, "%u", num ); 297 len = strlen( text ); 298 EnsureAlloced( len + 1 ); 299 strcpy( m_data->data, text ); 300 m_data->len = len; 301 } 302 303 inline int idStr::length( void ) const 304 { 305 return ( m_data != NULL ) ? m_data->len : 0; 306 } 307 308 inline int idStr::allocated( void ) const 309 { 310 return ( m_data != NULL ) ? m_data->alloced + sizeof( *m_data ) : 0; 311 } 312 313 inline const char *idStr::c_str( void ) const 314 { 315 assert( m_data ); 316 317 return m_data->data; 318 } 319 320 inline void idStr::append 321 ( 322 const char *text 323 ) 324 325 { 326 int len; 327 328 assert( text ); 329 330 if ( text ) 331 { 332 len = length() + strlen( text ); 333 EnsureAlloced( len + 1 ); 334 335 strcat( m_data->data, text ); 336 m_data->len = len; 337 } 338 } 339 340 inline void idStr::append 341 ( 342 const idStr& text 343 ) 344 345 { 346 int len; 347 348 len = length() + text.length(); 349 EnsureAlloced ( len + 1 ); 350 351 strcat ( m_data->data, text.c_str () ); 352 m_data->len = len; 353 } 354 355 inline char idStr::operator[]( int index ) const 356 { 357 assert ( m_data ); 358 359 if ( !m_data ) 360 return 0; 361 362 // don't include the '/0' in the test, because technically, it's out of bounds 363 assert( ( index >= 0 ) && ( index < m_data->len ) ); 364 365 // In release mode, give them a null character 366 // don't include the '/0' in the test, because technically, it's out of bounds 367 if ( ( index < 0 ) || ( index >= m_data->len ) ) 368 { 369 return 0; 370 } 371 372 return m_data->data[ index ]; 373 } 374 375 inline char& idStr::operator[] 376 ( 377 int index 378 ) 379 380 { 381 // Used for result for invalid indices 382 static char dummy = 0; 383 assert ( m_data ); 384 385 // We don't know if they'll write to it or not 386 // if it's not a const object 387 EnsureDataWritable (); 388 389 if ( !m_data ) 390 return dummy; 391 392 // don't include the '/0' in the test, because technically, it's out of bounds 393 assert( ( index >= 0 ) && ( index < m_data->len ) ); 394 395 // In release mode, let them change a safe variable 396 // don't include the '/0' in the test, because technically, it's out of bounds 397 if ( ( index < 0 ) || ( index >= m_data->len ) ) 398 { 399 return dummy; 400 } 401 402 return m_data->data[ index ]; 403 } 404 405 inline void idStr::operator= 406 ( 407 const idStr& text 408 ) 409 410 { 411 // adding the reference before deleting our current reference prevents 412 // us from deleting our string if we are copying from ourself 413 text.m_data->AddRef(); 414 m_data->DelRef(); 415 m_data = text.m_data; 416 } 417 418 inline void idStr::operator= 419 ( 420 const char *text 421 ) 422 423 { 424 int len; 425 426 assert( text ); 427 428 if ( !text ) 429 { 430 // safe behaviour if NULL 431 EnsureAlloced ( 1, false ); 432 m_data->data[0] = 0; 433 m_data->len = 0; 434 return; 435 } 436 437 if ( !m_data ) 438 { 439 len = strlen ( text ); 440 EnsureAlloced( len + 1, false ); 441 strcpy ( m_data->data, text ); 442 m_data->len = len; 443 return; 444 } 445 446 if ( text == m_data->data ) 447 return; // Copying same thing. Punt. 448 449 // If we alias and I don't do this, I could corrupt other strings... This 450 // will get called with EnsureAlloced anyway 451 EnsureDataWritable (); 452 453 // Now we need to check if we're aliasing.. 454 if ( text >= m_data->data && text <= m_data->data + m_data->len ) 455 { 456 // Great, we're aliasing. We're copying from inside ourselves. 457 // This means that I don't have to ensure that anything is alloced, 458 // though I'll assert just in case. 459 int diff = text - m_data->data; 460 int i; 461 462 assert ( strlen ( text ) < (unsigned) m_data->len ); 463 464 for ( i = 0; text[i]; i++ ) 465 { 466 m_data->data[i] = text[i]; 467 } 468 469 m_data->data[i] = 0; 470 471 m_data->len -= diff; 472 473 return; 474 } 475 476 len = strlen( text ); 477 EnsureAlloced ( len + 1, false ); 478 strcpy( m_data->data, text ); 479 m_data->len = len; 480 } 481 482 inline idStr operator+ 483 ( 484 const idStr& a, 485 const idStr& b 486 ) 487 488 { 489 idStr result( a ); 490 491 result.append( b ); 492 493 return result; 494 } 495 496 inline idStr operator+ 497 ( 498 const idStr& a, 499 const char *b 500 ) 501 502 { 503 idStr result( a ); 504 505 result.append( b ); 506 507 return result; 508 } 509 510 inline idStr operator+ 511 ( 512 const char *a, 513 const idStr& b 514 ) 515 516 { 517 idStr result( a ); 518 519 result.append( b ); 520 521 return result; 522 } 523 524 inline idStr operator+ 525 ( 526 const idStr& a, 527 const bool b 528 ) 529 530 { 531 idStr result( a ); 532 533 result.append( b ? "true" : "false" ); 534 535 return result; 536 } 537 538 inline idStr operator+ 539 ( 540 const idStr& a, 541 const char b 542 ) 543 544 { 545 char text[ 2 ]; 546 547 text[ 0 ] = b; 548 text[ 1 ] = 0; 549 550 return a + text; 551 } 552 553 inline idStr& idStr::operator+= 554 ( 555 const idStr& a 556 ) 557 558 { 559 append( a ); 560 return *this; 561 } 562 563 inline idStr& idStr::operator+= 564 ( 565 const char *a 566 ) 567 568 { 569 append( a ); 570 return *this; 571 } 572 573 inline idStr& idStr::operator+= 574 ( 575 const char a 576 ) 577 578 { 579 char text[ 2 ]; 580 581 text[ 0 ] = a; 582 text[ 1 ] = 0; 583 append( text ); 584 585 return *this; 586 } 587 588 inline idStr& idStr::operator+= 589 ( 590 const bool a 591 ) 592 593 { 594 append( a ? "true" : "false" ); 595 return *this; 596 } 597 598 inline bool operator== 599 ( 600 const idStr& a, 601 const idStr& b 602 ) 603 604 { 605 return ( !strcmp( a.c_str(), b.c_str() ) ); 606 } 607 608 inline bool operator== 609 ( 610 const idStr& a, 611 const char *b 612 ) 613 614 { 615 assert( b ); 616 if ( !b ) 617 { 618 return false; 619 } 620 return ( !strcmp( a.c_str(), b ) ); 621 } 622 623 inline bool operator== 624 ( 625 const char *a, 626 const idStr& b 627 ) 628 629 { 630 assert( a ); 631 if ( !a ) 632 { 633 return false; 634 } 635 return ( !strcmp( a, b.c_str() ) ); 636 } 637 638 inline bool operator!= 639 ( 640 const idStr& a, 641 const idStr& b 642 ) 643 644 { 645 return !( a == b ); 646 } 647 648 inline bool operator!= 649 ( 650 const idStr& a, 651 const char *b 652 ) 653 654 { 655 return !( a == b ); 656 } 657 658 inline bool operator!= 659 ( 660 const char *a, 661 const idStr& b 662 ) 663 664 { 665 return !( a == b ); 666 } 667 668 inline int idStr::icmpn 669 ( 670 const char *text, 671 int n 672 ) const 673 674 { 675 assert( m_data ); 676 assert( text ); 677 678 return idStr::icmpn( m_data->data, text, n ); 679 } 680 681 inline int idStr::icmpn 682 ( 683 const idStr& text, 684 int n 685 ) const 686 687 { 688 assert( m_data ); 689 assert( text.m_data ); 690 691 return idStr::icmpn( m_data->data, text.m_data->data, n ); 692 } 693 694 inline int idStr::icmp 695 ( 696 const char *text 697 ) const 698 699 { 700 assert( m_data ); 701 assert( text ); 702 703 return idStr::icmp( m_data->data, text ); 704 } 705 706 inline int idStr::icmp 707 ( 708 const idStr& text 709 ) const 710 711 { 712 assert( c_str () ); 713 assert( text.c_str () ); 714 715 return idStr::icmp( c_str () , text.c_str () ); 716 } 717 718 inline int idStr::cmp 719 ( 720 const char *text 721 ) const 722 723 { 724 assert( m_data ); 725 assert( text ); 726 727 return idStr::cmp( m_data->data, text ); 728 } 729 730 inline int idStr::cmp 731 ( 732 const idStr& text 733 ) const 734 735 { 736 assert( c_str () ); 737 assert( text.c_str () ); 738 739 return idStr::cmp( c_str () , text.c_str () ); 740 } 741 742 inline int idStr::cmpn 743 ( 744 const char *text, 745 int n 746 ) const 747 748 { 749 assert( c_str () ); 750 assert( text ); 751 752 return idStr::cmpn( c_str () , text, n ); 753 } 754 755 inline int idStr::cmpn 756 ( 757 const idStr& text, 758 int n 759 ) const 760 761 { 762 assert( c_str () ); 763 assert( text.c_str () ); 764 765 return idStr::cmpn( c_str () , text.c_str () , n ); 766 } 767 768 inline void idStr::tolower 769 ( 770 void 771 ) 772 773 { 774 assert( m_data ); 775 776 EnsureDataWritable (); 777 778 idStr::tolower( m_data->data ); 779 } 780 781 inline void idStr::toupper 782 ( 783 void 784 ) 785 786 { 787 assert( m_data ); 788 789 EnsureDataWritable (); 790 791 idStr::toupper( m_data->data ); 792 } 793 794 inline bool idStr::isNumeric 795 ( 796 void 797 ) const 798 799 { 800 assert( m_data ); 801 return idStr::isNumeric( m_data->data ); 802 } 803 804 inline idStr::operator const char *() { 805 return c_str(); 806 } 807 808 inline idStr::operator const char * 809 ( 810 void 811 ) const 812 813 { 814 return c_str (); 815 } 816 817 #endif