1 //========================================================================
5 // Simple variable-length string type.
7 // Copyright 1996-2003 Glyph & Cog, LLC
9 //========================================================================
13 #ifdef USE_GCC_PRAGMAS
14 #pragma implementation
25 //------------------------------------------------------------------------
27 union GStringFormatArg
{
38 enum GStringFormatType
{
63 static const char *formatStrings
[] = {
64 "d", "x", "o", "b", "ud", "ux", "uo", "ub",
65 "ld", "lx", "lo", "lb", "uld", "ulx", "ulo", "ulb",
74 //------------------------------------------------------------------------
76 static inline int size(int len
) {
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
) {
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
);
94 memcpy(s1
, s
, length
+ 1);
107 GString::GString(const char *sA
) {
112 memcpy(s
, sA
, n
+ 1);
115 GString::GString(const char *sA
, int lengthA
) {
117 resize(length
= lengthA
);
118 memcpy(s
, sA
, length
* sizeof(char));
122 GString::GString(GString
*str
, int idx
, int lengthA
) {
124 resize(length
= lengthA
);
125 memcpy(s
, str
->getCString() + idx
, length
);
129 GString::GString(GString
*str
) {
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();
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
150 formatInt(x
, buf
, sizeof(buf
), gFalse
, 0, 10, &p
, &len
);
151 return new GString(p
, len
);
154 GString
*GString::format(char *fmt
, ...) {
159 va_start(argList
, fmt
);
160 s
->appendfv(fmt
, argList
);
165 GString
*GString::formatv(char *fmt
, va_list argList
) {
169 s
->appendfv(fmt
, argList
);
173 GString::~GString() {
177 GString
*GString::clear() {
178 s
[length
= 0] = '\0';
183 GString
*GString::append(char c
) {
190 GString
*GString::append(GString
*str
) {
191 int n
= str
->getLength();
194 memcpy(s
+ length
, str
->getCString(), n
+ 1);
199 GString
*GString::append(const char *str
) {
203 memcpy(s
+ length
, str
, n
+ 1);
208 GString
*GString::append(const char *str
, int lengthA
) {
209 resize(length
+ lengthA
);
210 memcpy(s
+ length
, str
, lengthA
);
216 GString
*GString::appendf(char *fmt
, ...) {
219 va_start(argList
, fmt
);
220 appendfv(fmt
, argList
);
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
;
238 args
= (GStringFormatArg
*)gmallocn(argsSize
, sizeof(GStringFormatArg
));
249 // parse the format string
250 if (!(*p0
>= '0' && *p0
<= '9')) {
254 for (++p0
; *p0
>= '0' && *p0
<= '9'; ++p0
) {
255 idx
= 10 * idx
+ (*p0
- '0');
262 reverseAlign
= gTrue
;
265 reverseAlign
= gFalse
;
268 zeroFill
= *p0
== '0';
269 for (; *p0
>= '0' && *p0
<= '9'; ++p0
) {
270 width
= 10 * width
+ (*p0
- '0');
275 for (; *p0
>= '0' && *p0
<= '9'; ++p0
) {
276 prec
= 10 * prec
+ (*p0
- '0');
281 for (ft
= (GStringFormatType
)0;
283 ft
= (GStringFormatType
)(ft
+ 1)) {
284 if (!strncmp(p0
, formatStrings
[ft
], strlen(formatStrings
[ft
]))) {
288 if (!formatStrings
[ft
]) {
291 p0
+= strlen(formatStrings
[ft
]);
297 // fetch the argument
301 if (idx
== argsLen
) {
302 if (argsLen
== argsSize
) {
304 args
= (GStringFormatArg
*)greallocn(args
, argsSize
,
305 sizeof(GStringFormatArg
));
313 args
[argsLen
].i
= va_arg(argList
, int);
319 args
[argsLen
].ui
= va_arg(argList
, Guint
);
325 args
[argsLen
].l
= va_arg(argList
, long);
327 case fmtULongDecimal
:
331 args
[argsLen
].ul
= va_arg(argList
, Gulong
);
335 args
[argsLen
].f
= va_arg(argList
, double);
338 args
[argsLen
].c
= (char)va_arg(argList
, int);
341 args
[argsLen
].s
= va_arg(argList
, char *);
344 args
[argsLen
].gs
= va_arg(argList
, GString
*);
350 // format the argument
354 formatInt(arg
.i
, buf
, sizeof(buf
), zeroFill
, width
, 10, &str
, &len
);
357 formatInt(arg
.i
, buf
, sizeof(buf
), zeroFill
, width
, 16, &str
, &len
);
360 formatInt(arg
.i
, buf
, sizeof(buf
), zeroFill
, width
, 8, &str
, &len
);
363 formatInt(arg
.i
, buf
, sizeof(buf
), zeroFill
, width
, 2, &str
, &len
);
366 formatUInt(arg
.ui
, buf
, sizeof(buf
), zeroFill
, width
, 10,
370 formatUInt(arg
.ui
, buf
, sizeof(buf
), zeroFill
, width
, 16,
374 formatUInt(arg
.ui
, buf
, sizeof(buf
), zeroFill
, width
, 8, &str
, &len
);
377 formatUInt(arg
.ui
, buf
, sizeof(buf
), zeroFill
, width
, 2, &str
, &len
);
380 formatInt(arg
.l
, buf
, sizeof(buf
), zeroFill
, width
, 10, &str
, &len
);
383 formatInt(arg
.l
, buf
, sizeof(buf
), zeroFill
, width
, 16, &str
, &len
);
386 formatInt(arg
.l
, buf
, sizeof(buf
), zeroFill
, width
, 8, &str
, &len
);
389 formatInt(arg
.l
, buf
, sizeof(buf
), zeroFill
, width
, 2, &str
, &len
);
391 case fmtULongDecimal
:
392 formatUInt(arg
.ul
, buf
, sizeof(buf
), zeroFill
, width
, 10,
396 formatUInt(arg
.ul
, buf
, sizeof(buf
), zeroFill
, width
, 16,
400 formatUInt(arg
.ul
, buf
, sizeof(buf
), zeroFill
, width
, 8, &str
, &len
);
403 formatUInt(arg
.ul
, buf
, sizeof(buf
), zeroFill
, width
, 2, &str
, &len
);
406 formatDouble(arg
.f
, buf
, sizeof(buf
), prec
, gFalse
, &str
, &len
);
409 formatDouble(arg
.f
, buf
, sizeof(buf
), prec
, gTrue
, &str
, &len
);
415 reverseAlign
= !reverseAlign
;
420 reverseAlign
= !reverseAlign
;
423 str
= arg
.gs
->getCString();
424 len
= arg
.gs
->getLength();
425 reverseAlign
= !reverseAlign
;
434 // append the formatted arg, handling width and alignment
435 if (!reverseAlign
&& len
< width
) {
436 for (i
= len
; i
< width
; ++i
) {
441 if (reverseAlign
&& len
< width
) {
442 for (i
= len
; i
< width
; ++i
) {
448 } else if (*p0
== '}') {
456 for (p1
= p0
+ 1; *p1
&& *p1
!= '{' && *p1
!= '}'; ++p1
) ;
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";
481 while (i
> start
&& x
) {
482 buf
[--i
] = vals
[x
% base
];
487 for (j
= bufSize
- i
; i
> start
&& j
< width
- start
; ++j
) {
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";
509 buf
[--i
] = vals
[x
% base
];
514 for (j
= bufSize
- i
; i
> 0 && j
< width
; ++j
) {
522 void GString::formatDouble(double x
, char *buf
, int bufSize
, int prec
,
523 GBool trim
, char **p
, int *len
) {
531 x
= floor(x
* pow(10, prec
) + 0.5);
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) {
543 if (i
> 1 && started
) {
548 x2
= floor(0.1 * (x
+ 0.5));
549 d
= (int)floor(x
- 10 * x2
+ 0.5);
552 } while (i
> 1 && x
);
561 GString
*GString::insert(int i
, char c
) {
565 for (j
= length
+ 1; j
> i
; --j
)
572 GString
*GString::insert(int i
, GString
*str
) {
573 int n
= str
->getLength();
577 for (j
= length
; j
>= i
; --j
)
579 memcpy(s
+i
, str
->getCString(), n
);
584 GString
*GString::insert(int i
, const char *str
) {
589 for (j
= length
; j
>= i
; --j
)
596 GString
*GString::insert(int i
, const char *str
, int lengthA
) {
599 resize(length
+ lengthA
);
600 for (j
= length
; j
>= i
; --j
)
602 memcpy(s
+i
, str
, lengthA
);
607 GString
*GString::del(int i
, int n
) {
611 if (i
+ n
> length
) {
614 for (j
= i
; j
<= length
- n
; ++j
) {
622 GString
*GString::upperCase() {
625 for (i
= 0; i
< length
; ++i
) {
627 s
[i
] = toupper(s
[i
]);
632 GString
*GString::lowerCase() {
635 for (i
= 0; i
< length
; ++i
) {
637 s
[i
] = tolower(s
[i
]);
642 int GString::cmp(GString
*str
) {
648 for (i
= 0, p1
= s
, p2
= str
->s
; i
< n1
&& i
< n2
; ++i
, ++p1
, ++p2
) {
657 int GString::cmpN(GString
*str
, int n
) {
663 for (i
= 0, p1
= s
, p2
= str
->s
;
664 i
< n1
&& i
< n2
&& i
< n
;
677 int GString::cmp(const char *sA
) {
682 for (i
= 0, p1
= s
, p2
= sA
; i
< n1
&& *p2
; ++i
, ++p1
, ++p2
) {
697 int GString::cmpN(const char *sA
, int n
) {
702 for (i
= 0, p1
= s
, p2
= sA
; i
< n1
&& *p2
&& i
< n
; ++i
, ++p1
, ++p2
) {