src/string.cpp

changeset 286
7a562bf3d829
parent 273
0a9141118630
equal deleted inserted replaced
285:836e77323ab0 286:7a562bf3d829
1 /*
2 * LDForge: LDraw parts authoring CAD
3 * Copyright (C) 2013 Santeri Piippo
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include <stdexcept>
20 #include "common.h"
21 #include "string.h"
22
23 String::String () {}
24
25 String::String (const char* data) {
26 m_string = data;
27 }
28
29 String::String (const QString data) {
30 m_string = data.toStdString ();
31 }
32
33 String::String (std::string data) {
34 m_string = data;
35 }
36
37 str fmt (const char* fmtstr, ...) {
38 va_list va;
39
40 va_start (va, fmtstr);
41 char* buf = dynafmt (fmtstr, va, 256);
42 va_end (va);
43
44 str msg = buf;
45 delete[] buf;
46 return msg;
47 }
48
49 char* dynafmt (const char* fmtstr, va_list va, ulong size) {
50 char* buf = null;
51 ushort run = 0;
52
53 do {
54 try {
55 buf = new char[size];
56 } catch (std::bad_alloc&) {
57 // fmt uses dynafmt, so using fmt here is dangerous and could lead
58 // into infinite recursion. Thus, use a C string this one time.
59 char err[256];
60 sprintf (err, "caught std::bad_alloc on run #%u while trying to allocate %lu bytes", run + 1, size);
61 fatal (err);
62 }
63
64 if (!vsnprintf (buf, size - 1, fmtstr, va)) {
65 delete[] buf;
66 buf = null;
67 }
68
69 size *= 2;
70 ++run;
71 } while (buf == null);
72
73 return buf;
74 }
75
76 void String::append (const char* data) {
77 m_string.append (data);
78 }
79
80 void String::append (const char data) {
81 m_string.push_back (data);
82 }
83
84 void String::append (const String data) {
85 m_string.append (data.chars ());
86 }
87
88 String::it String::begin () {
89 return m_string.begin ();
90 }
91
92 String::c_it String::begin () const {
93 return m_string.cbegin ();
94 }
95
96 const char* String::c () const {
97 return chars ();
98 }
99
100 size_t String::capacity () const {
101 return m_string.capacity ();
102 }
103
104 const char* String::chars () const {
105 return m_string.c_str ();
106 }
107
108 int String::compare (const char* other) const {
109 return m_string.compare (other);
110 }
111
112 int String::compare (String other) const {
113 return m_string.compare (other);
114 }
115
116 String::it String::end () {
117 return m_string.end ();
118 }
119
120 String::c_it String::end () const {
121 return m_string.end ();
122 }
123
124 void String::clear () {
125 m_string.clear ();
126 }
127
128 bool String::empty() const {
129 return m_string.empty ();
130 }
131
132 void String::erase (size_t pos) {
133 m_string.erase (m_string.begin () + pos);
134 }
135
136 void String::insert (size_t pos, char c) {
137 m_string.insert (m_string.begin () + pos, c);
138 }
139
140 size_t String::len () const {
141 return m_string.length ();
142 }
143
144 size_t String::maxSize () const {
145 return m_string.max_size ();
146 }
147
148 void String::resize (size_t n) {
149 m_string.resize (n);
150 }
151
152 void String::shrinkToFit () {
153 m_string.shrink_to_fit ();
154 }
155
156
157
158 void String::trim (short n) {
159 if (n > 0)
160 for (short i = 0; i < n; ++i)
161 m_string.erase (m_string.end () - 1 - i);
162 else
163 for (short i = abs (n) - 1; i >= 0; ++i)
164 m_string.erase (m_string.begin () + i);
165 }
166
167 String String::strip (char unwanted) {
168 return strip ({unwanted});
169 }
170
171 String String::strip (std::initializer_list<char> unwanted) {
172 String copy (m_string);
173
174 for (char c : unwanted) {
175 for (long i = len (); i >= 0; --i)
176 if (copy[(size_t) i] == c)
177 copy.erase (i);
178 }
179
180 return copy;
181 }
182
183 String String::upper() const {
184 String newstr = m_string;
185
186 for (char& c : newstr)
187 if (c >= 'a' && c <= 'z')
188 c -= 'a' - 'A';
189
190 return newstr;
191 }
192
193 String String::lower () const {
194 String newstr = m_string;
195
196 for (char& c : newstr)
197 if (c >= 'A' && c <= 'Z')
198 c += 'a' - 'A';
199
200 return newstr;
201 }
202
203 vector<String> String::split (char del) const {
204 String delimstr;
205 delimstr += del;
206 return split (delimstr);
207 }
208
209 vector<String> String::split (String del) const {
210 vector<String> res;
211 size_t a = 0;
212
213 // Find all separators and store the text left to them.
214 while (1) {
215 long b = first (del, a);
216
217 if (b == -1)
218 break;
219
220 String sub = substr (a, b);
221 if (~sub > 0)
222 res.push_back (substr (a, b));
223
224 a = b + strlen (del);
225 }
226
227 // Add the string at the right of the last separator
228 if (a < len ())
229 res.push_back (substr (a, len()));
230
231 return res;
232 }
233
234 void String::replace (const char* a, const char* b) {
235 long pos;
236
237 while ((pos = first (a)) != -1)
238 m_string = m_string.replace (pos, strlen (a), b);
239 }
240
241 void String::format (const char* fmtstr, ...) {
242 va_list va;
243
244 va_start (va, fmtstr);
245 char* buf = dynafmt (fmtstr, va, 256);
246 va_end (va);
247
248 m_string = buf;
249 delete[] buf;
250 }
251
252 ushort String::count (const char needle) const {
253 ushort numNeedles = 0;
254
255 for (const char& c : m_string)
256 if (c == needle)
257 numNeedles++;
258
259 return numNeedles;
260 }
261
262 String String::substr (long a, long b) const {
263 if (b == -1)
264 b = len ();
265
266 str sub;
267
268 try {
269 sub = m_string.substr (a, b - a);
270 } catch (const std::out_of_range& e) {
271 fatal (fmt ("caught std::out_of_range, coords were: (%ld, %ld), string: `%s', length: %lu",
272 a, b, chars (), (ulong) len ()));
273 }
274
275 return sub;
276 }
277
278 // ============================================================================
279 int String::first (const char* c, int a) const {
280 unsigned int r = 0;
281 unsigned int index = 0;
282 for (; a < (int) len (); a++) {
283 if (m_string[a] == c[r]) {
284 if (r == 0)
285 index = a;
286
287 r++;
288 if (r == strlen (c))
289 return index;
290 } else {
291 if (r != 0) {
292 // If the string sequence broke at this point, we need to
293 // check this character again, for a new sequence just
294 // might start right here.
295 a--;
296 }
297
298 r = 0;
299 }
300 }
301
302 return -1;
303 }
304
305 // ============================================================================
306 int String::last (const char* c, int a) const {
307 if (a == -1)
308 a = len();
309
310 int max = strlen (c) - 1;
311
312 int r = max;
313 for (; a >= 0; a--) {
314 if (m_string[a] == c[r]) {
315 r--;
316 if (r == -1)
317 return a;
318 } else {
319 if (r != max)
320 a++;
321
322 r = max;
323 }
324 }
325
326 return -1;
327 }
328
329 String String::operator+ (const String data) const {
330 String newstr = *this;
331 newstr += data;
332 return newstr;
333 }
334
335 String String::operator+ (const char* data) const {
336 String newstr = *this;
337 newstr += data;
338 return newstr;
339 }
340
341 String& String::operator+= (const String data) {
342 append (data);
343 return *this;
344 }
345
346 String& String::operator+= (const char* data) {
347 append (data);
348 return *this;
349 }
350
351 String& String::operator+= (const char data) {
352 append (data);
353 return *this;
354 }
355
356 String String::operator+ () const {
357 return upper ();
358 }
359
360 String String::operator- () const {
361 return lower ();
362 }
363
364 String String::operator- (size_t n) const {
365 String newstr = m_string;
366 newstr -= n;
367 return newstr;
368 }
369
370 String& String::operator-= (size_t n) {
371 trim (n);
372 return *this;
373 }
374
375 size_t String::operator~ () const {
376 return len ();
377 }
378
379 vector<String> String::operator/ (String del) const {
380 return split (del);
381 }
382
383 char& String::operator[] (size_t n) {
384 return m_string[n];
385 }
386
387 const char& String::operator[] (size_t n) const {
388 return m_string[n];
389 }
390
391 bool String::operator== (const String other) const {
392 return compare (other) == 0;
393 }
394
395 bool String::operator== (const char* other) const {
396 return compare (other) == 0;
397 }
398
399 bool String::operator!= (const String other) const {
400 return compare (other) != 0;
401 }
402
403 bool String::operator!= (const char* other) const {
404 return compare (other) != 0;
405 }
406
407 bool String::operator! () const {
408 return empty ();
409 }
410
411 String::operator const char* () const {
412 return chars ();
413 }
414
415 String::operator QString () {
416 return chars ();
417 }
418
419 String::operator const QString () const {
420 return chars ();
421 }
422
423 str String::join (const vector<str>& items, const str& delim) {
424 str text;
425
426 for (const str& item : items) {
427 if (item != items[0])
428 text += delim;
429
430 text += item;
431 }
432
433 return text;
434 }

mercurial