1 /**************************************************************************
2 ** (c) Copyright 1997, Andromeda Technology & Automation
3 ***************************************************************************
4 ** MODULE INFORMATION *
5 ***********************
6 ** FILE NAME : string.cpp
7 ** SYSTEM NAME : Andromeda X-Windows Encapsulation
8 ** VERSION NUMBER : $Revision: 1.5 $
10 ** DESCRIPTION : String class implementation.
15 ***************************************************************************
16 ** ADMINISTRATIVE INFORMATION *
17 ********************************
18 ** ORIGINAL AUTHOR : Arjen Baart - arjen@andromeda.nl
19 ** CREATION DATE : Nov 17, 1997
20 ** LAST UPDATE : Jun 12, 2020
21 **************************************************************************/
27 // Constructors and destructors for the String class
29 String::String() // Create an empty String
37 String::String(char c) // Create a String from a char
46 String::String(const char *s) // Create a String from a char *
55 p->s = new char[strlen(s)+1];
61 String::String(const String& x) // Create a String from another String
67 String::String(const substring &x)
71 p->s = new char[x.len+1];
72 strncpy(p->s, x.str->p->s+x.start, x.len);
73 p->s[x.len] = '\0'; // strncpy does not add the \0
77 String::String(const std::string &x)
82 p->s = new char[x.size()+1];
83 x.copy(p->s, x.size());
97 * Assignment operators must handle cleanup of their left-hand operand.
100 String& String::operator=(const char c)
117 String& String::operator=(const char *s)
129 p->s = new char[strlen(s)+1];
136 /* Make sure that assignment of an object to itself works correctly: */
138 String& String::operator=(const String& x)
151 String& String::operator=(const std::string &x)
162 p->s = new char[x.size()+1];
163 x.copy(p->s, x.size());
168 /* Numerical conversion */
170 String::String(int i)
173 p->s = new char[15]; // A little longer than needed...
174 sprintf(p->s, "%d", i);
178 String::String(long i)
181 p->s = new char[15]; // A little longer than needed...
182 sprintf(p->s, "%ld", i);
186 String::String(unsigned long i)
189 p->s = new char[15]; // A little longer than needed...
190 sprintf(p->s, "%lu", i);
194 String::String(double d)
197 p->s = new char[25]; // A little longer than needed...
198 sprintf(p->s, "%.3f", d);
202 /* String concatenation */
204 String& String::operator+=(const String& x)
206 char *s = new char[strlen(p->s) + strlen(x.p->s) + 1];
224 String& String::operator+=(const char * str)
226 char *s = new char[strlen(p->s) + strlen(str) + 1];
244 String operator+(const String& x, const String& y)
252 String operator+(const String& x, const char * y)
260 String operator+(const char * x, const String& y)
268 /* Shift operators */
271 String operator<<(const String &x, int n)
279 String & String::operator<<=(int n)
281 // Make sure we are the only one being shifted.
285 char *s = new char[strlen(p->s) + 1];
294 // Shift left means we really have to copy all characters.
296 int len = strlen(p->s);
301 // Shift more than we have: the String becomes empty.
306 for (i = 0; i <= len - n; i++)
315 String operator>>(const String &x, int n)
323 String & String::operator>>=(int n)
325 // Make sure we are the only one being shifted.
329 char *s = new char[strlen(p->s) + 1];
338 // Shift right is simple: just put the '\0' n places back.
341 int len = strlen(p->s);
345 // Shift more than we have: the String becomes empty.
350 p->s[len - n] = '\0';
356 /* Substring selection and assignment */
358 substring String::operator()(int start, int len)
363 _start = start; // Proper type conversion
365 if (_start > strlen(p->s) || _start + len > strlen(p->s))
367 throw StringException("Substring Out of bounds: ("
368 + String(start) + ", " + String(len) + ")");
376 String& substring::operator=(const String &x)
378 char *s = new char[strlen(x.p->s) + ~*str - len + 1];
380 strncpy(s, str->p->s, start);
383 strcat(s, str->p->s+start+len);
388 /* Input and output */
390 std::ostream& operator<<(std::ostream& s, const String& x)
397 std::istream& operator>>(std::istream& s, String& x)
404 buf = new char[bufsize];
411 // Buffer is too small. Allocate some new space.
413 char *newbuf = new char[bufsize * 2];
414 memcpy(newbuf, buf, bufsize);
423 while (s && buf[i] != '\n');
436 * The subscript operator is provided for access to individual characters
439 // TODO: Assignment to an individual character does not decouple references (BUG)
441 char& String::operator[](size_t i)
443 if (i >= strlen(p->s))
445 throw StringException("Out of bounds: " + String((int)i));
451 String String::upper()
456 up.p->s = new char[strlen(p->s)+1];
458 for(i=0; p->s[i]; i++)
460 up.p->s[i] = toupper(p->s[i]);
467 String String::lower()
472 low.p->s = new char[strlen(p->s)+1];
474 for(i=0; p->s[i]; i++)
476 low.p->s[i] = tolower(p->s[i]);
483 String String::escape()
485 const int BUFSIZE = 500;
487 char buffer[BUFSIZE];
489 int i; // Index in buffer[]
490 int j; // Index in *this
493 for (j = 0; p->s[j] != '\0'; j++)
554 if (p->s[j] > '\x20' && p->s[j] < '\x7F')
556 buffer[i++] = p->s[j];
562 // Turn into hexadecimal representation
566 nibble = (p->s[j] >> 4) & 0x0f;
567 buffer[i++] = nibble < 10 ? nibble + '0' : nibble - 10 + 'A';
568 nibble = p->s[j] & 0x0f;
569 buffer[i++] = nibble < 10 ? nibble + '0' : nibble - 10 + 'A';
581 String String::unescape()
586 unescaped.p->s = new char[strlen(p->s)+1];
647 while (*s >= '0' && *s <= '7')
658 s++; // Skip the initial 'x'
662 *d += *s > '9' ? toupper(*s) - 'A' + 10 : *s - '0';
685 // Find the first occurance of 'c'
687 int String::index(char c)
691 found = strchr(p->s, c);
698 // Find the last occurance of 'c'
700 int String::rindex(char c)
704 found = strrchr(p->s, c);
711 /* Find the first occurance of x */
713 int String::index(const char * x)
717 match = strstr(p->s, x);
724 /* Find the last occurance of x */
726 int String::rindex(const char * x)
728 char *match, *lastmatch;
730 match = strstr(p->s, x);
736 match = strstr(match + 1, x);
740 return lastmatch - p->s;
746 SuperString String::split(const String &separator)
748 SuperString splitted;
752 sep = strstr(p->s, separator.p->s);
756 // Create a new string from the part until the separator
758 int len = sep - part;
759 char *str = new char[len + 1];
761 strncpy(str, part, len);
763 splitted += String(str);
765 // Look for the next separator
769 sep = strstr(sep, separator.p->s);
772 // Add the leftover after the last separator.
774 splitted += String(part);
779 SuperString String::tokenize(const String &delim)
782 char *next_token, *save;
784 // The string to tokenize is modified, so we need to make a copy
786 char *str = new char[strlen(p->s) + 1];
789 next_token = strtok_r(str, delim.p->s, &save);
790 while (next_token != 0)
792 char *tok = new char[strlen(next_token) + 1];
793 strcpy(tok, next_token);
795 tokens += String(tok);
796 next_token = strtok_r(NULL, delim.p->s, &save);