remove $Id: tags after discussion on the mailign list: http://markmail.org/message...
[blender.git] / intern / string / intern / STR_String.cpp
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): none yet.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file string/intern/STR_String.cpp
29  *  \ingroup string
30  */
31
32
33 /**
34
35  * Copyright (C) 2001 NaN Technologies B.V.
36  * This file was formerly known as: GEN_StdString.cpp.
37  * @date        April, 25, 2001
38  */
39
40 #include <stdio.h>
41 #include <stdarg.h>
42 #include <stdlib.h> 
43 #include <ctype.h>
44 #include <string.h>
45 #if defined(__sun__) || defined( __sun ) || defined (__sparc) || defined (__sparc__) || defined (_AIX)
46 #  include <strings.h>
47 #endif
48 #include "STR_String.h"
49
50 /*-------------------------------------------------------------------------------------------------
51         Construction / destruction
52 -------------------------------------------------------------------------------------------------*/
53
54
55
56 //
57 // Construct an empty string
58 //
59 STR_String::STR_String() :
60         pData(new char [32]), 
61         Len(0),
62         Max(32)
63 {
64         pData[0] = 0;
65 }
66
67
68
69 //
70 // Construct a string of one character
71 //
72 STR_String::STR_String(char c) :
73         pData(new char [9]),
74         Len(1),
75         Max(9)
76 {
77         pData[0] = c;
78         pData[1] = 0;
79 }
80
81
82
83 //
84 // Construct a string of multiple repeating characters
85 //
86 STR_String::STR_String(char c, int len) :
87         pData(new char [len+8]),
88         Len(len),
89         Max(len+8)
90 {
91         assertd(pData != NULL);
92         memset(pData, c, len);
93         pData[len] = 0;
94 }
95
96
97
98 //
99 // Construct a string from a pointer-to-ASCIIZ-string
100 //
101 // MAART: Changed to test for null strings
102 STR_String::STR_String(const char *str)
103 {
104         if (str) {
105                 Len = ::strlen(str);
106                 Max = Len + 8;
107                 pData = new char [Max];
108                 assertd(pData != NULL);
109                 ::memcpy(pData, str, Len);
110                 pData[Len] = 0;
111         }
112         else {
113                 pData = 0;
114                 Len = 0;
115                 Max = 8;
116         }
117 }
118
119
120
121 //
122 // Construct a string from a pointer-to-ASCII-string and a length
123 //
124 STR_String::STR_String(const char *str, int len) :
125         pData(new char [len+8]),
126         Len(len),
127         Max(len+8)
128 {
129         assertd(pData != NULL);
130         memcpy(pData, str, len);
131         pData[len] = 0;
132 }
133
134
135
136 //
137 // Construct a string from another string
138 //
139 STR_String::STR_String(rcSTR_String str) :
140         pData(new char [str.Length()+8]),
141         Len(str.Length()),
142         Max(str.Length()+8)
143 {
144         assertd(pData != NULL);
145         assertd(str.pData != NULL);
146         memcpy(pData, str.pData, str.Length());
147         pData[str.Length()] = 0;
148 }
149
150
151
152 //
153 // Construct a string from the first number of characters in another string
154 //
155 STR_String::STR_String(rcSTR_String str, int len) :
156         pData(new char [len+8]),
157         Len(len),
158         Max(len+8)
159 {
160         assertd(pData != NULL);
161         assertd(str.pData != NULL);
162         memcpy(pData, str.pData, str.Length());
163         pData[str.Length()] = 0;
164 }
165
166
167
168 //
169 // Create a string by concatenating two sources
170 //
171 STR_String::STR_String(const char *src1, int len1, const char *src2, int len2) :
172         pData(new char [len1+len2+8]),
173         Len(len1+len2),
174         Max(len1+len2+8)
175 {
176         assertd(pData != NULL);
177         memcpy(pData, src1, len1);
178         memcpy(pData+len1, src2, len2);
179         pData[len1+len2] = 0;
180 }
181
182
183
184 //
185 // Create a string with an integer value
186 //
187 STR_String::STR_String(int val) :
188         pData(new char [32]),
189         Max(32)
190 {
191         assertd(pData != NULL);
192         Len=sprintf(pData, "%d", val);
193 }
194         
195
196
197
198 //
199 // Create a string with a dword value
200 //
201 STR_String::STR_String(dword val) :
202         pData(new char [32]),
203         Max(32)
204 {
205         assertd(pData != NULL);
206         Len=sprintf(pData, "%lu", val);
207 }
208
209
210
211 //
212 // Create a string with a floating point value
213 //
214 STR_String::STR_String(float val) :
215         pData(new char [32]),
216         Max(32)
217 {
218         assertd(pData != NULL);
219         Len=sprintf(pData, "%g", val);
220 }
221
222
223
224 //
225 // Create a string with a double value
226 //
227 STR_String::STR_String(double val) :
228         pData(new char [32]),
229         Max(32)
230 {
231         assertd(pData != NULL);
232         Len=sprintf(pData, "%g", val);
233 }
234
235
236
237 /*-------------------------------------------------------------------------------------------------
238         Buffer management
239 -------------------------------------------------------------------------------------------------*/
240
241
242
243 //
244 // Make sure that the allocated buffer is at least <len> in size
245 //
246 void STR_String::AllocBuffer(int len, bool keep_contents)
247 {
248         // Check if we have enough space
249         if (len+1 <= Max) return;
250
251         // Reallocate string
252         char *new_data = new char [len+8];
253         if (keep_contents) memcpy(new_data, pData, Len);
254         delete[] pData;
255
256         // Accept new data
257         Max = len+8;
258         pData = new_data;
259         assertd(pData != NULL);
260 }
261         
262
263
264 /*-------------------------------------------------------------------------------------------------
265         Basic string operations
266 -------------------------------------------------------------------------------------------------*/
267
268
269
270 //
271 // Format string (as does sprintf)
272 //
273 STR_String& STR_String::Format(const char *fmt, ...)
274 {
275         AllocBuffer(2048, false);
276
277         assertd(pData != NULL);
278         // Expand arguments and format to string
279         va_list args;
280         va_start(args, fmt);
281         Len = vsprintf(pData, fmt, args);
282         assertd(Len <= 2048);
283         va_end(args);
284
285         return *this;
286 }
287
288
289
290 //
291 // Format string (as does sprintf)
292 //
293 STR_String& STR_String::FormatAdd(const char *fmt, ...)
294 {
295         AllocBuffer(2048, false);
296
297         assertd(pData != NULL);
298         // Expand arguments and format to string
299         va_list args;
300         va_start(args, fmt);
301         Len += vsprintf(pData+Len, fmt, args);
302         assertd(Len <= 2048);
303         va_end(args);
304
305         return *this;
306 }
307
308
309
310 /*-------------------------------------------------------------------------------------------------
311         Properties
312 -------------------------------------------------------------------------------------------------*/
313
314
315
316 //
317 // Check if string is entirely in UPPERCase
318 //
319 bool STR_String::IsUpper() const
320 {
321         for (int i=0; i<Len; i++)
322                 if (isLower(pData[i]))
323                         return false;
324
325         return true;
326 }
327
328
329
330 //
331 // Check if string is entirely in lowerCase
332 //
333 bool STR_String::IsLower() const
334 {
335         for (int i=0; i<Len; i++)
336                 if (isUpper(pData[i]))
337                         return false;
338
339         return true;
340 }
341
342
343
344 /*-------------------------------------------------------------------------------------------------
345         Search/Replace
346 -------------------------------------------------------------------------------------------------*/
347
348
349
350 //
351 // Find the first orccurence of <c> in the string
352 //
353 int STR_String::Find(char c, int pos) const
354 {
355         assertd(pos >= 0);
356         assertd(Len==0 || pos<Len);
357         assertd(pData != NULL);
358         char *find_pos = strchr(pData+pos, c);
359         return (find_pos) ? (find_pos-pData) : -1;
360 }
361
362
363
364 //
365 // Find the first occurrence of <str> in the string
366 //
367 int     STR_String::Find(const char *str, int pos) const
368 {
369         assertd(pos >= 0);
370         assertd(Len==0 || pos<Len);
371         assertd(pData != NULL);
372         char *find_pos = strstr(pData+pos, str);
373         return (find_pos) ? (find_pos-pData) : -1;
374 }
375
376
377
378 //
379 // Find the first occurrence of <str> in the string
380 //
381 int     STR_String::Find(rcSTR_String str, int pos) const
382 {
383         assertd(pos >= 0);
384         assertd(Len==0 || pos<Len);
385         assertd(pData != NULL);
386         char *find_pos = strstr(pData+pos, str.ReadPtr());
387         return (find_pos) ? (find_pos-pData) : -1;
388 }
389
390
391
392 //
393 // Find the last occurrence of <c> in the string
394 //
395 int STR_String::RFind(char c) const
396 {
397         assertd(pData != NULL);
398         char *pos = strrchr(pData, c);
399         return (pos) ? (pos-pData) : -1;
400 }
401
402
403
404 //
405 // Find the first occurrence of any character in character set <set> in the string
406 //
407 int STR_String::FindOneOf(const char *set, int pos) const
408 {
409         assertd(pos >= 0);
410         assertd(Len==0 || pos<Len);
411         assertd(pData != NULL);
412         char *find_pos = strpbrk(pData+pos, set);
413         return (find_pos) ? (find_pos-pData) : -1;
414 }
415
416
417
418 //
419 // Replace a character in this string with another string
420 //
421 void STR_String::Replace(int pos, rcSTR_String str)
422 {
423         //bounds(pos, 0, Length()-1);
424
425         if (str.Length() < 1)
426         {
427                 // Remove one character from the string
428                 memcpy(pData+pos, pData+pos+1, Len-pos);
429         }
430         else
431         {
432                 // Insert zero or more characters into the string
433                 AllocBuffer(Len + str.Length() - 1, true);
434                 if (str.Length() != 1) memcpy(pData+pos+str.Length(), pData+pos+1, Length()-pos);
435                 memcpy(pData+pos, str.ReadPtr(), str.Length());
436         }
437
438         Len += str.Length()-1;
439 }
440
441
442
443 //
444 // Replace a substring of this string with another string
445 //
446 void STR_String::Replace(int pos, int num, rcSTR_String str)
447 {
448         //bounds(pos, 0, Length()-1);
449         //bounds(pos+num, 0, Length());
450         assertd(num >= 1);
451
452         if (str.Length() < num)
453         {
454                 // Remove some data from the string by replacement
455                 memcpy(pData+pos+str.Length(), pData+pos+num, Len-pos-num+1);
456                 memcpy(pData+pos, str.ReadPtr(), str.Length());
457         }
458         else
459         {
460                 // Insert zero or more characters into the string
461                 AllocBuffer(Len + str.Length() - num, true);
462                 if (str.Length() != num) memcpy(pData+pos+str.Length(), pData+pos+num, Length()-pos-num+1);
463                 memcpy(pData+pos, str.ReadPtr(), str.Length());
464         }
465
466         Len += str.Length()-num;
467 }
468
469
470
471 /*-------------------------------------------------------------------------------------------------
472         Comparison
473 -------------------------------------------------------------------------------------------------*/
474
475
476
477 //
478 // Compare two strings and return the result, <0 if *this<rhs, >0 if *this>rhs or 0 if *this==rhs
479 //
480 int     STR_String::Compare(rcSTR_String rhs) const
481 {
482         return strcmp(pData, rhs.pData);
483 }
484
485
486
487 //
488 // Compare two strings without respecting case and return the result, <0 if *this<rhs, >0 if *this>rhs or 0 if *this==rhs
489 //
490 int STR_String::CompareNoCase(rcSTR_String rhs) const
491 {
492 #ifdef WIN32
493         return stricmp(pData, rhs.pData);
494 #else
495         return strcasecmp(pData, rhs.pData);
496 #endif
497 }
498
499
500
501 /*-------------------------------------------------------------------------------------------------
502         Formatting
503 -------------------------------------------------------------------------------------------------*/
504
505
506
507 //
508 // Capitalize string, "heLLo" -> "HELLO"
509 //
510 STR_String&     STR_String::Upper()
511 {
512         assertd(pData != NULL);
513 #ifdef WIN32
514         _strupr(pData);
515 #else
516         for (int i=0;i<Len;i++)
517                 pData[i] = (pData[i] >= 'a' && pData[i] <= 'z')?pData[i]+'A'-'a':pData[i];
518 #endif
519         return *this;
520 }
521
522
523
524 //
525 // Lower string, "heLLo" -> "hello"
526 //
527 STR_String&     STR_String::Lower()
528 {
529         assertd(pData != NULL);
530 #ifdef WIN32
531         _strlwr(pData);
532 #else
533         for (int i=0;i<Len;i++)
534                 pData[i] = (pData[i] >= 'A' && pData[i] <= 'Z')?pData[i]+'a'-'A':pData[i];
535 #endif
536         return *this;
537 }
538
539
540
541 //
542 // Capitalize string, "heLLo" -> "Hello"
543 //
544 STR_String&     STR_String::Capitalize()
545 {
546         assertd(pData != NULL);
547 #ifdef WIN32
548         if (Len>0) pData[0] = toupper(pData[0]);
549         if (Len>1) _strlwr(pData+1);
550 #else
551         if (Len > 0)
552                 pData[0] = (pData[0] >= 'A' && pData[0] <= 'A')?pData[0]+'a'-'A':pData[0];
553         for (int i=1;i<Len;i++)
554                 pData[i] = (pData[i] >= 'a' && pData[i] <= 'z')?pData[i]+'A'-'a':pData[i];
555 #endif
556         return *this;
557 }
558
559
560
561 //
562 // Trim whitespace from the left side of the string
563 //
564 STR_String&     STR_String::TrimLeft()
565 {
566         int skip;
567         assertd(pData != NULL);
568         for (skip=0; isSpace(pData[skip]); skip++, Len--)
569                 {};
570         memmove(pData, pData+skip, Len+1);
571         return *this;
572 }
573
574
575
576 //
577 // Trim whitespaces from the right side of the string
578 //
579 STR_String&     STR_String::TrimRight()
580 {
581         assertd(pData != NULL);
582         while (Len && isSpace(pData[Len-1])) Len--;
583         pData[Len]=0;
584         return *this;
585 }
586
587
588
589 //
590 // Trim spaces from both sides of the character set
591 //
592 STR_String&     STR_String::Trim()
593 {
594         TrimRight();
595         TrimLeft();
596         return *this;
597 }
598
599
600
601 //
602 // Trim characters from the character set <set> from the left side of the string
603 //
604 STR_String&     STR_String::TrimLeft(char *set)
605 {
606         int skip;
607         assertd(pData != NULL);
608         for (skip=0; Len && strchr(set, pData[skip]); skip++, Len--)
609                 {};
610         memmove(pData, pData+skip, Len+1);
611         return *this;
612 }
613
614
615
616 //
617 // Trim characters from the character set <set> from the right side of the string
618 //
619 STR_String&     STR_String::TrimRight(char *set)
620 {
621         assertd(pData != NULL);
622         while (Len && strchr(set, pData[Len-1])) Len--;
623         pData[Len]=0;
624         return *this;
625 }
626
627
628
629 //
630 // Trim characters from the character set <set> from both sides of the character set
631 //
632 STR_String&     STR_String::Trim(char *set)
633 {
634         TrimRight(set);
635         TrimLeft(set);
636         return *this;
637 }
638
639
640
641 //
642 // Trim quotes from both sides of the string
643 //
644 STR_String&     STR_String::TrimQuotes()
645 {
646         // Trim quotes if they are on both sides of the string
647         assertd(pData != NULL);
648         if ((Len >= 2) && (pData[0] == '\"') && (pData[Len-1] == '\"'))
649         {
650                 memmove(pData, pData+1, Len-2+1);
651                 Len-=2;
652         }
653         return *this;
654 }
655
656
657
658 /*-------------------------------------------------------------------------------------------------
659         Assignment/Concatenation
660 -------------------------------------------------------------------------------------------------*/
661
662
663
664 //
665 // Set the string's conents to a copy of <src> with length <len>
666 //
667 rcSTR_String STR_String::Copy(const char *src, int len)
668 {
669         assertd(len>=0);
670         assertd(src);
671         assertd(pData != NULL);
672
673         AllocBuffer(len, false);
674         Len = len;
675         memcpy(pData, src, len);
676         pData[Len] = 0;
677
678         return *this;
679 }
680
681
682
683 //
684 // Concate a number of bytes to the current string
685 //
686 rcSTR_String STR_String::Concat(const char *data, int len)
687 {
688         assertd(Len>=0);
689         assertd(len>=0);
690         assertd(data);
691         assertd(pData != NULL);
692
693         AllocBuffer(Len+len, true);
694         memcpy(pData+Len, data, len);
695         Len+=len;
696         pData[Len] = 0;
697
698         return *this;
699 }
700
701
702
703
704
705 vector<STR_String>      STR_String::Explode(char c) const
706 {
707         STR_String                              lcv     = *this;
708         vector<STR_String>              uc;
709
710         while (lcv.Length())
711         {
712                 int pos = lcv.Find(c);
713                 if (pos < 0)
714                 {
715                         uc.push_back(lcv);
716                         lcv.Clear();
717                 } else
718                 {
719                         uc.push_back(lcv.Left(pos));
720                         lcv = lcv.Mid(pos+1);
721                 }
722         }
723
724         //uc. -= STR_String("");
725
726         return uc;
727 }
728
729
730 /*
731
732 int             STR_String::Serialize(pCStream stream)
733 {
734         if (stream->GetAccess() == CStream::Access_Read)
735         {
736                 int ln;
737                 stream->Read(&ln, sizeof(ln));
738                 AllocBuffer(ln, false);
739                 stream->Read(pData, ln); 
740                 pData[ln]       = '\0';
741                 Len                     = ln;
742         } else
743         {
744                 stream->Write(&Len, sizeof(Len));
745                 stream->Write(pData, Len);
746         }
747
748         return Len + sizeof(Len);
749 }
750 */
751