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