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