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