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