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
87 * Assignment operators must handle cleanup of their left-hand operand.
90 String& String::operator=(const char c)
107 String& String::operator=(const char *s)
119 p->s = new char[strlen(s)+1];
126 /* Make sure that assignment of an object to itself works correctly: */
128 String& String::operator=(const String& x)
141 /* Numerical conversion */
143 String::String(int i)
146 p->s = new char[15]; // A little longer than needed...
147 sprintf(p->s, "%d", i);
151 String::String(long i)
154 p->s = new char[15]; // A little longer than needed...
155 sprintf(p->s, "%ld", i);
159 String::String(unsigned long i)
162 p->s = new char[15]; // A little longer than needed...
163 sprintf(p->s, "%lu", i);
167 String::String(double d)
170 p->s = new char[25]; // A little longer than needed...
171 sprintf(p->s, "%.3f", d);
175 /* String concatenation */
177 String& String::operator+=(const String& x)
179 char *s = new char[strlen(p->s) + strlen(x.p->s) + 1];
197 String& String::operator+=(const char * str)
199 char *s = new char[strlen(p->s) + strlen(str) + 1];
217 String operator+(const String& x, const String& y)
225 String operator+(const String& x, const char * y)
233 String operator+(const char * x, const String& y)
241 /* Shift operators */
244 String operator<<(const String &x, int n)
252 String & String::operator<<=(int n)
254 // Make sure we are the only one being shifted.
258 char *s = new char[strlen(p->s) + 1];
267 // Shift left means we really have to copy all characters.
269 int len = strlen(p->s);
274 // Shift more than we have: the String becomes empty.
279 for (i = 0; i <= len - n; i++)
288 String operator>>(const String &x, int n)
296 String & String::operator>>=(int n)
298 // Make sure we are the only one being shifted.
302 char *s = new char[strlen(p->s) + 1];
311 // Shift right is simple: just put the '\0' n places back.
314 int len = strlen(p->s);
318 // Shift more than we have: the String becomes empty.
323 p->s[len - n] = '\0';
329 /* Substring selection and assignment */
331 substring String::operator()(int start, int len)
336 _start = start; // Proper type conversion
338 if (_start > strlen(p->s) || _start + len > strlen(p->s))
340 throw StringException("Substring Out of bounds: ("
341 + String(start) + ", " + String(len) + ")");
349 String& substring::operator=(const String &x)
351 char *s = new char[strlen(x.p->s) + ~*str - len + 1];
353 strncpy(s, str->p->s, start);
356 strcat(s, str->p->s+start+len);
361 /* Input and output */
363 std::ostream& operator<<(std::ostream& s, const String& x)
370 std::istream& operator>>(std::istream& s, String& x)
377 buf = new char[bufsize];
384 // Buffer is too small. Allocate some new space.
386 char *newbuf = new char[bufsize * 2];
387 memcpy(newbuf, buf, bufsize);
396 while (s && buf[i] != '\n');
409 * The subscript operator is provided for access to individual characters
412 // TODO: Assignment to an individual character does not decouple references (BUG)
414 char& String::operator[](size_t i)
416 if (i >= strlen(p->s))
418 throw StringException("Out of bounds: " + String((int)i));
424 String String::upper()
429 up.p->s = new char[strlen(p->s)+1];
431 for(i=0; p->s[i]; i++)
433 up.p->s[i] = toupper(p->s[i]);
440 String String::lower()
445 low.p->s = new char[strlen(p->s)+1];
447 for(i=0; p->s[i]; i++)
449 low.p->s[i] = tolower(p->s[i]);
456 String String::escape()
458 const int BUFSIZE = 500;
460 char buffer[BUFSIZE];
462 int i; // Index in buffer[]
463 int j; // Index in *this
466 for (j = 0; p->s[j] != '\0'; j++)
527 if (p->s[j] > '\x20' && p->s[j] < '\x7F')
529 buffer[i++] = p->s[j];
535 // Turn into hexadecimal representation
539 nibble = (p->s[j] >> 4) & 0x0f;
540 buffer[i++] = nibble < 10 ? nibble + '0' : nibble - 10 + 'A';
541 nibble = p->s[j] & 0x0f;
542 buffer[i++] = nibble < 10 ? nibble + '0' : nibble - 10 + 'A';
554 String String::unescape()
559 unescaped.p->s = new char[strlen(p->s)+1];
620 while (*s >= '0' && *s <= '7')
631 s++; // Skip the initial 'x'
635 *d += *s > '9' ? toupper(*s) - 'A' + 10 : *s - '0';
658 // Find the first occurance of 'c'
660 int String::index(char c)
664 found = strchr(p->s, c);
671 // Find the last occurance of 'c'
673 int String::rindex(char c)
677 found = strrchr(p->s, c);
684 /* In: see if I am part of x, return -1 if not found */
686 int String::in(String & x)
690 match = strstr(x.p->s, p->s);
692 return match - x.p->s;
697 SuperString String::split(const String &separator)
699 SuperString splitted;
703 sep = strstr(p->s, separator.p->s);
707 // Create a new string from the part until the separator
709 int len = sep - part;
710 char *str = new char[len + 1];
712 strncpy(str, part, len);
714 splitted += String(str);
716 // Look for the next separator
720 sep = strstr(sep, separator.p->s);
723 // Add the leftover after the last separator.
725 splitted += String(part);
730 SuperString String::tokenize(const String &delim)
733 char *next_token, *save;
735 // The string to tokenize is modified, so we need to make a copy
737 char *str = new char[strlen(p->s) + 1];
740 next_token = strtok_r(str, delim.p->s, &save);
741 while (next_token != 0)
743 char *tok = new char[strlen(next_token) + 1];
744 strcpy(tok, next_token);
746 tokens += String(tok);
747 next_token = strtok_r(NULL, delim.p->s, &save);