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