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