/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- size
- resize
- fromInt
- format
- formatv
- clear
- append
- append
- append
- append
- appendf
- appendfv
- formatInt
- formatUInt
- formatDouble
- insert
- insert
- insert
- insert
- del
- upperCase
- lowerCase
- cmp
- cmpN
- cmp
- cmpN
//========================================================================
//
// GString.cc
//
// Simple variable-length string type.
//
// Copyright 1996-2003 Glyph & Cog, LLC
//
//========================================================================
#include <aconf.h>
#ifdef USE_GCC_PRAGMAS
#pragma implementation
#endif
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include "gmem.h"
#include "GString.h"
//------------------------------------------------------------------------
union GStringFormatArg {
int i;
Guint ui;
long l;
Gulong ul;
double f;
char c;
char *s;
GString *gs;
};
enum GStringFormatType {
fmtIntDecimal,
fmtIntHex,
fmtIntOctal,
fmtIntBinary,
fmtUIntDecimal,
fmtUIntHex,
fmtUIntOctal,
fmtUIntBinary,
fmtLongDecimal,
fmtLongHex,
fmtLongOctal,
fmtLongBinary,
fmtULongDecimal,
fmtULongHex,
fmtULongOctal,
fmtULongBinary,
fmtDouble,
fmtDoubleTrim,
fmtChar,
fmtString,
fmtGString,
fmtSpace
};
static char *formatStrings[] = {
"d", "x", "o", "b", "ud", "ux", "uo", "ub",
"ld", "lx", "lo", "lb", "uld", "ulx", "ulo", "ulb",
"f", "g",
"c",
"s",
"t",
"w",
NULL
};
//------------------------------------------------------------------------
static inline int size(int len) {
int delta;
for (delta = 8; delta < len && delta < 0x100000; delta <<= 1) ;
// this is ((len + 1) + (delta - 1)) & ~(delta - 1)
return (len + delta) & ~(delta - 1);
}
inline void GString::resize(int length1) {
char *s1;
if (!s) {
s = new char[size(length1)];
} else if (size(length1) != size(length)) {
s1 = new char[size(length1)];
if (length1 < length) {
memcpy(s1, s, length1);
s1[length1] = '\0';
} else {
memcpy(s1, s, length + 1);
}
delete[] s;
s = s1;
}
}
GString::GString() {
s = NULL;
resize(length = 0);
s[0] = '\0';
}
GString::GString(const char *sA) {
int n = strlen(sA);
s = NULL;
resize(length = n);
memcpy(s, sA, n + 1);
}
GString::GString(const char *sA, int lengthA) {
s = NULL;
resize(length = lengthA);
memcpy(s, sA, length * sizeof(char));
s[length] = '\0';
}
GString::GString(GString *str, int idx, int lengthA) {
s = NULL;
resize(length = lengthA);
memcpy(s, str->getCString() + idx, length);
s[length] = '\0';
}
GString::GString(GString *str) {
s = NULL;
resize(length = str->getLength());
memcpy(s, str->getCString(), length + 1);
}
GString::GString(GString *str1, GString *str2) {
int n1 = str1->getLength();
int n2 = str2->getLength();
s = NULL;
resize(length = n1 + n2);
memcpy(s, str1->getCString(), n1);
memcpy(s + n1, str2->getCString(), n2 + 1);
}
GString *GString::fromInt(int x) {
char buf[24]; // enough space for 64-bit ints plus a little extra
char *p;
int len;
formatInt(x, buf, sizeof(buf), gFalse, 0, 10, &p, &len);
return new GString(p, len);
}
GString *GString::format(char *fmt, ...) {
va_list argList;
GString *s;
s = new GString();
va_start(argList, fmt);
s->appendfv(fmt, argList);
va_end(argList);
return s;
}
GString *GString::formatv(char *fmt, va_list argList) {
GString *s;
s = new GString();
s->appendfv(fmt, argList);
return s;
}
GString::~GString() {
delete[] s;
}
GString *GString::clear() {
s[length = 0] = '\0';
resize(0);
return this;
}
GString *GString::append(char c) {
resize(length + 1);
s[length++] = c;
s[length] = '\0';
return this;
}
GString *GString::append(GString *str) {
int n = str->getLength();
resize(length + n);
memcpy(s + length, str->getCString(), n + 1);
length += n;
return this;
}
GString *GString::append(const char *str) {
int n = strlen(str);
resize(length + n);
memcpy(s + length, str, n + 1);
length += n;
return this;
}
GString *GString::append(const char *str, int lengthA) {
resize(length + lengthA);
memcpy(s + length, str, lengthA);
length += lengthA;
s[length] = '\0';
return this;
}
GString *GString::appendf(char *fmt, ...) {
va_list argList;
va_start(argList, fmt);
appendfv(fmt, argList);
va_end(argList);
return this;
}
GString *GString::appendfv(char *fmt, va_list argList) {
GStringFormatArg *args;
int argsLen, argsSize;
GStringFormatArg arg;
int idx, width, prec;
GBool reverseAlign, zeroFill;
GStringFormatType ft;
char buf[65];
int len, i;
char *p0, *p1, *str;
argsLen = 0;
argsSize = 8;
args = (GStringFormatArg *)gmallocn(argsSize, sizeof(GStringFormatArg));
p0 = fmt;
while (*p0) {
if (*p0 == '{') {
++p0;
if (*p0 == '{') {
++p0;
append('{');
} else {
// parse the format string
if (!(*p0 >= '0' && *p0 <= '9')) {
break;
}
idx = *p0 - '0';
for (++p0; *p0 >= '0' && *p0 <= '9'; ++p0) {
idx = 10 * idx + (*p0 - '0');
}
if (*p0 != ':') {
break;
}
++p0;
if (*p0 == '-') {
reverseAlign = gTrue;
++p0;
} else {
reverseAlign = gFalse;
}
width = 0;
zeroFill = *p0 == '0';
for (; *p0 >= '0' && *p0 <= '9'; ++p0) {
width = 10 * width + (*p0 - '0');
}
if (*p0 == '.') {
++p0;
prec = 0;
for (; *p0 >= '0' && *p0 <= '9'; ++p0) {
prec = 10 * prec + (*p0 - '0');
}
} else {
prec = 0;
}
for (ft = (GStringFormatType)0;
formatStrings[ft];
ft = (GStringFormatType)(ft + 1)) {
if (!strncmp(p0, formatStrings[ft], strlen(formatStrings[ft]))) {
break;
}
}
if (!formatStrings[ft]) {
break;
}
p0 += strlen(formatStrings[ft]);
if (*p0 != '}') {
break;
}
++p0;
// fetch the argument
if (idx > argsLen) {
break;
}
if (idx == argsLen) {
if (argsLen == argsSize) {
argsSize *= 2;
args = (GStringFormatArg *)greallocn(args, argsSize,
sizeof(GStringFormatArg));
}
switch (ft) {
case fmtIntDecimal:
case fmtIntHex:
case fmtIntOctal:
case fmtIntBinary:
case fmtSpace:
args[argsLen].i = va_arg(argList, int);
break;
case fmtUIntDecimal:
case fmtUIntHex:
case fmtUIntOctal:
case fmtUIntBinary:
args[argsLen].ui = va_arg(argList, Guint);
break;
case fmtLongDecimal:
case fmtLongHex:
case fmtLongOctal:
case fmtLongBinary:
args[argsLen].l = va_arg(argList, long);
break;
case fmtULongDecimal:
case fmtULongHex:
case fmtULongOctal:
case fmtULongBinary:
args[argsLen].ul = va_arg(argList, Gulong);
break;
case fmtDouble:
case fmtDoubleTrim:
args[argsLen].f = va_arg(argList, double);
break;
case fmtChar:
args[argsLen].c = (char)va_arg(argList, int);
break;
case fmtString:
args[argsLen].s = va_arg(argList, char *);
break;
case fmtGString:
args[argsLen].gs = va_arg(argList, GString *);
break;
}
++argsLen;
}
// format the argument
arg = args[idx];
switch (ft) {
case fmtIntDecimal:
formatInt(arg.i, buf, sizeof(buf), zeroFill, width, 10, &str, &len);
break;
case fmtIntHex:
formatInt(arg.i, buf, sizeof(buf), zeroFill, width, 16, &str, &len);
break;
case fmtIntOctal:
formatInt(arg.i, buf, sizeof(buf), zeroFill, width, 8, &str, &len);
break;
case fmtIntBinary:
formatInt(arg.i, buf, sizeof(buf), zeroFill, width, 2, &str, &len);
break;
case fmtUIntDecimal:
formatUInt(arg.ui, buf, sizeof(buf), zeroFill, width, 10,
&str, &len);
break;
case fmtUIntHex:
formatUInt(arg.ui, buf, sizeof(buf), zeroFill, width, 16,
&str, &len);
break;
case fmtUIntOctal:
formatUInt(arg.ui, buf, sizeof(buf), zeroFill, width, 8, &str, &len);
break;
case fmtUIntBinary:
formatUInt(arg.ui, buf, sizeof(buf), zeroFill, width, 2, &str, &len);
break;
case fmtLongDecimal:
formatInt(arg.l, buf, sizeof(buf), zeroFill, width, 10, &str, &len);
break;
case fmtLongHex:
formatInt(arg.l, buf, sizeof(buf), zeroFill, width, 16, &str, &len);
break;
case fmtLongOctal:
formatInt(arg.l, buf, sizeof(buf), zeroFill, width, 8, &str, &len);
break;
case fmtLongBinary:
formatInt(arg.l, buf, sizeof(buf), zeroFill, width, 2, &str, &len);
break;
case fmtULongDecimal:
formatUInt(arg.ul, buf, sizeof(buf), zeroFill, width, 10,
&str, &len);
break;
case fmtULongHex:
formatUInt(arg.ul, buf, sizeof(buf), zeroFill, width, 16,
&str, &len);
break;
case fmtULongOctal:
formatUInt(arg.ul, buf, sizeof(buf), zeroFill, width, 8, &str, &len);
break;
case fmtULongBinary:
formatUInt(arg.ul, buf, sizeof(buf), zeroFill, width, 2, &str, &len);
break;
case fmtDouble:
formatDouble(arg.f, buf, sizeof(buf), prec, gFalse, &str, &len);
break;
case fmtDoubleTrim:
formatDouble(arg.f, buf, sizeof(buf), prec, gTrue, &str, &len);
break;
case fmtChar:
buf[0] = arg.c;
str = buf;
len = 1;
reverseAlign = !reverseAlign;
break;
case fmtString:
str = arg.s;
len = strlen(str);
reverseAlign = !reverseAlign;
break;
case fmtGString:
str = arg.gs->getCString();
len = arg.gs->getLength();
reverseAlign = !reverseAlign;
break;
case fmtSpace:
str = buf;
len = 0;
width = arg.i;
break;
}
// append the formatted arg, handling width and alignment
if (!reverseAlign && len < width) {
for (i = len; i < width; ++i) {
append(' ');
}
}
append(str, len);
if (reverseAlign && len < width) {
for (i = len; i < width; ++i) {
append(' ');
}
}
}
} else if (*p0 == '}') {
++p0;
if (*p0 == '}') {
++p0;
}
append('}');
} else {
for (p1 = p0 + 1; *p1 && *p1 != '{' && *p1 != '}'; ++p1) ;
append(p0, p1 - p0);
p0 = p1;
}
}
gfree(args);
return this;
}
void GString::formatInt(long x, char *buf, int bufSize,
GBool zeroFill, int width, int base,
char **p, int *len) {
static char vals[17] = "0123456789abcdef";
GBool neg;
int start, i, j;
i = bufSize;
if ((neg = x < 0)) {
x = -x;
}
start = neg ? 1 : 0;
if (x == 0) {
buf[--i] = '0';
} else {
while (i > start && x) {
buf[--i] = vals[x % base];
x /= base;
}
}
if (zeroFill) {
for (j = bufSize - i; i > start && j < width - start; ++j) {
buf[--i] = '0';
}
}
if (neg) {
buf[--i] = '-';
}
*p = buf + i;
*len = bufSize - i;
}
void GString::formatUInt(Gulong x, char *buf, int bufSize,
GBool zeroFill, int width, int base,
char **p, int *len) {
static char vals[17] = "0123456789abcdef";
int i, j;
i = bufSize;
if (x == 0) {
buf[--i] = '0';
} else {
while (i > 0 && x) {
buf[--i] = vals[x % base];
x /= base;
}
}
if (zeroFill) {
for (j = bufSize - i; i > 0 && j < width; ++j) {
buf[--i] = '0';
}
}
*p = buf + i;
*len = bufSize - i;
}
void GString::formatDouble(double x, char *buf, int bufSize, int prec,
GBool trim, char **p, int *len) {
GBool neg, started;
double x2;
int d, i, j;
if ((neg = x < 0)) {
x = -x;
}
x = floor(x * pow(10, prec) + 0.5);
i = bufSize;
started = !trim;
for (j = 0; j < prec && i > 1; ++j) {
x2 = floor(0.1 * (x + 0.5));
d = (int)floor(x - 10 * x2 + 0.5);
if (started || d != 0) {
buf[--i] = '0' + d;
started = gTrue;
}
x = x2;
}
if (i > 1 && started) {
buf[--i] = '.';
}
if (i > 1) {
do {
x2 = floor(0.1 * (x + 0.5));
d = (int)floor(x - 10 * x2 + 0.5);
buf[--i] = '0' + d;
x = x2;
} while (i > 1 && x);
}
if (neg) {
buf[--i] = '-';
}
*p = buf + i;
*len = bufSize - i;
}
GString *GString::insert(int i, char c) {
int j;
resize(length + 1);
for (j = length + 1; j > i; --j)
s[j] = s[j-1];
s[i] = c;
++length;
return this;
}
GString *GString::insert(int i, GString *str) {
int n = str->getLength();
int j;
resize(length + n);
for (j = length; j >= i; --j)
s[j+n] = s[j];
memcpy(s+i, str->getCString(), n);
length += n;
return this;
}
GString *GString::insert(int i, const char *str) {
int n = strlen(str);
int j;
resize(length + n);
for (j = length; j >= i; --j)
s[j+n] = s[j];
memcpy(s+i, str, n);
length += n;
return this;
}
GString *GString::insert(int i, const char *str, int lengthA) {
int j;
resize(length + lengthA);
for (j = length; j >= i; --j)
s[j+lengthA] = s[j];
memcpy(s+i, str, lengthA);
length += lengthA;
return this;
}
GString *GString::del(int i, int n) {
int j;
if (n > 0) {
if (i + n > length) {
n = length - i;
}
for (j = i; j <= length - n; ++j) {
s[j] = s[j + n];
}
resize(length -= n);
}
return this;
}
GString *GString::upperCase() {
int i;
for (i = 0; i < length; ++i) {
if (islower(s[i]))
s[i] = toupper(s[i]);
}
return this;
}
GString *GString::lowerCase() {
int i;
for (i = 0; i < length; ++i) {
if (isupper(s[i]))
s[i] = tolower(s[i]);
}
return this;
}
int GString::cmp(GString *str) {
int n1, n2, i, x;
char *p1, *p2;
n1 = length;
n2 = str->length;
for (i = 0, p1 = s, p2 = str->s; i < n1 && i < n2; ++i, ++p1, ++p2) {
x = *p1 - *p2;
if (x != 0) {
return x;
}
}
return n1 - n2;
}
int GString::cmpN(GString *str, int n) {
int n1, n2, i, x;
char *p1, *p2;
n1 = length;
n2 = str->length;
for (i = 0, p1 = s, p2 = str->s;
i < n1 && i < n2 && i < n;
++i, ++p1, ++p2) {
x = *p1 - *p2;
if (x != 0) {
return x;
}
}
if (i == n) {
return 0;
}
return n1 - n2;
}
int GString::cmp(const char *sA) {
int n1, i, x;
const char *p1, *p2;
n1 = length;
for (i = 0, p1 = s, p2 = sA; i < n1 && *p2; ++i, ++p1, ++p2) {
x = *p1 - *p2;
if (x != 0) {
return x;
}
}
if (i < n1) {
return 1;
}
if (*p2) {
return -1;
}
return 0;
}
int GString::cmpN(const char *sA, int n) {
int n1, i, x;
const char *p1, *p2;
n1 = length;
for (i = 0, p1 = s, p2 = sA; i < n1 && *p2 && i < n; ++i, ++p1, ++p2) {
x = *p1 - *p2;
if (x != 0) {
return x;
}
}
if (i == n) {
return 0;
}
if (i < n1) {
return 1;
}
if (*p2) {
return -1;
}
return 0;
}