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