A few small bug fixes.
[AXE.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.2 $
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     : Aug 26, 1999
21 **      MODIFICATIONS   : 
22 **************************************************************************/
23
24 /*****************************
25    $Log: string.cpp,v $
26    Revision 1.2  2002-09-28 06:42:11  arjen
27    A few small bug fixes.
28
29    Revision 1.1  2002/07/25 08:01:27  arjen
30    First checkin, AXE release 0.2
31
32 *****************************/
33
34 static const char RCSID[] = "$Id: string.cpp,v 1.2 2002-09-28 06:42:11 arjen Exp $";
35
36 #include <stdio.h>
37 #include <ctype.h>
38 #include "String.h"
39
40  //  Constructors and destructors for the String class
41
42 String::String()       // Create an empty String
43 {
44    p = new srep;
45    p->s = 0;
46    p->n = 1;
47 }
48
49 String::String(char c)    //  Create a String from a char
50 {
51    p = new srep;
52    p->s = new char[2];
53    p->s[0] = c;
54    p->s[1] = '\0';
55    p->n = 1;
56 }
57
58 String::String(const char *s)    //  Create a String from a char *
59 {
60    p = new srep;
61    p->s = new char[strlen(s)+1];
62    strcpy(p->s, s);
63    p->n = 1;
64 }
65
66 String::String(const String& x)   // Create a String from another String
67 {
68    x.p->n++;
69    p = x.p;
70 }
71
72 String::String(const substring &x)
73 {
74    p = new srep;
75
76    p->s = new char[x.len+1];
77    strncpy(p->s, x.str->p->s+x.start, x.len);
78    p->s[x.len] = '\0';     // strncpy does not add the \0
79    p->n = 1;
80 }
81
82 String::~String()
83 {
84    if (--p->n == 0)
85    {
86       delete p->s;
87       delete p;
88    }
89 }
90
91 /*
92  *  Assignment operators must handle cleanup of their left-hand operand.
93  */
94
95 String& String::operator=(const char c)
96 {
97    if (p->n > 1)
98    {                //    Dsiconnect self
99       p->n--;
100       p = new srep;
101    }
102    else if (p->n == 1)
103       delete p->s;
104
105    p->s = new char[2];
106    p->s[0] = c;
107    p->s[1] = '\0';
108    p->n = 1;
109    return *this;
110 }
111
112 String& String::operator=(const char *s)
113 {
114    if (p->n > 1)
115    {                //    Disconnect self
116       p->n--;
117       p = new srep;
118    }
119    else if (p->n == 1)
120       delete p->s;
121
122    p->s = new char[strlen(s)+1];
123    strcpy(p->s, s);
124    p->n = 1;
125    return *this;
126 }
127
128 /*  Make sure that assignment of an object to itself works correctly:  */
129
130 String& String::operator=(const String& x)
131 {
132    x.p->n++;
133    if (--p->n == 0)
134    {
135       delete p->s;
136       delete p;
137    }
138
139    p = x.p;
140    return *this;
141 }
142
143 /*  Numerical conversion */
144
145 String::String(int i)
146 {
147    p = new srep;
148    p->s = new char[15];  //  A little longer than needed...
149    sprintf(p->s, "%d", i);
150    p->n = 1;
151 }
152
153 String::String(long i)
154 {
155    p = new srep;
156    p->s = new char[15];  //  A little longer than needed...
157    sprintf(p->s, "%ld", i);
158    p->n = 1;
159 }
160
161 String::String(unsigned long i)
162 {
163    p = new srep;
164    p->s = new char[15];  //  A little longer than needed...
165    sprintf(p->s, "%lu", i);
166    p->n = 1;
167 }
168
169 String::String(double d)
170 {
171    p = new srep;
172    p->s = new char[25];  //  A little longer than needed...
173    sprintf(p->s, "%.3f", d);
174    p->n = 1;
175 }
176
177 /*   String concatenation */
178
179 String& String::operator+=(const String& x)
180 {
181    char *s = new char[strlen(p->s) + strlen(x.p->s) + 1];
182
183    strcpy(s, p->s);
184    strcat(s, x.p->s);
185
186    if (p->n > 1)
187    {                //    Disconnect self
188       p->n--;
189       p = new srep;
190    }
191    else if (p->n == 1)
192       delete p->s;
193
194    p->s = s;
195    p->n = 1;
196    return *this;
197 }
198
199 String& String::operator+=(const char * str)
200 {
201    char *s = new char[strlen(p->s) + strlen(str) + 1];
202
203    strcpy(s, p->s);
204    strcat(s, str);
205
206    if (p->n > 1)
207    {                //    Disconnect self
208       p->n--;
209       p = new srep;
210    }
211    else if (p->n == 1)
212       delete p->s;
213
214    p->s = s;
215    p->n = 1;
216    return *this;
217 }
218
219 String operator+(const String& x, const String& y)
220 {
221    String  cat = x;
222
223    cat  += y;
224    return cat;
225 }
226
227 String operator+(const String& x, const char * y)
228 {
229    String  cat = x;
230
231    cat  += y;
232    return cat;
233 }
234
235 String operator+(const char * x, const String& y)
236 {
237    String  cat = x;
238
239    cat  += y;
240    return cat;
241 }
242
243 /*  Shift operators  */
244
245
246 String operator<<(const String &x, int n)
247 {
248    String s(x);
249
250    s <<= n;
251    return s;
252 }
253
254 String & String::operator<<=(int n)
255 {
256    //  Make sure we are the only one being shifted.
257
258    if (p->n > 1)
259    {                //    Disconnect self
260       char *s = new char[strlen(p->s) + 1];
261
262       strcpy(s, p->s);
263       p->n--;
264       p = new srep;
265       p->s = s;
266       p->n = 1;
267    }
268
269    //  Shift left means we really have to copy all characters.
270    
271    int len = strlen(p->s);
272    int i;
273
274    if (n >= len)
275    {
276       //  Shift more than we have: the String becomes empty.
277       p->s[0] = '\0';
278    }
279    else
280    {
281       for (i = 0; i <= len - n; i++)
282       {
283          p->s[i] = p->s[i+n];
284       }
285    }
286    
287    return *this;
288 }
289
290 String operator>>(const String &x, int n)
291 {
292    String s(x);
293
294    s >>= n;
295    return s;
296 }
297
298 String & String::operator>>=(int n)
299 {
300    //  Make sure we are the only one being shifted.
301
302    if (p->n > 1)
303    {                //    Disconnect self
304       char *s = new char[strlen(p->s) + 1];
305
306       strcpy(s, p->s);
307       p->n--;
308       p = new srep;
309       p->s = s;
310       p->n = 1;
311    }
312
313    // Shift right is simple: just put the '\0' n places back.
314
315    
316    int len = strlen(p->s);
317
318    if (n >= len)
319    {
320       //  Shift more than we have: the String becomes empty.
321       p->s[0] = '\0';
322    }
323    else
324    {
325       p->s[len - n] = '\0';
326    }
327
328    return *this;
329 }
330
331 /*  Substring selection and assignment */
332
333 substring String::operator()(int start, int len)
334 {
335    substring sub;
336
337    sub.str = this;
338    sub.start = start;
339    sub.len   = len;
340    return sub;
341 }
342
343 String& substring::operator=(const String &x)
344 {
345    char *s = new char[strlen(x.p->s) + ~*str - len + 1];
346
347    strncpy(s, str->p->s, start);
348    s[start] = '\0';
349    strcat(s, x.p->s);
350    strcat(s, str->p->s+start+len);
351
352    return *str = s;
353 }
354
355 /*   Input and output   */
356
357 std::ostream& operator<<(std::ostream& s, const String& x)
358 {
359    if (x.p->s)
360       s << x.p->s;
361    return s;
362 }
363
364 std::istream& operator>>(std::istream& s, String& x)
365 {
366    char  buf[1024];
367    int   i;
368
369    i = -1;
370    do
371    {
372       i++;
373       s.get(buf[i]);
374    }
375    while (s && buf[i] != '\n');
376    if (buf[i] == '\n')
377    {
378       buf[i] = '\0';
379    }
380    x = buf;
381    return s;
382 }
383
384 /*
385  *   The subscript operator is provided for access to individual characters
386  */
387
388 char& String::operator[](int i)
389 {
390    return p->s[i];
391 }
392
393 String String::upper(void)
394 {
395    String  up;
396    int     i;
397
398    up.p->s = new char[strlen(p->s)+1];
399
400    for(i=0; p->s[i]; i++)
401    {
402       up.p->s[i] = toupper(p->s[i]);
403    }
404    up.p->s[i] = '\0';
405
406    return up;
407 }
408
409 String String::lower(void)
410 {
411    String  low;
412    int     i;
413
414    low.p->s = new char[strlen(p->s)+1];
415
416    for(i=0; p->s[i]; i++)
417    {
418       low.p->s[i] = tolower(p->s[i]);
419    }
420    low.p->s[i] = '\0';
421
422    return low;
423 }
424
425 // Find the first occurance of 'c'
426
427 int String::index(char c)
428 {
429    char *found;
430
431    found = strchr(p->s, c);
432    if (found)
433       return found - p->s;
434    else
435       return -1;
436 }
437
438 // Find the last occurance of 'c'
439
440 int String::rindex(char c)
441 {
442    char *found;
443
444    found = strrchr(p->s, c);
445    if (found)
446       return found - p->s;
447    else
448       return -1;
449 }
450
451 /* In: see if I am part of x, return -1 if not found */
452
453 int String::in(String & x)
454 {
455    char *match;
456
457    match = strstr(x.p->s, p->s);
458    if (match)
459       return match - x.p->s;
460    else
461       return -1;
462 }