fix build with recent changes/gcc 6.3.0
[AROS-Contrib.git] / arospdf / goo / GString.cc
blob30b1b70991be695dddc0a556dffeb2f411be287c
1 //========================================================================
2 //
3 // GString.cc
4 //
5 // Simple variable-length string type.
6 //
7 // Copyright 1996-2003 Glyph & Cog, LLC
8 //
9 //========================================================================
11 #include <aconf.h>
13 #ifdef USE_GCC_PRAGMAS
14 #pragma implementation
15 #endif
17 #include <stdlib.h>
18 #include <stddef.h>
19 #include <string.h>
20 #include <ctype.h>
21 #include <math.h>
22 #include "gmem.h"
23 #include "GString.h"
25 //------------------------------------------------------------------------
27 union GStringFormatArg {
28 int i;
29 Guint ui;
30 long l;
31 Gulong ul;
32 double f;
33 char c;
34 char *s;
35 GString *gs;
38 enum GStringFormatType {
39 fmtIntDecimal,
40 fmtIntHex,
41 fmtIntOctal,
42 fmtIntBinary,
43 fmtUIntDecimal,
44 fmtUIntHex,
45 fmtUIntOctal,
46 fmtUIntBinary,
47 fmtLongDecimal,
48 fmtLongHex,
49 fmtLongOctal,
50 fmtLongBinary,
51 fmtULongDecimal,
52 fmtULongHex,
53 fmtULongOctal,
54 fmtULongBinary,
55 fmtDouble,
56 fmtDoubleTrim,
57 fmtChar,
58 fmtString,
59 fmtGString,
60 fmtSpace
63 static const char *formatStrings[] = {
64 "d", "x", "o", "b", "ud", "ux", "uo", "ub",
65 "ld", "lx", "lo", "lb", "uld", "ulx", "ulo", "ulb",
66 "f", "g",
67 "c",
68 "s",
69 "t",
70 "w",
71 NULL
74 //------------------------------------------------------------------------
76 static inline int size(int len) {
77 int delta;
78 for (delta = 8; delta < len && delta < 0x100000; delta <<= 1) ;
79 // this is ((len + 1) + (delta - 1)) & ~(delta - 1)
80 return (len + delta) & ~(delta - 1);
83 inline void GString::resize(int length1) {
84 char *s1;
86 if (!s) {
87 s = new char[size(length1)];
88 } else if (size(length1) != size(length)) {
89 s1 = new char[size(length1)];
90 if (length1 < length) {
91 memcpy(s1, s, length1);
92 s1[length1] = '\0';
93 } else {
94 memcpy(s1, s, length + 1);
96 delete[] s;
97 s = s1;
101 GString::GString() {
102 s = NULL;
103 resize(length = 0);
104 s[0] = '\0';
107 GString::GString(const char *sA) {
108 int n = strlen(sA);
110 s = NULL;
111 resize(length = n);
112 memcpy(s, sA, n + 1);
115 GString::GString(const char *sA, int lengthA) {
116 s = NULL;
117 resize(length = lengthA);
118 memcpy(s, sA, length * sizeof(char));
119 s[length] = '\0';
122 GString::GString(GString *str, int idx, int lengthA) {
123 s = NULL;
124 resize(length = lengthA);
125 memcpy(s, str->getCString() + idx, length);
126 s[length] = '\0';
129 GString::GString(GString *str) {
130 s = NULL;
131 resize(length = str->getLength());
132 memcpy(s, str->getCString(), length + 1);
135 GString::GString(GString *str1, GString *str2) {
136 int n1 = str1->getLength();
137 int n2 = str2->getLength();
139 s = NULL;
140 resize(length = n1 + n2);
141 memcpy(s, str1->getCString(), n1);
142 memcpy(s + n1, str2->getCString(), n2 + 1);
145 GString *GString::fromInt(int x) {
146 char buf[24]; // enough space for 64-bit ints plus a little extra
147 char *p;
148 int len;
150 formatInt(x, buf, sizeof(buf), gFalse, 0, 10, &p, &len);
151 return new GString(p, len);
154 GString *GString::format(char *fmt, ...) {
155 va_list argList;
156 GString *s;
158 s = new GString();
159 va_start(argList, fmt);
160 s->appendfv(fmt, argList);
161 va_end(argList);
162 return s;
165 GString *GString::formatv(char *fmt, va_list argList) {
166 GString *s;
168 s = new GString();
169 s->appendfv(fmt, argList);
170 return s;
173 GString::~GString() {
174 delete[] s;
177 GString *GString::clear() {
178 s[length = 0] = '\0';
179 resize(0);
180 return this;
183 GString *GString::append(char c) {
184 resize(length + 1);
185 s[length++] = c;
186 s[length] = '\0';
187 return this;
190 GString *GString::append(GString *str) {
191 int n = str->getLength();
193 resize(length + n);
194 memcpy(s + length, str->getCString(), n + 1);
195 length += n;
196 return this;
199 GString *GString::append(const char *str) {
200 int n = strlen(str);
202 resize(length + n);
203 memcpy(s + length, str, n + 1);
204 length += n;
205 return this;
208 GString *GString::append(const char *str, int lengthA) {
209 resize(length + lengthA);
210 memcpy(s + length, str, lengthA);
211 length += lengthA;
212 s[length] = '\0';
213 return this;
216 GString *GString::appendf(char *fmt, ...) {
217 va_list argList;
219 va_start(argList, fmt);
220 appendfv(fmt, argList);
221 va_end(argList);
222 return this;
225 GString *GString::appendfv(char *fmt, va_list argList) {
226 GStringFormatArg *args;
227 int argsLen, argsSize;
228 GStringFormatArg arg;
229 int idx, width, prec;
230 GBool reverseAlign, zeroFill;
231 GStringFormatType ft;
232 char buf[65];
233 int len, i;
234 char *p0, *p1, *str;
236 argsLen = 0;
237 argsSize = 8;
238 args = (GStringFormatArg *)gmallocn(argsSize, sizeof(GStringFormatArg));
240 p0 = fmt;
241 while (*p0) {
242 if (*p0 == '{') {
243 ++p0;
244 if (*p0 == '{') {
245 ++p0;
246 append('{');
247 } else {
249 // parse the format string
250 if (!(*p0 >= '0' && *p0 <= '9')) {
251 break;
253 idx = *p0 - '0';
254 for (++p0; *p0 >= '0' && *p0 <= '9'; ++p0) {
255 idx = 10 * idx + (*p0 - '0');
257 if (*p0 != ':') {
258 break;
260 ++p0;
261 if (*p0 == '-') {
262 reverseAlign = gTrue;
263 ++p0;
264 } else {
265 reverseAlign = gFalse;
267 width = 0;
268 zeroFill = *p0 == '0';
269 for (; *p0 >= '0' && *p0 <= '9'; ++p0) {
270 width = 10 * width + (*p0 - '0');
272 if (*p0 == '.') {
273 ++p0;
274 prec = 0;
275 for (; *p0 >= '0' && *p0 <= '9'; ++p0) {
276 prec = 10 * prec + (*p0 - '0');
278 } else {
279 prec = 0;
281 for (ft = (GStringFormatType)0;
282 formatStrings[ft];
283 ft = (GStringFormatType)(ft + 1)) {
284 if (!strncmp(p0, formatStrings[ft], strlen(formatStrings[ft]))) {
285 break;
288 if (!formatStrings[ft]) {
289 break;
291 p0 += strlen(formatStrings[ft]);
292 if (*p0 != '}') {
293 break;
295 ++p0;
297 // fetch the argument
298 if (idx > argsLen) {
299 break;
301 if (idx == argsLen) {
302 if (argsLen == argsSize) {
303 argsSize *= 2;
304 args = (GStringFormatArg *)greallocn(args, argsSize,
305 sizeof(GStringFormatArg));
307 switch (ft) {
308 case fmtIntDecimal:
309 case fmtIntHex:
310 case fmtIntOctal:
311 case fmtIntBinary:
312 case fmtSpace:
313 args[argsLen].i = va_arg(argList, int);
314 break;
315 case fmtUIntDecimal:
316 case fmtUIntHex:
317 case fmtUIntOctal:
318 case fmtUIntBinary:
319 args[argsLen].ui = va_arg(argList, Guint);
320 break;
321 case fmtLongDecimal:
322 case fmtLongHex:
323 case fmtLongOctal:
324 case fmtLongBinary:
325 args[argsLen].l = va_arg(argList, long);
326 break;
327 case fmtULongDecimal:
328 case fmtULongHex:
329 case fmtULongOctal:
330 case fmtULongBinary:
331 args[argsLen].ul = va_arg(argList, Gulong);
332 break;
333 case fmtDouble:
334 case fmtDoubleTrim:
335 args[argsLen].f = va_arg(argList, double);
336 break;
337 case fmtChar:
338 args[argsLen].c = (char)va_arg(argList, int);
339 break;
340 case fmtString:
341 args[argsLen].s = va_arg(argList, char *);
342 break;
343 case fmtGString:
344 args[argsLen].gs = va_arg(argList, GString *);
345 break;
347 ++argsLen;
350 // format the argument
351 arg = args[idx];
352 switch (ft) {
353 case fmtIntDecimal:
354 formatInt(arg.i, buf, sizeof(buf), zeroFill, width, 10, &str, &len);
355 break;
356 case fmtIntHex:
357 formatInt(arg.i, buf, sizeof(buf), zeroFill, width, 16, &str, &len);
358 break;
359 case fmtIntOctal:
360 formatInt(arg.i, buf, sizeof(buf), zeroFill, width, 8, &str, &len);
361 break;
362 case fmtIntBinary:
363 formatInt(arg.i, buf, sizeof(buf), zeroFill, width, 2, &str, &len);
364 break;
365 case fmtUIntDecimal:
366 formatUInt(arg.ui, buf, sizeof(buf), zeroFill, width, 10,
367 &str, &len);
368 break;
369 case fmtUIntHex:
370 formatUInt(arg.ui, buf, sizeof(buf), zeroFill, width, 16,
371 &str, &len);
372 break;
373 case fmtUIntOctal:
374 formatUInt(arg.ui, buf, sizeof(buf), zeroFill, width, 8, &str, &len);
375 break;
376 case fmtUIntBinary:
377 formatUInt(arg.ui, buf, sizeof(buf), zeroFill, width, 2, &str, &len);
378 break;
379 case fmtLongDecimal:
380 formatInt(arg.l, buf, sizeof(buf), zeroFill, width, 10, &str, &len);
381 break;
382 case fmtLongHex:
383 formatInt(arg.l, buf, sizeof(buf), zeroFill, width, 16, &str, &len);
384 break;
385 case fmtLongOctal:
386 formatInt(arg.l, buf, sizeof(buf), zeroFill, width, 8, &str, &len);
387 break;
388 case fmtLongBinary:
389 formatInt(arg.l, buf, sizeof(buf), zeroFill, width, 2, &str, &len);
390 break;
391 case fmtULongDecimal:
392 formatUInt(arg.ul, buf, sizeof(buf), zeroFill, width, 10,
393 &str, &len);
394 break;
395 case fmtULongHex:
396 formatUInt(arg.ul, buf, sizeof(buf), zeroFill, width, 16,
397 &str, &len);
398 break;
399 case fmtULongOctal:
400 formatUInt(arg.ul, buf, sizeof(buf), zeroFill, width, 8, &str, &len);
401 break;
402 case fmtULongBinary:
403 formatUInt(arg.ul, buf, sizeof(buf), zeroFill, width, 2, &str, &len);
404 break;
405 case fmtDouble:
406 formatDouble(arg.f, buf, sizeof(buf), prec, gFalse, &str, &len);
407 break;
408 case fmtDoubleTrim:
409 formatDouble(arg.f, buf, sizeof(buf), prec, gTrue, &str, &len);
410 break;
411 case fmtChar:
412 buf[0] = arg.c;
413 str = buf;
414 len = 1;
415 reverseAlign = !reverseAlign;
416 break;
417 case fmtString:
418 str = arg.s;
419 len = strlen(str);
420 reverseAlign = !reverseAlign;
421 break;
422 case fmtGString:
423 str = arg.gs->getCString();
424 len = arg.gs->getLength();
425 reverseAlign = !reverseAlign;
426 break;
427 case fmtSpace:
428 str = buf;
429 len = 0;
430 width = arg.i;
431 break;
434 // append the formatted arg, handling width and alignment
435 if (!reverseAlign && len < width) {
436 for (i = len; i < width; ++i) {
437 append(' ');
440 append(str, len);
441 if (reverseAlign && len < width) {
442 for (i = len; i < width; ++i) {
443 append(' ');
448 } else if (*p0 == '}') {
449 ++p0;
450 if (*p0 == '}') {
451 ++p0;
453 append('}');
455 } else {
456 for (p1 = p0 + 1; *p1 && *p1 != '{' && *p1 != '}'; ++p1) ;
457 append(p0, p1 - p0);
458 p0 = p1;
462 gfree(args);
463 return this;
466 void GString::formatInt(long x, char *buf, int bufSize,
467 GBool zeroFill, int width, int base,
468 char **p, int *len) {
469 static char vals[17] = "0123456789abcdef";
470 GBool neg;
471 int start, i, j;
473 i = bufSize;
474 if ((neg = x < 0)) {
475 x = -x;
477 start = neg ? 1 : 0;
478 if (x == 0) {
479 buf[--i] = '0';
480 } else {
481 while (i > start && x) {
482 buf[--i] = vals[x % base];
483 x /= base;
486 if (zeroFill) {
487 for (j = bufSize - i; i > start && j < width - start; ++j) {
488 buf[--i] = '0';
491 if (neg) {
492 buf[--i] = '-';
494 *p = buf + i;
495 *len = bufSize - i;
498 void GString::formatUInt(Gulong x, char *buf, int bufSize,
499 GBool zeroFill, int width, int base,
500 char **p, int *len) {
501 static char vals[17] = "0123456789abcdef";
502 int i, j;
504 i = bufSize;
505 if (x == 0) {
506 buf[--i] = '0';
507 } else {
508 while (i > 0 && x) {
509 buf[--i] = vals[x % base];
510 x /= base;
513 if (zeroFill) {
514 for (j = bufSize - i; i > 0 && j < width; ++j) {
515 buf[--i] = '0';
518 *p = buf + i;
519 *len = bufSize - i;
522 void GString::formatDouble(double x, char *buf, int bufSize, int prec,
523 GBool trim, char **p, int *len) {
524 GBool neg, started;
525 double x2;
526 int d, i, j;
528 if ((neg = x < 0)) {
529 x = -x;
531 x = floor(x * pow(10, prec) + 0.5);
532 i = bufSize;
533 started = !trim;
534 for (j = 0; j < prec && i > 1; ++j) {
535 x2 = floor(0.1 * (x + 0.5));
536 d = (int)floor(x - 10 * x2 + 0.5);
537 if (started || d != 0) {
538 buf[--i] = '0' + d;
539 started = gTrue;
541 x = x2;
543 if (i > 1 && started) {
544 buf[--i] = '.';
546 if (i > 1) {
547 do {
548 x2 = floor(0.1 * (x + 0.5));
549 d = (int)floor(x - 10 * x2 + 0.5);
550 buf[--i] = '0' + d;
551 x = x2;
552 } while (i > 1 && x);
554 if (neg) {
555 buf[--i] = '-';
557 *p = buf + i;
558 *len = bufSize - i;
561 GString *GString::insert(int i, char c) {
562 int j;
564 resize(length + 1);
565 for (j = length + 1; j > i; --j)
566 s[j] = s[j-1];
567 s[i] = c;
568 ++length;
569 return this;
572 GString *GString::insert(int i, GString *str) {
573 int n = str->getLength();
574 int j;
576 resize(length + n);
577 for (j = length; j >= i; --j)
578 s[j+n] = s[j];
579 memcpy(s+i, str->getCString(), n);
580 length += n;
581 return this;
584 GString *GString::insert(int i, const char *str) {
585 int n = strlen(str);
586 int j;
588 resize(length + n);
589 for (j = length; j >= i; --j)
590 s[j+n] = s[j];
591 memcpy(s+i, str, n);
592 length += n;
593 return this;
596 GString *GString::insert(int i, const char *str, int lengthA) {
597 int j;
599 resize(length + lengthA);
600 for (j = length; j >= i; --j)
601 s[j+lengthA] = s[j];
602 memcpy(s+i, str, lengthA);
603 length += lengthA;
604 return this;
607 GString *GString::del(int i, int n) {
608 int j;
610 if (n > 0) {
611 if (i + n > length) {
612 n = length - i;
614 for (j = i; j <= length - n; ++j) {
615 s[j] = s[j + n];
617 resize(length -= n);
619 return this;
622 GString *GString::upperCase() {
623 int i;
625 for (i = 0; i < length; ++i) {
626 if (islower(s[i]))
627 s[i] = toupper(s[i]);
629 return this;
632 GString *GString::lowerCase() {
633 int i;
635 for (i = 0; i < length; ++i) {
636 if (isupper(s[i]))
637 s[i] = tolower(s[i]);
639 return this;
642 int GString::cmp(GString *str) {
643 int n1, n2, i, x;
644 char *p1, *p2;
646 n1 = length;
647 n2 = str->length;
648 for (i = 0, p1 = s, p2 = str->s; i < n1 && i < n2; ++i, ++p1, ++p2) {
649 x = *p1 - *p2;
650 if (x != 0) {
651 return x;
654 return n1 - n2;
657 int GString::cmpN(GString *str, int n) {
658 int n1, n2, i, x;
659 char *p1, *p2;
661 n1 = length;
662 n2 = str->length;
663 for (i = 0, p1 = s, p2 = str->s;
664 i < n1 && i < n2 && i < n;
665 ++i, ++p1, ++p2) {
666 x = *p1 - *p2;
667 if (x != 0) {
668 return x;
671 if (i == n) {
672 return 0;
674 return n1 - n2;
677 int GString::cmp(const char *sA) {
678 int n1, i, x;
679 const char *p1, *p2;
681 n1 = length;
682 for (i = 0, p1 = s, p2 = sA; i < n1 && *p2; ++i, ++p1, ++p2) {
683 x = *p1 - *p2;
684 if (x != 0) {
685 return x;
688 if (i < n1) {
689 return 1;
691 if (*p2) {
692 return -1;
694 return 0;
697 int GString::cmpN(const char *sA, int n) {
698 int n1, i, x;
699 const char *p1, *p2;
701 n1 = length;
702 for (i = 0, p1 = s, p2 = sA; i < n1 && *p2 && i < n; ++i, ++p1, ++p2) {
703 x = *p1 - *p2;
704 if (x != 0) {
705 return x;
708 if (i == n) {
709 return 0;
711 if (i < n1) {
712 return 1;
714 if (*p2) {
715 return -1;
717 return 0;