]>
Commit | Line | Data |
---|---|---|
3c054baf RC |
1 | /* |
2 | * Copyright (c) 2002, Robert Collins. | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or modify | |
5 | * it under the terms of the GNU General Public License as published by | |
6 | * the Free Software Foundation; either version 2 of the License, or | |
7 | * (at your option) any later version. | |
8 | * | |
9 | * A copy of the GNU General Public License can be found at | |
10 | * http://www.gnu.org/ | |
11 | * | |
12 | * Written by Robert Collins. | |
13 | * | |
14 | */ | |
15 | ||
16 | // A String class to replace all the char * manipulation. | |
17 | ||
18 | #include "String++.h" | |
19 | #include <string.h> | |
20 | #include <ctype.h> | |
21 | #include "concat.h" | |
22 | #include "io_stream.h" | |
6391823e | 23 | #include <iostream> |
076654e7 | 24 | #include <strstream> |
b401ef47 | 25 | #include <string> |
3c054baf RC |
26 | |
27 | // _data | |
28 | ||
29 | String::_data::_data(_data const &aData) : count (1), theString (new unsigned char[aData.length]), cstr(0), length (aData.length) { | |
30 | memcpy (theString, aData.theString, aData.length); | |
31 | } | |
32 | ||
33 | String::_data::_data(): count (1), theString(new unsigned char[0]), cstr (0), length (0) {} | |
34 | String::_data::_data(size_t aLength): count (1), theString(new unsigned char[aLength]), cstr(0), length (aLength) {} | |
35 | String::_data::~_data () | |
36 | { | |
37 | if (theString) | |
38 | delete[] theString; | |
39 | if (cstr) | |
40 | delete[] cstr; | |
41 | } | |
42 | ||
43 | //String | |
44 | ||
45 | String::String (const char *acString) : theData (new _data(acString ? strlen(acString) : 0)) | |
46 | { | |
47 | memcpy (theData->theString, acString, theData->length); | |
48 | } | |
49 | ||
50 | String::~String () | |
51 | { | |
52 | if (--theData->count == 0) | |
53 | delete theData; | |
54 | } | |
55 | ||
076654e7 RC |
56 | String::String (int const anInt) |
57 | { | |
58 | ostrstream os; | |
59 | os << anInt; | |
60 | theData = new _data(os.pcount()); | |
61 | memcpy (theData->theString, os.str(), os.pcount()); | |
62 | } | |
63 | ||
b401ef47 RC |
64 | String::String (string const &aString) : theData (new _data (aString.c_str() ? strlen (aString.c_str()) : 0)) |
65 | { | |
66 | memcpy (theData->theString, aString.c_str(), theData->length); | |
67 | } | |
68 | ||
3c054baf RC |
69 | // able to cache the result if needed. |
70 | char * | |
71 | String::cstr () | |
72 | { | |
73 | if (theData->length == 0) | |
74 | return NULL; | |
75 | char * tempcStr =new char[theData->length + 1]; | |
76 | // remove when exceptions are done | |
77 | if (!tempcStr) | |
78 | exit (100); | |
79 | tempcStr[theData->length] = '\0'; | |
80 | memcpy (tempcStr, theData->theString, theData->length); | |
81 | return tempcStr; | |
82 | } | |
83 | ||
84 | char * | |
85 | String::cstr () const | |
86 | { | |
87 | if (theData->length == 0) | |
88 | return NULL; | |
89 | char * tempcStr =new char[theData->length + 1]; | |
90 | // remove when exceptions are done | |
91 | if (!tempcStr) | |
92 | exit (100); | |
93 | tempcStr[theData->length] = '\0'; | |
94 | memcpy (tempcStr, theData->theString, theData->length); | |
95 | return tempcStr; | |
96 | } | |
97 | ||
98 | // able to cache the result if needed. | |
99 | char const * | |
100 | String::cstr_oneuse () const | |
101 | { | |
102 | if (theData->length == 0) | |
103 | return NULL; | |
104 | if (theData->cstr) | |
105 | delete[] theData->cstr; | |
106 | theData->cstr = new char[theData->length + 1]; | |
107 | theData->cstr[theData->length] = '\0'; | |
108 | memcpy (theData->cstr, theData->theString, theData->length); | |
109 | return theData->cstr; | |
110 | } | |
111 | ||
112 | // does this character exist in the string? | |
113 | // 0 is false, 1 is the first position... | |
114 | // XXX FIXME: Introduce npos, and change all | |
115 | // if (size) calls to be if (size()==npos) | |
116 | size_t | |
117 | String::find(char aChar) const | |
118 | { | |
119 | for (size_t i=0; i < theData->length; ++i) | |
120 | if (theData->theString[i] == aChar) | |
121 | return i+1; | |
122 | return 0; | |
123 | } | |
124 | ||
b401ef47 RC |
125 | String |
126 | String::substr(size_t start, size_t len) const | |
127 | { | |
128 | // Adapt the C++ string class | |
129 | return string(cstr_oneuse()).substr(start, len); | |
130 | } | |
131 | ||
3c054baf RC |
132 | int |
133 | String::compare (String const &aString, size_t const count) const | |
134 | { | |
135 | // trivial cases: | |
136 | if (theData == aString.theData) | |
137 | return 0; | |
138 | size_t length = count ? count : theData->length; | |
139 | if (length > theData->length) | |
140 | length = theData->length; | |
141 | if (length > aString.theData->length) | |
142 | length = aString.theData->length; | |
143 | size_t i; | |
144 | for (i=0; i < length ; ++i) | |
145 | if (theData->theString[i] < aString.theData->theString[i]) | |
146 | return -1; | |
147 | else if (theData->theString[i] > aString.theData->theString[i]) | |
148 | return 1; | |
149 | // equal for length | |
150 | if (i == count && count != 0) | |
151 | return 0; | |
152 | if (theData->length < aString.theData->length) | |
153 | return -1; | |
154 | else if (theData->length > aString.theData->length) | |
155 | return 1; | |
156 | return 0; | |
157 | } | |
158 | ||
159 | int | |
160 | String::casecompare (String const &aString, size_t const count) const | |
161 | { | |
162 | // trivial cases: | |
163 | if (theData == aString.theData) | |
164 | return 0; | |
165 | size_t length = count ? count : theData->length; | |
166 | if (length > theData->length) | |
167 | length = theData->length; | |
168 | if (length > aString.theData->length) | |
169 | length = aString.theData->length; | |
170 | size_t i; | |
171 | for (i=0; i < length; ++i) | |
172 | if (toupper(theData->theString[i]) < toupper(aString.theData->theString[i])) | |
173 | return -1; | |
174 | else if (toupper(theData->theString[i]) > toupper(aString.theData->theString[i])) | |
175 | return 1; | |
176 | // equal for length | |
177 | if (i == count && count != 0) | |
178 | return 0; | |
179 | if (theData->length < aString.theData->length) | |
180 | return -1; | |
181 | else if (theData->length > aString.theData->length) | |
182 | return 1; | |
183 | return 0; | |
184 | } | |
185 | ||
3c054baf RC |
186 | String & |
187 | String::operator+= (String const &aString) | |
188 | { | |
189 | if (theData->count > 1) | |
190 | { | |
191 | _data * someData = new _data(*theData); | |
192 | --theData->count; | |
193 | theData = someData; | |
194 | } | |
195 | ||
196 | unsigned char *tempString = theData->theString; | |
197 | theData->theString = new unsigned char [theData->length + aString.theData->length]; | |
198 | // remove when exceptions are done | |
199 | if (!theData->theString) | |
200 | exit (100); | |
201 | memcpy (theData->theString, tempString, theData->length); | |
202 | delete[] tempString; | |
203 | memcpy (&theData->theString[theData->length], aString.theData->theString, aString.theData->length); | |
204 | theData->length += aString.theData->length; | |
205 | return *this; | |
206 | } | |
207 | ||
208 | String | |
209 | String::operator + (String const &aString) const | |
210 | { | |
211 | unsigned char *tempcString = new unsigned char [theData->length + aString.theData->length]; | |
212 | // remove when exceptions are done | |
213 | if (!tempcString) | |
214 | exit (100); | |
215 | memcpy (tempcString, theData->theString, theData->length); | |
216 | memcpy (&tempcString[theData->length], aString.theData->theString, aString.theData->length); | |
217 | return absorb (tempcString, theData->length + aString.theData->length); | |
218 | } | |
219 | ||
220 | String | |
221 | String::operator + (char const *aString) const | |
222 | { | |
223 | // expensive, but quick to code. | |
224 | return *this + String (aString); | |
225 | } | |
226 | ||
227 | bool | |
228 | String::operator == (String const &rhs) const | |
229 | { | |
230 | return compare (rhs) ? false : true; | |
231 | } | |
232 | ||
233 | bool | |
234 | String::operator == (char const *rhs) const | |
235 | { | |
236 | return compare (rhs) ? false : true; | |
237 | } | |
238 | ||
239 | String | |
240 | String::absorb (unsigned char *aString, size_t aLength) | |
241 | { | |
242 | String theString; | |
243 | theString.theData->theString = aString; | |
244 | theString.theData->length = aLength; | |
245 | return theString; | |
246 | } | |
247 | ||
248 | int | |
249 | String::casecompare (String const lhs, String const rhs) | |
250 | { | |
251 | return lhs.casecompare (rhs); | |
252 | } | |
6391823e RC |
253 | |
254 | /* TODO: research how wide char and unicode interoperate with | |
255 | * C++ streams | |
256 | */ | |
257 | ostream & | |
258 | operator << (ostream &os, String const &theString) | |
259 | { | |
260 | os << theString.cstr_oneuse(); | |
261 | return os; | |
262 | } |