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