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