Convert String to and from std::string
[libacl.git] / src / string.cpp
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 $
9 **
10 **  DESCRIPTION      :  String class implementation.
11 **
12 **  EXPORTED OBJECTS : 
13 **  LOCAL    OBJECTS : 
14 **  MODULES  USED    :
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 **************************************************************************/
22
23 #include <stdio.h>
24 #include <ctype.h>
25 #include "String.h"
26
27  //  Constructors and destructors for the String class
28
29 String::String()       // Create an empty String
30 {
31    p = new srep;
32    p->s = new char[1];
33    p->s[0] = '\0';
34    p->n = 1;
35 }
36
37 String::String(char c)    //  Create a String from a char
38 {
39    p = new srep;
40    p->s = new char[2];
41    p->s[0] = c;
42    p->s[1] = '\0';
43    p->n = 1;
44 }
45
46 String::String(const char *s)    //  Create a String from a char *
47 {
48    p = new srep;
49
50    p->s = 0;
51    p->n = 1;
52
53    if (s != 0)
54    {
55       p->s = new char[strlen(s)+1];
56       strcpy(p->s, s);
57       p->n = 1;
58    }
59 }
60
61 String::String(const String& x)   // Create a String from another String
62 {
63    x.p->n++;
64    p = x.p;
65 }
66
67 String::String(const substring &x)
68 {
69    p = new srep;
70
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
74    p->n = 1;
75 }
76
77 String::String(const std::string &x)
78 {
79    p = new srep;
80
81    p->n = 1;
82    p->s = new char[x.size()+1];
83    x.copy(p->s, x.size());
84
85 }
86
87 String::~String()
88 {
89    if (--p->n == 0)
90    {
91       delete p->s;
92       delete p;
93    }
94 }
95
96 /*
97  *  Assignment operators must handle cleanup of their left-hand operand.
98  */
99
100 String& String::operator=(const char c)
101 {
102    if (p->n > 1)
103    {                //    Dsiconnect self
104       p->n--;
105       p = new srep;
106    }
107    else if (p->n == 1)
108       delete p->s;
109
110    p->s = new char[2];
111    p->s[0] = c;
112    p->s[1] = '\0';
113    p->n = 1;
114    return *this;
115 }
116
117 String& String::operator=(const char *s)
118 {
119    if (p->n > 1)
120    {                //    Disconnect self
121       p->n--;
122       p = new srep;
123    }
124    else if (p->n == 1)
125       delete p->s;
126
127    if (s != 0)
128    {
129       p->s = new char[strlen(s)+1];
130       strcpy(p->s, s);
131       p->n = 1;
132    }
133    return *this;
134 }
135
136 /*  Make sure that assignment of an object to itself works correctly:  */
137
138 String& String::operator=(const String& x)
139 {
140    x.p->n++;
141    if (--p->n == 0)
142    {
143       delete p->s;
144       delete p;
145    }
146
147    p = x.p;
148    return *this;
149 }
150
151 String& String::operator=(const std::string &x)
152 {
153    if (p->n > 1)
154    {                //    Disconnect self
155       p->n--;
156       p = new srep;
157    }
158    else if (p->n == 1)
159       delete p->s;
160
161    p->n = 1;
162    p->s = new char[x.size()+1];
163    x.copy(p->s, x.size());
164
165    return *this;
166 }
167
168 /*  Numerical conversion */
169
170 String::String(int i)
171 {
172    p = new srep;
173    p->s = new char[15];  //  A little longer than needed...
174    sprintf(p->s, "%d", i);
175    p->n = 1;
176 }
177
178 String::String(long i)
179 {
180    p = new srep;
181    p->s = new char[15];  //  A little longer than needed...
182    sprintf(p->s, "%ld", i);
183    p->n = 1;
184 }
185
186 String::String(unsigned long i)
187 {
188    p = new srep;
189    p->s = new char[15];  //  A little longer than needed...
190    sprintf(p->s, "%lu", i);
191    p->n = 1;
192 }
193
194 String::String(double d)
195 {
196    p = new srep;
197    p->s = new char[25];  //  A little longer than needed...
198    sprintf(p->s, "%.3f", d);
199    p->n = 1;
200 }
201
202 /*   String concatenation */
203
204 String& String::operator+=(const String& x)
205 {
206    char *s = new char[strlen(p->s) + strlen(x.p->s) + 1];
207
208    strcpy(s, p->s);
209    strcat(s, x.p->s);
210
211    if (p->n > 1)
212    {                //    Disconnect self
213       p->n--;
214       p = new srep;
215    }
216    else if (p->n == 1)
217       delete p->s;
218
219    p->s = s;
220    p->n = 1;
221    return *this;
222 }
223
224 String& String::operator+=(const char * str)
225 {
226    char *s = new char[strlen(p->s) + strlen(str) + 1];
227
228    strcpy(s, p->s);
229    strcat(s, str);
230
231    if (p->n > 1)
232    {                //    Disconnect self
233       p->n--;
234       p = new srep;
235    }
236    else if (p->n == 1)
237       delete p->s;
238
239    p->s = s;
240    p->n = 1;
241    return *this;
242 }
243
244 String operator+(const String& x, const String& y)
245 {
246    String  cat = x;
247
248    cat  += y;
249    return cat;
250 }
251
252 String operator+(const String& x, const char * y)
253 {
254    String  cat = x;
255
256    cat  += y;
257    return cat;
258 }
259
260 String operator+(const char * x, const String& y)
261 {
262    String  cat = x;
263
264    cat  += y;
265    return cat;
266 }
267
268 /*  Shift operators  */
269
270
271 String operator<<(const String &x, int n)
272 {
273    String s(x);
274
275    s <<= n;
276    return s;
277 }
278
279 String & String::operator<<=(int n)
280 {
281    //  Make sure we are the only one being shifted.
282
283    if (p->n > 1)
284    {                //    Disconnect self
285       char *s = new char[strlen(p->s) + 1];
286
287       strcpy(s, p->s);
288       p->n--;
289       p = new srep;
290       p->s = s;
291       p->n = 1;
292    }
293
294    //  Shift left means we really have to copy all characters.
295    
296    int len = strlen(p->s);
297    int i;
298
299    if (n >= len)
300    {
301       //  Shift more than we have: the String becomes empty.
302       p->s[0] = '\0';
303    }
304    else
305    {
306       for (i = 0; i <= len - n; i++)
307       {
308          p->s[i] = p->s[i+n];
309       }
310    }
311    
312    return *this;
313 }
314
315 String operator>>(const String &x, int n)
316 {
317    String s(x);
318
319    s >>= n;
320    return s;
321 }
322
323 String & String::operator>>=(int n)
324 {
325    //  Make sure we are the only one being shifted.
326
327    if (p->n > 1)
328    {                //    Disconnect self
329       char *s = new char[strlen(p->s) + 1];
330
331       strcpy(s, p->s);
332       p->n--;
333       p = new srep;
334       p->s = s;
335       p->n = 1;
336    }
337
338    // Shift right is simple: just put the '\0' n places back.
339
340    
341    int len = strlen(p->s);
342
343    if (n >= len)
344    {
345       //  Shift more than we have: the String becomes empty.
346       p->s[0] = '\0';
347    }
348    else
349    {
350       p->s[len - n] = '\0';
351    }
352
353    return *this;
354 }
355
356 /*  Substring selection and assignment */
357
358 substring String::operator()(int start, int len)
359 {
360    substring sub;
361    size_t    _start;
362
363    _start = start;   //  Proper type conversion
364
365    if (_start > strlen(p->s) || _start + len > strlen(p->s))
366    {
367       throw StringException("Substring Out of bounds: (" 
368                     + String(start) + ", " + String(len) + ")");
369    }
370    sub.str = this;
371    sub.start = start;
372    sub.len   = len;
373    return sub;
374 }
375
376 String& substring::operator=(const String &x)
377 {
378    char *s = new char[strlen(x.p->s) + ~*str - len + 1];
379
380    strncpy(s, str->p->s, start);
381    s[start] = '\0';
382    strcat(s, x.p->s);
383    strcat(s, str->p->s+start+len);
384
385    return *str = s;
386 }
387
388 /*   Input and output   */
389
390 std::ostream& operator<<(std::ostream& s, const String& x)
391 {
392    if (x.p->s)
393       s << x.p->s;
394    return s;
395 }
396
397 std::istream& operator>>(std::istream& s, String& x)
398 {
399    char  *buf;
400    int   i;
401
402    int   bufsize = 1024;
403
404    buf = new char[bufsize];
405
406    i = -1;
407    do
408    {
409       if (i >= bufsize)
410       {
411          //  Buffer is too small. Allocate some new space.
412
413          char *newbuf = new char[bufsize * 2];
414          memcpy(newbuf, buf, bufsize);
415          delete [] buf;
416          buf = newbuf;
417          bufsize *= 2;
418       }
419
420       i++;
421       s.get(buf[i]);
422    }
423    while (s && buf[i] != '\n');
424    if (buf[i] == '\n')
425    {
426       buf[i] = '\0';
427    }
428    x = buf;
429
430    delete [] buf;
431
432    return s;
433 }
434
435 /*
436  *   The subscript operator is provided for access to individual characters
437  */
438
439 // TODO: Assignment to an individual character does not decouple references (BUG)
440
441 char& String::operator[](size_t i)
442 {
443    if (i >= strlen(p->s))
444    {
445       throw StringException("Out of bounds: " + String((int)i));
446    }
447
448    return p->s[i];
449 }
450
451 String String::upper()
452 {
453    String  up;
454    int     i;
455
456    up.p->s = new char[strlen(p->s)+1];
457
458    for(i=0; p->s[i]; i++)
459    {
460       up.p->s[i] = toupper(p->s[i]);
461    }
462    up.p->s[i] = '\0';
463
464    return up;
465 }
466
467 String String::lower()
468 {
469    String  low;
470    int     i;
471
472    low.p->s = new char[strlen(p->s)+1];
473
474    for(i=0; p->s[i]; i++)
475    {
476       low.p->s[i] = tolower(p->s[i]);
477    }
478    low.p->s[i] = '\0';
479
480    return low;
481 }
482
483 String String::escape()
484 {
485    const int BUFSIZE = 500;
486
487    char   buffer[BUFSIZE];
488    String escaped = "";
489    int    i;              //  Index in buffer[]
490    int    j;              //  Index in *this
491
492    i = 0;
493    for (j = 0; p->s[j] != '\0'; j++)
494    {
495       if (i + 5 > BUFSIZE)
496       {
497          escaped += buffer;
498          i = 0;
499       }
500
501       switch (p->s[j])
502       {
503       case '\a':
504          buffer[i++] = '\\';
505          buffer[i++] = 'a';
506          break;
507
508       case '\b':
509          buffer[i++] = '\\';
510          buffer[i++] = 'b';
511          break;
512
513       case '\f':
514          buffer[i++] = '\\';
515          buffer[i++] = 'f';
516          break;
517
518       case '\n':
519          buffer[i++] = '\\';
520          buffer[i++] = 'n';
521          break;
522
523       case '\r':
524          buffer[i++] = '\\';
525          buffer[i++] = 'r';
526          break;
527
528       case '\t':
529          buffer[i++] = '\\';
530          buffer[i++] = 't';
531          break;
532
533       case '\v':
534          buffer[i++] = '\\';
535          buffer[i++] = 'v';
536          break;
537
538       case '\'':
539          buffer[i++] = '\\';
540          buffer[i++] = '\'';
541          break;
542
543       case '"':
544          buffer[i++] = '\\';
545          buffer[i++] = '"';
546          break;
547
548       case '\\':
549          buffer[i++] = '\\';
550          buffer[i++] = '\\';
551          break;
552
553       default:
554          if (p->s[j] > '\x20' && p->s[j] < '\x7F')
555          {
556             buffer[i++] = p->s[j];
557          }
558          else
559          {
560             short   nibble;
561
562             //  Turn into hexadecimal representation
563
564             buffer[i++] = '\\';
565             buffer[i++] = 'x';
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';
570          }
571          break;
572       }
573    }
574
575    buffer[i] = '\0';
576    escaped += buffer;
577
578    return escaped;
579 }
580
581 String String::unescape()
582 {
583    String unescaped;
584    char   *s, *d;
585
586    unescaped.p->s = new char[strlen(p->s)+1];
587    s = p->s;
588    d = unescaped.p->s;
589
590    while (*s != '\0')
591    {
592       if (*s == '\\')
593       {
594          s++;
595
596          switch (*s)
597          {
598          case 'a':
599             *d = '\a';
600             break;
601
602          case 'b':
603             *d = '\b';
604             break;
605
606          case 'f':
607             *d = '\f';
608             break;
609
610          case 'n':
611             *d = '\n';
612             break;
613
614          case 'r':
615             *d = '\r';
616             break;
617
618          case 't':
619             *d = '\t';
620             break;
621
622          case 'v':
623             *d = '\v';
624             break;
625
626          case '\'':
627             *d = '\'';
628             break;
629
630          case '"':
631             *d = '"';
632             break;
633
634          case '\\':
635             *d = '\\';
636             break;
637
638          case '0':
639          case '1':
640          case '2':
641          case '3':
642          case '4':
643          case '5':
644          case '6':
645          case '7':
646             *d = 0;
647             while (*s >= '0' && *s <= '7')
648             {
649                *d *= 8;
650                *d += *s - '0';
651                s++;
652             }
653             s--;
654             break;
655
656          case 'x':
657             *d = 0;
658             s++;           //  Skip the initial 'x'
659             while (isxdigit(*s))
660             {
661                *d *= 16;
662                *d += *s > '9' ? toupper(*s) - 'A' + 10 : *s - '0';
663                s++;
664             }
665             s--;
666             break;
667
668          default:
669             *d = *s;
670             break;
671          }
672       }
673       else
674       {
675          *d = *s;
676       }
677       s++;
678       d++;
679    }
680
681    return unescaped;
682 }
683
684
685 // Find the first occurance of 'c'
686
687 int String::index(char c)
688 {
689    char *found;
690
691    found = strchr(p->s, c);
692    if (found)
693       return found - p->s;
694    else
695       return -1;
696 }
697
698 // Find the last occurance of 'c'
699
700 int String::rindex(char c)
701 {
702    char *found;
703
704    found = strrchr(p->s, c);
705    if (found)
706       return found - p->s;
707    else
708       return -1;
709 }
710
711 /* Find the first occurance of x */
712
713 int String::index(const char * x)
714 {
715    char *match;
716
717    match = strstr(p->s, x);
718    if (match)
719       return match - p->s;
720    else
721       return -1;
722 }
723
724 /* Find the last occurance of x */
725
726 int String::rindex(const char * x)
727 {
728    char *match, *lastmatch;
729
730    match = strstr(p->s, x);
731    lastmatch = 0;
732
733    while (match)
734    {
735       lastmatch = match;
736       match = strstr(match + 1, x);
737    }
738
739    if (lastmatch)
740       return lastmatch - p->s;
741    else
742       return -1;
743 }
744
745
746 SuperString String::split(const String &separator)
747 {
748    SuperString splitted;
749    char *sep, *part;
750
751    part = p->s;
752    sep = strstr(p->s, separator.p->s);
753
754    while (sep != NULL)
755    {
756       //  Create a new string from the part until the separator
757
758       int  len  = sep - part;
759       char *str = new char[len + 1];
760
761       strncpy(str, part, len);
762       str[len] = '\0';
763       splitted += String(str);
764
765       // Look for the next separator
766
767       sep += ~separator;
768       part = sep;
769       sep = strstr(sep, separator.p->s);
770    }
771
772    // Add the leftover after the last separator.
773
774    splitted += String(part);
775
776    return splitted;
777 }
778
779 SuperString String::tokenize(const String &delim)
780 {
781    SuperString tokens;
782    char        *next_token, *save;
783
784    // The string to tokenize is modified, so we need to make a copy
785
786    char *str  = new char[strlen(p->s) + 1];
787    strcpy (str, p->s);
788
789    next_token = strtok_r(str, delim.p->s, &save);
790    while (next_token != 0)
791    {
792       char *tok = new char[strlen(next_token) + 1];
793       strcpy(tok, next_token);
794
795       tokens += String(tok);
796       next_token = strtok_r(NULL, delim.p->s, &save);
797    }
798
799    delete [] str;
800
801    return tokens;
802 }