remove RSA's md4.c, replace by DP's
[xonotic/netradiant.git] / libs / splines / util_str.cpp
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 #include "util_str.h"
25 #include <stdlib.h>
26 #include <ctype.h>
27 #include <stdio.h>
28 #include <stdarg.h>
29
30 #ifdef _WIN32
31 #pragma warning(disable : 4244)     // 'conversion' conversion from 'type1' to 'type2', possible loss of data
32 #pragma warning(disable : 4710)     // function 'blah' not inlined
33 #endif
34
35 static const int STR_ALLOC_GRAN = 20;
36
37 // screwy but intentional
38 #ifdef __APPLE_BUG__
39 char *idStr::__tolower
40 #else
41 char *idStr::tolower
42 #endif
43    (
44    char *s1
45    )
46    
47    {
48    char *s;
49
50    s = s1;
51         while( *s )
52       {
53       *s = ::tolower( *s );
54                 s++;
55            }
56    
57    return s1;
58    }
59
60 // screwy but intentional
61 #ifdef __APPLE_BUG__
62 char *idStr::__toupper
63 #else
64 char *idStr::toupper
65 #endif
66    (
67    char *s1
68    )
69    
70    {
71    char *s;
72
73    s = s1;
74         while( *s )
75       {
76       *s = ::toupper( *s );
77                 s++;
78            }
79    
80    return s1;
81    }
82
83 int idStr::icmpn
84    (
85    const char *s1, 
86    const char *s2, 
87    int n
88    )
89    
90    {
91         int c1;
92    int c2;
93         
94         do 
95       {
96                 c1 = *s1++;
97                 c2 = *s2++;
98
99                 if ( !n-- )
100          {
101          // idStrings are equal until end point
102                         return 0;
103                    }
104                 
105                 if ( c1 != c2 )
106          {
107                         if ( c1 >= 'a' && c1 <= 'z' )
108             {
109                                 c1 -= ( 'a' - 'A' );
110                            }
111
112                         if ( c2 >= 'a' && c2 <= 'z' )
113             {
114                                 c2 -= ( 'a' - 'A' );
115                            }
116
117                         if ( c1 < c2 )
118             {
119             // strings less than
120                                 return -1;
121                            }
122          else if ( c1 > c2 ) 
123             {
124             // strings greater than
125             return 1;
126             }
127                    }
128            } 
129    while( c1 );
130         
131    // strings are equal
132         return 0;
133    }
134
135 int idStr::icmp
136    (
137    const char *s1,
138    const char *s2
139    )
140    
141    {
142         int c1;
143    int c2;
144         
145         do 
146       {
147                 c1 = *s1++;
148                 c2 = *s2++;
149
150                 if ( c1 != c2 )
151          {
152                         if ( c1 >= 'a' && c1 <= 'z' )
153             {
154                                 c1 -= ( 'a' - 'A' );
155                            }
156
157                         if ( c2 >= 'a' && c2 <= 'z' )
158             {
159                                 c2 -= ( 'a' - 'A' );
160                            }
161
162                         if ( c1 < c2 )
163             {
164             // strings less than
165                                 return -1;
166                            }
167          else if ( c1 > c2 ) 
168             {
169             // strings greater than
170             return 1;
171             }
172                    }
173            } 
174    while( c1 );
175         
176    // strings are equal
177         return 0;
178    }
179
180 int idStr::cmpn
181    (
182    const char *s1, 
183    const char *s2, 
184    int n
185    )
186    
187    {
188         int c1;
189    int c2;
190         
191         do 
192       {
193                 c1 = *s1++;
194                 c2 = *s2++;
195
196                 if ( !n-- )
197          {
198          // strings are equal until end point
199                         return 0;
200                    }
201                 
202                 if ( c1 < c2 )
203          {
204          // strings less than
205                         return -1;
206                         }
207       else if ( c1 > c2 ) 
208          {
209          // strings greater than
210          return 1;
211          }
212            } 
213    while( c1 );
214         
215    // strings are equal
216         return 0;
217    }
218
219 int idStr::cmp
220    (
221    const char *s1, 
222    const char *s2
223    )
224    
225    {
226         int c1;
227    int c2;
228         
229         do 
230       {
231                 c1 = *s1++;
232                 c2 = *s2++;
233
234                 if ( c1 < c2 )
235          {
236          // strings less than
237                         return -1;
238                         }
239       else if ( c1 > c2 ) 
240          {
241          // strings greater than
242          return 1;
243          }
244            } 
245    while( c1 );
246         
247    // strings are equal
248         return 0;
249    }
250
251 /*
252 ============
253 IsNumeric
254
255 Checks a string to see if it contains only numerical values.
256 ============
257 */
258 bool idStr::isNumeric
259    (
260    const char *str
261    )
262
263    {
264         int len;
265         int i;
266         bool dot;
267
268         if ( *str == '-' )
269                 {
270                 str++;
271                 }
272
273         dot = false;
274         len = strlen( str );
275         for( i = 0; i < len; i++ )
276                 {
277                 if ( !isdigit( str[ i ] ) )
278                         {
279                         if ( ( str[ i ] == '.' ) && !dot )
280                                 {
281                                 dot = true;
282                                 continue;
283                                 }
284                         return false;
285                         }
286                 }
287
288         return true;
289    }
290
291 idStr operator+
292    (
293    const idStr& a,
294    const float b
295    )
296
297    {
298    char text[ 20 ];
299
300         idStr result( a );
301
302    sprintf( text, "%f", b );
303         result.append( text );
304
305         return result;
306    }
307
308 idStr operator+
309    (
310    const idStr& a,
311    const int b
312    )
313
314    {
315    char text[ 20 ];
316
317         idStr result( a );
318
319    sprintf( text, "%d", b );
320         result.append( text );
321
322         return result;
323    }
324
325 idStr operator+
326    (
327    const idStr& a,
328    const unsigned b
329    )
330
331    {
332    char text[ 20 ];
333
334         idStr result( a );
335
336    sprintf( text, "%u", b );
337         result.append( text );
338
339         return result;
340    }
341
342 idStr& idStr::operator+=
343         (
344         const float a
345         )
346
347         {
348    char text[ 20 ];
349
350    sprintf( text, "%f", a );
351         append( text );
352
353    return *this;
354         }
355
356 idStr& idStr::operator+=
357         (
358         const int a
359         )
360
361         {
362    char text[ 20 ];
363
364    sprintf( text, "%d", a );
365         append( text );
366
367    return *this;
368         }
369
370 idStr& idStr::operator+=
371         (
372         const unsigned a
373         )
374
375         {
376    char text[ 20 ];
377
378    sprintf( text, "%u", a );
379         append( text );
380
381    return *this;
382         }
383
384 void idStr::CapLength 
385    (
386    int newlen 
387    )
388
389    {
390    assert ( m_data );
391    
392    if ( length() <= newlen )
393       return;
394
395    EnsureDataWritable ();
396
397    m_data->data[newlen] = 0;
398    m_data->len = newlen;
399    }
400
401 void idStr::EnsureDataWritable 
402    (
403    void
404    )
405
406    {
407    assert ( m_data );
408    strdata *olddata;
409    int len;
410
411    if ( !m_data->refcount )
412       return;
413
414    olddata = m_data;
415    len = length();
416
417    m_data = new strdata;
418
419    EnsureAlloced ( len + 1, false );
420    strncpy ( m_data->data, olddata->data, len+1 );
421    m_data->len = len;
422
423    olddata->DelRef ();
424    }
425
426 void idStr::EnsureAlloced (int amount, bool keepold) {
427
428         if ( !m_data ) {
429       m_data = new strdata();
430         }
431    
432         // Now, let's make sure it's writable
433         EnsureDataWritable ();
434
435         char *newbuffer;
436         bool wasalloced = ( m_data->alloced != 0 );
437
438         if ( amount < m_data->alloced ) {
439                 return;
440         }
441
442         assert ( amount );
443         if ( amount == 1 ) {
444                 m_data->alloced = 1;
445         } else {
446                 int newsize, mod;
447                 mod = amount % STR_ALLOC_GRAN;
448                 if ( !mod ) {
449                         newsize = amount;
450                 } else {
451          newsize = amount + STR_ALLOC_GRAN - mod;
452                 }
453                 m_data->alloced = newsize;
454         }
455
456         newbuffer = new char[m_data->alloced];
457         if ( wasalloced && keepold ) {
458                 strcpy ( newbuffer, m_data->data );
459         }
460
461         if ( m_data->data ) {
462                 delete [] m_data->data;
463     }
464         m_data->data = newbuffer;
465 }
466
467 void idStr::BackSlashesToSlashes
468    (
469    void
470    )
471
472    {
473    int i;
474
475    EnsureDataWritable ();
476
477    for ( i=0; i < m_data->len; i++ )
478       {
479       if ( m_data->data[i] == '\\' )
480          m_data->data[i] = '/';
481       }
482    }
483
484 void idStr::snprintf 
485    (
486    char *dst,
487    int size,
488    const char *fmt, 
489    ...
490    )
491
492    {
493    char buffer[0x10000];
494         int             len;
495         va_list         argptr;
496
497         va_start (argptr,fmt);
498         len = vsprintf (buffer,fmt,argptr);
499         va_end (argptr);
500         
501    assert ( len < size );
502
503    strncpy (dst, buffer, size-1);
504    }
505
506 #ifdef _WIN32
507 #pragma warning(disable : 4189)         // local variable is initialized but not referenced
508 #endif
509
510 /*
511 =================
512 TestStringClass
513
514 This is a fairly rigorous test of the idStr class's functionality.
515 Because of the fairly global and subtle ramifications of a bug occuring
516 in this class, it should be run after any changes to the class.
517 Add more tests as functionality is changed.  Tests should include
518 any possible bounds violation and NULL data tests.
519 =================
520 */
521 void TestStringClass
522         (
523         void 
524         )
525
526         {
527         char    ch;                                                     // ch == ?
528         idStr   *t;                                                     // t == ?
529         idStr   a;                                                              // a.len == 0, a.data == "\0"
530         idStr   b;                                                              // b.len == 0, b.data == "\0"
531         idStr   c( "test" );                            // c.len == 4, c.data == "test\0"
532         idStr   d( c );                                         // d.len == 4, d.data == "test\0"
533         idStr   e( reinterpret_cast<const char *>(NULL) );                                      
534                                  // e.len == 0, e.data == "\0"                                  ASSERT!
535         int     i;                                                              // i == ?
536
537         i = a.length();                                 // i == 0
538         i = c.length();                                 // i == 4
539
540         const char *s1 = a.c_str();     // s1 == "\0"
541         const char *s2 = c.c_str();     // s2 == "test\0"
542
543         t = new idStr();                                                // t->len == 0, t->data == "\0"
544         delete t;                                                       // t == ?
545
546         b = "test";                                                     // b.len == 4, b.data == "test\0"
547         t = new idStr( "test" );                        // t->len == 4, t->data == "test\0"
548         delete t;                                                       // t == ?
549
550         a = c;                                                          // a.len == 4, a.data == "test\0"
551 //   a = "";
552    a = NULL;                                                    // a.len == 0, a.data == "\0"                                   ASSERT!
553         a = c + d;                                                      // a.len == 8, a.data == "testtest\0"
554         a = c + "wow";                                          // a.len == 7, a.data == "testwow\0"
555         a = c + reinterpret_cast<const char *>(NULL);
556                                  // a.len == 4, a.data == "test\0"                      ASSERT!
557         a = "this" + d;                                 // a.len == 8, a.data == "thistest\0"
558         a = reinterpret_cast<const char *>(NULL) + d;
559                                  // a.len == 4, a.data == "test\0"                      ASSERT!
560         a += c;                                                         // a.len == 8, a.data == "testtest\0"
561         a += "wow";                                                     // a.len == 11, a.data == "testtestwow\0"
562         a += reinterpret_cast<const char *>(NULL);
563                                  // a.len == 11, a.data == "testtestwow\0"      ASSERT!
564
565         a = "test";                                                     // a.len == 4, a.data == "test\0"
566         ch = a[ 0 ];                                            // ch == 't'
567         ch = a[ -1 ];                                           // ch == 0                                                                                      ASSERT!
568         ch = a[ 1000 ];                                 // ch == 0                                                                                      ASSERT!
569         ch = a[ 0 ];                                            // ch == 't'
570         ch = a[ 1 ];                                            // ch == 'e'
571         ch = a[ 2 ];                                            // ch == 's'
572         ch = a[ 3 ];                                            // ch == 't'
573         ch = a[ 4 ];                                            // ch == '\0'                                                                           ASSERT!
574         ch = a[ 5 ];                                            // ch == '\0'                                                                           ASSERT!
575
576         a[ 1 ] = 'b';                                           // a.len == 4, a.data == "tbst\0"
577         a[ -1 ] = 'b';                                          // a.len == 4, a.data == "tbst\0"                       ASSERT!
578         a[ 0 ] = '0';                                           // a.len == 4, a.data == "0bst\0"
579         a[ 1 ] = '1';                                           // a.len == 4, a.data == "01st\0"
580         a[ 2 ] = '2';                                           // a.len == 4, a.data == "012t\0"
581         a[ 3 ] = '3';                                           // a.len == 4, a.data == "0123\0"
582         a[ 4 ] = '4';                                           // a.len == 4, a.data == "0123\0"                       ASSERT!
583         a[ 5 ] = '5';                                           // a.len == 4, a.data == "0123\0"                       ASSERT!
584         a[ 7 ] = '7';                                           // a.len == 4, a.data == "0123\0"                       ASSERT!
585
586         a = "test";                                                     // a.len == 4, a.data == "test\0"
587         b = "no";                                                       // b.len == 2, b.data == "no\0"
588
589         i = ( a == b );                                 // i == 0
590         i = ( a == c );                                 // i == 1
591
592         i = ( a == "blow" );                            // i == 0
593         i = ( a == "test" );                            // i == 1
594         i = ( a == NULL );                              // i == 0                                                                                       ASSERT!
595
596         i = ( "test" == b );                            // i == 0
597         i = ( "test" == a );                            // i == 1
598         i = ( NULL == a );                              // i == 0                                                                                       ASSERT!
599
600         i = ( a != b );                                 // i == 1
601         i = ( a != c );                                 // i == 0
602
603         i = ( a != "blow" );                            // i == 1
604         i = ( a != "test" );                            // i == 0
605         i = ( a != NULL );                              // i == 1                                                                                       ASSERT!
606
607         i = ( "test" != b );                            // i == 1
608         i = ( "test" != a );                            // i == 0
609         i = ( NULL != a );                              // i == 1                                                                                       ASSERT!
610
611    a = "test";                   // a.data == "test"
612    b = a;                        // b.data == "test"
613
614    a = "not";                   // a.data == "not", b.data == "test"
615
616    a = b;                        // a.data == b.data == "test"
617
618    a += b;                       // a.data == "testtest", b.data = "test"
619
620    a = b;
621
622    a[1] = '1';                   // a.data = "t1st", b.data = "test"
623         }
624
625 #ifdef _WIN32
626 #pragma warning(default : 4189)         // local variable is initialized but not referenced
627 #pragma warning(disable : 4514)     // unreferenced inline function has been removed
628 #endif