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