]> cygwin.com Git - cygwin-apps/setup.git/blob - String++.cc
2006-03-30 Max Bowsher <maxb1@ukf.net>
[cygwin-apps/setup.git] / String++.cc
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 "io_stream.h"
22 #include <iostream>
23 #include <sstream>
24 #include <string>
25 #include <algorithm>
26
27 using namespace std;
28
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
58 String::String (string const &aString) : theData (new _data (aString.c_str() ? strlen (aString.c_str()) : 0))
59 {
60 memcpy (theData->theString, aString.c_str(), theData->length);
61 }
62
63 // able to cache the result if needed.
64 char const *
65 String::c_str () const
66 {
67 if (theData->length == 0)
68 return NULL;
69 if (theData->cstr)
70 delete[] theData->cstr;
71 theData->cstr = new char[theData->length + 1];
72 theData->cstr[theData->length] = '\0';
73 memcpy (theData->cstr, theData->theString, theData->length);
74 return theData->cstr;
75 }
76
77 // does this character exist in the string?
78 // 0 is false, 1 is the first position...
79 // XXX FIXME: Introduce npos, and change all
80 // if (size) calls to be if (size()==npos)
81 size_t
82 String::find(char aChar) const
83 {
84 for (size_t i=0; i < theData->length; ++i)
85 if (theData->theString[i] == aChar)
86 return i+1;
87 return 0;
88 }
89
90 String
91 String::substr(size_t start, int len) const
92 {
93 // Adapt the C++ string class
94 return string(c_str()).substr(start, len);
95 }
96
97 int
98 String::compare (String const &aString, size_t const count) const
99 {
100 // trivial cases:
101 if (theData == aString.theData)
102 return 0;
103 size_t length = count ? count : theData->length;
104 if (length > theData->length)
105 length = theData->length;
106 if (length > aString.theData->length)
107 length = aString.theData->length;
108 size_t i;
109 for (i=0; i < length ; ++i)
110 if (theData->theString[i] < aString.theData->theString[i])
111 return -1;
112 else if (theData->theString[i] > aString.theData->theString[i])
113 return 1;
114 // equal for length
115 if (i == count && count != 0)
116 return 0;
117 if (theData->length < aString.theData->length)
118 return -1;
119 else if (theData->length > aString.theData->length)
120 return 1;
121 return 0;
122 }
123
124 int
125 String::casecompare (String const &aString, size_t const count) const
126 {
127 // trivial cases:
128 if (theData == aString.theData)
129 return 0;
130 size_t length = count ? count : theData->length;
131 if (length > theData->length)
132 length = theData->length;
133 if (length > aString.theData->length)
134 length = aString.theData->length;
135 size_t i;
136 for (i=0; i < length; ++i)
137 if (toupper(theData->theString[i]) < toupper(aString.theData->theString[i]))
138 return -1;
139 else if (toupper(theData->theString[i]) > toupper(aString.theData->theString[i]))
140 return 1;
141 // equal for length
142 if (i == count && count != 0)
143 return 0;
144 if (theData->length < aString.theData->length)
145 return -1;
146 else if (theData->length > aString.theData->length)
147 return 1;
148 return 0;
149 }
150
151 String &
152 String::operator+= (String const &aString)
153 {
154 if (theData->count > 1)
155 {
156 _data * someData = new _data(*theData);
157 --theData->count;
158 theData = someData;
159 }
160
161 unsigned char *tempString = theData->theString;
162 theData->theString = new unsigned char [theData->length + aString.theData->length];
163 // remove when exceptions are done
164 if (!theData->theString)
165 exit (100);
166 memcpy (theData->theString, tempString, theData->length);
167 delete[] tempString;
168 memcpy (&theData->theString[theData->length], aString.theData->theString, aString.theData->length);
169 theData->length += aString.theData->length;
170 return *this;
171 }
172
173 String
174 String::operator + (String const &aString) const
175 {
176 unsigned char *tempcString = new unsigned char [theData->length + aString.theData->length];
177 // remove when exceptions are done
178 if (!tempcString)
179 exit (100);
180 memcpy (tempcString, theData->theString, theData->length);
181 memcpy (&tempcString[theData->length], aString.theData->theString, aString.theData->length);
182 return absorb (tempcString, theData->length + aString.theData->length);
183 }
184
185 String
186 String::operator + (char const *aString) const
187 {
188 // expensive, but quick to code.
189 return *this + String (aString);
190 }
191
192 bool
193 String::operator == (String const &rhs) const
194 {
195 return compare (rhs) ? false : true;
196 }
197
198 bool
199 String::operator == (char const *rhs) const
200 {
201 return compare (rhs) ? false : true;
202 }
203
204 bool
205 String::operator != (String const &rhs) const
206 {
207 return !(*this == rhs);
208 }
209
210 bool
211 String::operator != (char const *rhs) const
212 {
213 return !(*this == rhs);
214 }
215
216 String
217 String::absorb (unsigned char *aString, size_t aLength)
218 {
219 String theString;
220 theString.theData->theString = aString;
221 theString.theData->length = aLength;
222 return theString;
223 }
224
225 String
226 String::replace (char pattern, char replacement) const
227 {
228 unsigned char *tempcString = new unsigned char [theData->length];
229 // remove when exceptions are done
230 if (!tempcString)
231 exit (100);
232 unsigned char *s = theData->theString;
233 unsigned char *d = tempcString;
234 unsigned char *end = theData->theString + theData->length;
235 for (s = theData->theString; s < end; ++s)
236 {
237 if (*s == pattern)
238 *d++ = replacement;
239 else
240 *d++ = *s;
241 }
242 return absorb (tempcString, theData->length);
243 }
244
245 String
246 String::replace (String const &pattern, String const &replacement) const
247 {
248 int growth = replacement.theData->length - pattern.theData->length + 1;
249 if (growth < 1) growth = 1;
250 unsigned char *tempcString = new unsigned char [theData->length * growth];
251 // remove when exceptions are done
252 if (!tempcString)
253 exit (100);
254 unsigned char *s = theData->theString;
255 unsigned char *d = tempcString;
256 unsigned char *end = theData->theString + theData->length;
257 for (s = theData->theString; s < end - pattern.theData->length; )
258 {
259 if (memcmp(s, pattern.theData->theString, pattern.theData->length) == 0)
260 {
261 s += pattern.theData->length;
262 memcpy(d, replacement.theData->theString, replacement.theData->length);
263 d += replacement.theData->length;
264 }
265 else
266 *d++ = *s++;
267 }
268 for (; s < end; )
269 *d++ = *s++;
270 size_t length = d - tempcString;
271 // Avoid wasting space
272 unsigned char *newCopy = new unsigned char[length];
273 // remove when exceptions are done
274 if (!newCopy)
275 exit (100);
276 memcpy (newCopy, tempcString, length);
277 delete[] tempcString;
278
279 return absorb (newCopy, length);
280 }
281
282 char *
283 new_cstr_char_array (const String &s)
284 {
285 size_t len = s.size();
286 char *buf = new char[len + 1];
287 if (len)
288 memcpy (buf, s.c_str (), len);
289 buf[len] = 0;
290 return buf;
291 }
292
293 /* TODO: research how wide char and unicode interoperate with
294 * C++ streams
295 */
296 ostream &
297 operator << (ostream &os, String const &theString)
298 {
299 os << theString.c_str();
300 return os;
301 }
302
303 String
304 format_1000s(const int num, char sep)
305 {
306 int mult = 1;
307 while (mult * 1000 < num)
308 mult *= 1000;
309 ostringstream os;
310 os << ((num / mult) % 1000);
311 for (mult /= 1000; mult > 0; mult /= 1000)
312 {
313 int triplet = (num / mult) % 1000;
314 os << sep;
315 if (triplet < 100) os << '0';
316 if (triplet < 10) os << '0';
317 os << triplet;
318 }
319 return String(os.str());
320 }
321
322 std::string
323 stringify(int num)
324 {
325 std::ostringstream os;
326 os << num;
327 return os.str();
328 }
329
330 int
331 casecompare (const std::string& a, const std::string& b, size_t limit)
332 {
333 size_t length_to_check = std::min(a.length(), b.length());
334 if (limit && length_to_check > limit)
335 length_to_check = limit;
336
337 size_t i;
338 for (i = 0; i < length_to_check; ++i)
339 if (toupper(a[i]) < toupper(b[i]))
340 return -1;
341 else if (toupper(a[i]) > toupper(b[i]))
342 return 1;
343
344 // Hit the comparison limit without finding a difference
345 if (limit && i == limit)
346 return 0;
347
348 if (a.length() < b.length())
349 return -1;
350 else if (a.length() > b.length())
351 return 1;
352
353 return 0;
354 }
355
356 std::string
357 replace(const std::string& haystack, const std::string& needle,
358 const std::string& replacement)
359 {
360 std::string rv(haystack);
361 size_t n_len = needle.length(), r_len = replacement.length(),
362 search_start = 0;
363
364 while (true)
365 {
366 size_t pos = rv.find(needle, search_start);
367 if (pos == std::string::npos)
368 return rv;
369 rv.replace(pos, n_len, replacement);
370 search_start = pos + r_len;
371 }
372 }
This page took 0.052764 seconds and 6 git commands to generate.