src/str.cpp

changeset 189
ac2d3e8dd110
parent 188
4e686b771996
child 190
82f784cf2ce5
equal deleted inserted replaced
188:4e686b771996 189:ac2d3e8dd110
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 <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <stdarg.h>
23 #include <assert.h>
24 #include "str.h"
25 #include "common.h"
26 #include "misc.h"
27
28 #define ITERATE_STRING(u) \
29 for (uint u = 0; u < strlen (m_text); u++)
30
31 // ============================================================================
32 // vdynformat: Try to write to a formatted string with size bytes first, if
33 // that fails, double the size and keep recursing until it works.
34 char* vdynformat (const char* fmtstr, va_list va, long size) {
35 char* buffer = new char[size];
36 int r = vsnprintf (buffer, size - 1, fmtstr, va);
37 if (r > (signed)(size - 1) || r < 0) {
38 delete[] buffer;
39 buffer = vdynformat (fmtstr, va, size * 2);
40 }
41 return buffer;
42 }
43
44 // ============================================================================
45 str::str () {
46 m_text = new char[1];
47 clear();
48 m_allocated = strlen (m_text);
49 }
50
51 str::str (const char* c) {
52 m_text = new char[1];
53 m_text[0] = '\0';
54 m_writepos = m_allocated = 0;
55 append (c);
56 }
57
58 str::str (char c) {
59 m_text = new char[1];
60 m_text[0] = '\0';
61 m_writepos = m_allocated = 0;
62 append (c);
63 }
64
65 str::str (QString c) {
66 m_text = new char[1];
67 m_text[0] = '\0';
68 m_writepos = m_allocated = 0;
69 append (c);
70 }
71
72 str::~str () {
73 // delete[] text;
74 }
75
76 // ============================================================================
77 void str::clear () {
78 delete[] m_text;
79 m_text = new char[1];
80 m_text[0] = '\0';
81 m_writepos = 0;
82 m_allocated = 0;
83 }
84
85 // ============================================================================
86 void str::resize (uint len) {
87 uint oldlen = strlen (m_text);
88 char* oldtext = new char[oldlen];
89 strncpy (oldtext, m_text, oldlen);
90
91 delete[] m_text;
92 m_text = new char[len+1];
93 for (uint u = 0; u < len+1; u++)
94 m_text[u] = 0;
95 strncpy (m_text, oldtext, len);
96 delete[] oldtext;
97
98 m_allocated = len;
99 }
100
101 // ============================================================================
102 void str::dump () {
103 for (uint u = 0; u <= m_allocated; u++)
104 printf ("\t%u. %u (%c)\n", u, m_text[u], m_text[u]);
105 }
106
107 // ============================================================================
108 // Adds a new character at the end of the string.
109 void str::append (const char c) {
110 // Out of space, thus resize
111 if (m_writepos == m_allocated)
112 resize (m_allocated + 1);
113 m_text[m_writepos] = c;
114 m_writepos++;
115 }
116
117 void str::append (const char* c) {
118 resize (m_allocated + strlen (c));
119
120 for (uint u = 0; u < strlen (c); u++) {
121 if (c[u] != 0)
122 append (c[u]);
123 }
124 }
125
126 void str::append (str c) {
127 append (c.chars());
128 }
129
130 void str::append (QString c) {
131 append (c.toUtf8 ().constData ());
132 }
133
134 // ============================================================================
135 void str::appendformat (const char* c, ...) {
136 va_list v;
137
138 va_start (v, c);
139 char* buf = vdynformat (c, v, 256);
140 va_end (v);
141
142 append (buf);
143 delete[] buf;
144 }
145
146 void str::format (const char* fmt, ...) {
147 clear ();
148
149 va_list v;
150
151 va_start (v, fmt);
152 char* buf = vdynformat (fmt, v, 256);
153 va_end (v);
154
155 append (buf);
156 delete[] buf;
157 }
158
159 // ============================================================================
160 char* str::chars () {
161 return m_text;
162 }
163
164 // ============================================================================
165 int str::first (const char* c, uint a) {
166 uint r = 0;
167 uint index = 0;
168 for (; a < m_allocated; a++) {
169 if (m_text[a] == c[r]) {
170 if (r == 0)
171 index = a;
172
173 r++;
174 if (r == strlen (c))
175 return index;
176 } else {
177 if (r != 0) {
178 // If the string sequence broke at this point, we need to
179 // check this character again, for a new sequence just
180 // might start right here.
181 a--;
182 }
183
184 r = 0;
185 }
186 }
187
188 return -1;
189 }
190
191 // ============================================================================
192 int str::last (const char* c, int a) {
193 if (a == -1)
194 a = len();
195
196 int max = strlen (c)-1;
197
198 int r = max;
199 for (; a >= 0; a--) {
200 if (m_text[a] == c[r]) {
201 r--;
202 if (r == -1)
203 return a;
204 } else {
205 if (r != max)
206 a++;
207
208 r = max;
209 }
210 }
211
212 return -1;
213 }
214
215 // ============================================================================
216 str str::substr (uint a, uint b) {
217 if (a > len()) a = len();
218 if (b > len()) b = len();
219
220 if (b == a)
221 return "";
222
223 if (b < a) {
224 printf ("str::substring:: indices %u and %u given, should be the other way around, swapping..\n", a, b);
225
226 // Swap the variables
227 uint c = a;
228 a = b;
229 b = c;
230 }
231
232 char* s = new char[b - a + 1];
233 strncpy (s, m_text + a, b - a);
234 s[b - a] = '\0';
235
236 str other = s;
237 delete[] s;
238 return other;
239 }
240
241 // ============================================================================
242 void str::remove (uint idx, uint dellen) {
243 str s1 = substr (0, idx);
244 str s2 = substr (idx + dellen, -1);
245
246 clear();
247
248 append (s1);
249 append (s2);
250 }
251
252 // ============================================================================
253 str str::trim (int dellen) {
254 if (dellen > 0)
255 return substr (0, len() - dellen);
256 return substr (-dellen, len());
257 }
258
259 // ============================================================================
260 void str::replace (const char* o, const char* n, uint a) {
261 for (int idx; (idx = first (o, a)) != -1;) {
262 str s1 = substr (0, idx);
263 str s2 = substr (idx + strlen (o), len());
264
265 clear();
266
267 append (s1);
268 append (n);
269 append (s2);
270 }
271 }
272
273 // ============================================================================
274 str str::strip (char c) {
275 return strip ({c});
276 }
277
278 str str::strip (std::initializer_list<char> unwanted) {
279 str cache = m_text;
280 uint oldlen = len();
281
282 char* buf = new char[oldlen];
283 char* bufptr = buf;
284 for (uint i = 0; i < oldlen; i++) {
285 bool valid = true;
286 for (const char* j = unwanted.begin(); j < unwanted.end() && valid; j++)
287 if (m_text[i] == *j)
288 valid = false;
289
290 if (valid)
291 *bufptr++ = m_text[i];
292 }
293
294 *bufptr = '\0';
295 assert (bufptr <= buf + oldlen);
296
297 str zResult = buf;
298 delete[] buf;
299
300 return zResult;
301 }
302
303 void str::insert (char* c, uint pos) {
304 str s1 = substr (0, pos);
305 str s2 = substr (pos, len());
306
307 clear();
308 append (s1);
309 append (c);
310 append (s2);
311 }
312
313 str str::reverse () {
314 char* buf = new char[len() + 1];
315
316 for (uint i = 0; i < len(); i++)
317 buf[i] = m_text[len() - i - 1];
318 buf[len()] = '\0';
319
320 str other = buf;
321 delete[] buf;
322 return other;
323 }
324
325 str str::repeat (int n) {
326 assert (n >= 0);
327
328 str other;
329 for (int i = 0; i < n; i++)
330 other += m_text;
331 return other;
332 }
333
334 // ============================================================================
335 bool str::isnumber () {
336 ITERATE_STRING (u) {
337 // Minus sign as the first character is allowed for negatives
338 if (!u && m_text[u] == '-')
339 continue;
340
341 if (m_text[u] < '0' || m_text[u] > '9')
342 return false;
343 }
344 return true;
345 }
346
347 // ============================================================================
348 bool str::isword () {
349 ITERATE_STRING (u) {
350 // lowercase letters
351 if (m_text[u] >= 'a' || m_text[u] <= 'z')
352 continue;
353
354 // uppercase letters
355 if (m_text[u] >= 'A' || m_text[u] <= 'Z')
356 continue;
357
358 return false;
359 }
360 return true;
361 }
362
363 int str::instanceof (const char* c, uint n) {
364 uint r = 0;
365 uint index = 0;
366 uint x = 0;
367 for (uint a = 0; a < m_allocated; a++) {
368 if (m_text[a] == c[r]) {
369 if (r == 0)
370 index = a;
371
372 r++;
373 if (r == strlen (c)) {
374 if (x++ == n)
375 return index;
376 r = 0;
377 }
378 } else {
379 if (r != 0)
380 a--;
381 r = 0;
382 }
383 }
384
385 return -1;
386 }
387
388 // ============================================================================
389 int str::compare (const char* c) {
390 return strcmp (m_text, c);
391 }
392
393 int str::compare (str c) {
394 return compare (c.chars());
395 }
396
397 int str::icompare (const char* c) {
398 return icompare (str ((char*)c));
399 }
400
401 int str::icompare (str b) {
402 return strcmp (tolower().chars(), b.tolower().chars());
403 }
404
405 // ============================================================================
406 str str::tolower () {
407 str n = m_text;
408
409 for (uint u = 0; u < len(); u++) {
410 if (n[u] >= 'A' && n[u] < 'Z')
411 n.m_text[u] += ('a' - 'A');
412 }
413
414 return n;
415 }
416
417 // ============================================================================
418 str str::toupper () {
419 str n = m_text;
420
421 for (uint u = 0; u < len(); u++) {
422 if (n[u] >= 'a' && n[u] < 'z')
423 n.m_text[u] -= ('a' - 'A');
424 }
425
426 return n;
427 }
428
429 // ============================================================================
430 uint str::count (char c) {
431 uint n = 0;
432 ITERATE_STRING (u)
433 if (m_text[u] == c)
434 n++;
435 return n;
436 }
437
438 uint str::count (char* c) {
439 uint r = 0;
440 uint tmp = 0;
441 ITERATE_STRING (u) {
442 if (m_text[u] == c[r]) {
443 r++;
444 if (r == strlen (c)) {
445 r = 0;
446 tmp++;
447 }
448 } else {
449 if (r != 0)
450 u--;
451 r = 0;
452 }
453 }
454
455 return tmp;
456 }
457
458 // ============================================================================
459 std::vector<str> str::split (str del, bool bNoBlanks) {
460 std::vector<str> res;
461 uint a = 0;
462
463 // Find all separators and store the text left to them.
464 while (1) {
465 int b = first (del, a);
466
467 if (b == -1)
468 break;
469
470 if (!bNoBlanks || (b - a))
471 res.push_back (substr (a, b));
472
473 a = b + strlen (del);
474 }
475
476 // Add the string at the right of the last separator
477 if (!bNoBlanks || (len () - a))
478 res.push_back (substr (a, len ()));
479 return res;
480 }
481
482 std::vector<str> str::operator/ (str splitstring) {return split(splitstring);}
483 std::vector<str> str::operator/ (char* splitstring) {return split(splitstring);}
484 std::vector<str> str::operator/ (const char* splitstring) {return split(splitstring);}
485
486 str& str::operator+= (vertex vrt) {
487 appendformat ("%s", vrt.stringRep (false).chars());
488 return *this;
489 }
490
491 str fmt (const char* fmt, ...) {
492 va_list va;
493 char* buf;
494
495 va_start (va, fmt);
496 buf = vdynformat (fmt, va, 256);
497 va_end (va);
498
499 str val = buf;
500 delete[] buf;
501 return val;
502 }

mercurial