/src/xpdf-4.04/goo/GString.cc
Line | Count | Source (jump to first uncovered line) |
1 | | //======================================================================== |
2 | | // |
3 | | // GString.cc |
4 | | // |
5 | | // Simple variable-length string type. |
6 | | // |
7 | | // Copyright 1996-2003 Glyph & Cog, LLC |
8 | | // |
9 | | //======================================================================== |
10 | | |
11 | | #include <aconf.h> |
12 | | |
13 | | #ifdef USE_GCC_PRAGMAS |
14 | | #pragma implementation |
15 | | #endif |
16 | | |
17 | | #include <stdlib.h> |
18 | | #include <stddef.h> |
19 | | #include <string.h> |
20 | | #include <ctype.h> |
21 | | #include <math.h> |
22 | | #include <limits.h> |
23 | | #include "gmem.h" |
24 | | #include "gmempp.h" |
25 | | #include "GString.h" |
26 | | |
27 | | //------------------------------------------------------------------------ |
28 | | |
29 | | union GStringFormatArg { |
30 | | int i; |
31 | | Guint ui; |
32 | | long l; |
33 | | Gulong ul; |
34 | | #ifdef LLONG_MAX |
35 | | long long ll; |
36 | | #endif |
37 | | #ifdef ULLONG_MAX |
38 | | unsigned long long ull; |
39 | | #endif |
40 | | double f; |
41 | | char c; |
42 | | char *s; |
43 | | GString *gs; |
44 | | }; |
45 | | |
46 | | enum GStringFormatType { |
47 | | fmtIntDecimal, |
48 | | fmtIntHex, |
49 | | fmtIntOctal, |
50 | | fmtIntBinary, |
51 | | fmtUIntDecimal, |
52 | | fmtUIntHex, |
53 | | fmtUIntOctal, |
54 | | fmtUIntBinary, |
55 | | fmtLongDecimal, |
56 | | fmtLongHex, |
57 | | fmtLongOctal, |
58 | | fmtLongBinary, |
59 | | fmtULongDecimal, |
60 | | fmtULongHex, |
61 | | fmtULongOctal, |
62 | | fmtULongBinary, |
63 | | #ifdef LLONG_MAX |
64 | | fmtLongLongDecimal, |
65 | | fmtLongLongHex, |
66 | | fmtLongLongOctal, |
67 | | fmtLongLongBinary, |
68 | | #endif |
69 | | #ifdef ULLONG_MAX |
70 | | fmtULongLongDecimal, |
71 | | fmtULongLongHex, |
72 | | fmtULongLongOctal, |
73 | | fmtULongLongBinary, |
74 | | #endif |
75 | | fmtDouble, |
76 | | fmtDoubleTrim, |
77 | | fmtChar, |
78 | | fmtString, |
79 | | fmtGString, |
80 | | fmtSpace |
81 | | }; |
82 | | |
83 | | static const char *formatStrings[] = { |
84 | | "d", "x", "o", "b", "ud", "ux", "uo", "ub", |
85 | | "ld", "lx", "lo", "lb", "uld", "ulx", "ulo", "ulb", |
86 | | #ifdef LLONG_MAX |
87 | | "lld", "llx", "llo", "llb", |
88 | | #endif |
89 | | #ifdef ULLONG_MAX |
90 | | "ulld", "ullx", "ullo", "ullb", |
91 | | #endif |
92 | | "f", "g", |
93 | | "c", |
94 | | "s", |
95 | | "t", |
96 | | "w", |
97 | | NULL |
98 | | }; |
99 | | |
100 | | //------------------------------------------------------------------------ |
101 | | |
102 | 30.3M | static inline int size(int len) { |
103 | 30.3M | int delta; |
104 | 344M | for (delta = 8; delta < len && delta < 0x100000; delta <<= 1) ; |
105 | 30.3M | if (len > INT_MAX - delta) { |
106 | 0 | gMemError("Integer overflow in GString::size()"); |
107 | 0 | } |
108 | | // this is ((len + 1) + (delta - 1)) & ~(delta - 1) |
109 | 30.3M | return (len + delta) & ~(delta - 1); |
110 | 30.3M | } |
111 | | |
112 | 17.7M | inline void GString::resize(int length1) { |
113 | 17.7M | char *s1; |
114 | | |
115 | 17.7M | if (length1 < 0) { |
116 | 0 | gMemError("GString::resize() with negative length"); |
117 | 0 | } |
118 | 17.7M | if (!s) { |
119 | 5.31M | s = new char[size(length1)]; |
120 | 12.4M | } else if (size(length1) != size(length)) { |
121 | 105k | s1 = new char[size(length1)]; |
122 | 105k | if (length1 < length) { |
123 | 0 | memcpy(s1, s, length1); |
124 | 0 | s1[length1] = '\0'; |
125 | 105k | } else { |
126 | 105k | memcpy(s1, s, length + 1); |
127 | 105k | } |
128 | 105k | delete[] s; |
129 | 105k | s = s1; |
130 | 105k | } |
131 | 17.7M | } |
132 | | |
133 | 4.19M | GString::GString() { |
134 | 4.19M | s = NULL; |
135 | 4.19M | resize(length = 0); |
136 | 4.19M | s[0] = '\0'; |
137 | 4.19M | } |
138 | | |
139 | 1.09M | GString::GString(const char *sA) { |
140 | 1.09M | int n = (int)strlen(sA); |
141 | | |
142 | 1.09M | s = NULL; |
143 | 1.09M | resize(length = n); |
144 | 1.09M | memcpy(s, sA, n + 1); |
145 | 1.09M | } |
146 | | |
147 | 27.0k | GString::GString(const char *sA, int lengthA) { |
148 | 27.0k | s = NULL; |
149 | 27.0k | resize(length = lengthA); |
150 | 27.0k | memcpy(s, sA, length * sizeof(char)); |
151 | 27.0k | s[length] = '\0'; |
152 | 27.0k | } |
153 | | |
154 | 0 | GString::GString(GString *str, int idx, int lengthA) { |
155 | 0 | s = NULL; |
156 | 0 | resize(length = lengthA); |
157 | 0 | memcpy(s, str->getCString() + idx, length); |
158 | 0 | s[length] = '\0'; |
159 | 0 | } |
160 | | |
161 | 0 | GString::GString(GString *str) { |
162 | 0 | s = NULL; |
163 | 0 | resize(length = str->getLength()); |
164 | 0 | memcpy(s, str->getCString(), length + 1); |
165 | 0 | } |
166 | | |
167 | 0 | GString::GString(GString *str1, GString *str2) { |
168 | 0 | int n1 = str1->getLength(); |
169 | 0 | int n2 = str2->getLength(); |
170 | |
|
171 | 0 | s = NULL; |
172 | 0 | if (n1 > INT_MAX - n2) { |
173 | 0 | gMemError("Integer overflow in GString::GString()"); |
174 | 0 | } |
175 | 0 | resize(length = n1 + n2); |
176 | 0 | memcpy(s, str1->getCString(), n1); |
177 | 0 | memcpy(s + n1, str2->getCString(), n2 + 1); |
178 | 0 | } |
179 | | |
180 | 0 | GString *GString::fromInt(int x) { |
181 | 0 | char buf[24]; // enough space for 64-bit ints plus a little extra |
182 | 0 | const char *p; |
183 | 0 | int len; |
184 | |
|
185 | 0 | formatInt(x, buf, sizeof(buf), gFalse, 0, 10, &p, &len); |
186 | 0 | return new GString(p, len); |
187 | 0 | } |
188 | | |
189 | 0 | GString *GString::format(const char *fmt, ...) { |
190 | 0 | va_list argList; |
191 | 0 | GString *s; |
192 | |
|
193 | 0 | s = new GString(); |
194 | 0 | va_start(argList, fmt); |
195 | 0 | s->appendfv(fmt, argList); |
196 | 0 | va_end(argList); |
197 | 0 | return s; |
198 | 0 | } |
199 | | |
200 | 0 | GString *GString::formatv(const char *fmt, va_list argList) { |
201 | 0 | GString *s; |
202 | |
|
203 | 0 | s = new GString(); |
204 | 0 | s->appendfv(fmt, argList); |
205 | 0 | return s; |
206 | 0 | } |
207 | | |
208 | 5.31M | GString::~GString() { |
209 | 5.31M | delete[] s; |
210 | 5.31M | } |
211 | | |
212 | 0 | GString *GString::clear() { |
213 | 0 | s[length = 0] = '\0'; |
214 | 0 | resize(0); |
215 | 0 | return this; |
216 | 0 | } |
217 | | |
218 | 11.1M | GString *GString::append(char c) { |
219 | 11.1M | if (length > INT_MAX - 1) { |
220 | 0 | gMemError("Integer overflow in GString::append()"); |
221 | 0 | } |
222 | 11.1M | resize(length + 1); |
223 | 11.1M | s[length++] = c; |
224 | 11.1M | s[length] = '\0'; |
225 | 11.1M | return this; |
226 | 11.1M | } |
227 | | |
228 | 1.09M | GString *GString::append(GString *str) { |
229 | 1.09M | int n = str->getLength(); |
230 | | |
231 | 1.09M | if (length > INT_MAX - n) { |
232 | 0 | gMemError("Integer overflow in GString::append()"); |
233 | 0 | } |
234 | 1.09M | resize(length + n); |
235 | 1.09M | memcpy(s + length, str->getCString(), n + 1); |
236 | 1.09M | length += n; |
237 | 1.09M | return this; |
238 | 1.09M | } |
239 | | |
240 | 0 | GString *GString::append(const char *str) { |
241 | 0 | int n = (int)strlen(str); |
242 | |
|
243 | 0 | if (length > INT_MAX - n) { |
244 | 0 | gMemError("Integer overflow in GString::append()"); |
245 | 0 | } |
246 | 0 | resize(length + n); |
247 | 0 | memcpy(s + length, str, n + 1); |
248 | 0 | length += n; |
249 | 0 | return this; |
250 | 0 | } |
251 | | |
252 | 227k | GString *GString::append(const char *str, int lengthA) { |
253 | 227k | if (lengthA < 0 || length > INT_MAX - lengthA) { |
254 | 0 | gMemError("Integer overflow in GString::append()"); |
255 | 0 | } |
256 | 227k | resize(length + lengthA); |
257 | 227k | memcpy(s + length, str, lengthA); |
258 | 227k | length += lengthA; |
259 | 227k | s[length] = '\0'; |
260 | 227k | return this; |
261 | 227k | } |
262 | | |
263 | 0 | GString *GString::appendf(const char *fmt, ...) { |
264 | 0 | va_list argList; |
265 | |
|
266 | 0 | va_start(argList, fmt); |
267 | 0 | appendfv(fmt, argList); |
268 | 0 | va_end(argList); |
269 | 0 | return this; |
270 | 0 | } |
271 | | |
272 | 0 | GString *GString::appendfv(const char *fmt, va_list argList) { |
273 | 0 | GStringFormatArg *args; |
274 | 0 | int argsLen, argsSize; |
275 | 0 | GStringFormatArg arg; |
276 | 0 | int idx, width, prec; |
277 | 0 | GBool reverseAlign, zeroFill; |
278 | 0 | GStringFormatType ft; |
279 | 0 | char buf[65]; |
280 | 0 | int len, i; |
281 | 0 | const char *p0, *p1; |
282 | 0 | const char *str; |
283 | |
|
284 | 0 | argsLen = 0; |
285 | 0 | argsSize = 8; |
286 | 0 | args = (GStringFormatArg *)gmallocn(argsSize, sizeof(GStringFormatArg)); |
287 | |
|
288 | 0 | p0 = fmt; |
289 | 0 | while (*p0) { |
290 | 0 | if (*p0 == '{') { |
291 | 0 | ++p0; |
292 | 0 | if (*p0 == '{') { |
293 | 0 | ++p0; |
294 | 0 | append('{'); |
295 | 0 | } else { |
296 | | |
297 | | // parse the format string |
298 | 0 | if (!(*p0 >= '0' && *p0 <= '9')) { |
299 | 0 | break; |
300 | 0 | } |
301 | 0 | idx = *p0 - '0'; |
302 | 0 | for (++p0; *p0 >= '0' && *p0 <= '9'; ++p0) { |
303 | 0 | idx = 10 * idx + (*p0 - '0'); |
304 | 0 | } |
305 | 0 | if (*p0 != ':') { |
306 | 0 | break; |
307 | 0 | } |
308 | 0 | ++p0; |
309 | 0 | if (*p0 == '-') { |
310 | 0 | reverseAlign = gTrue; |
311 | 0 | ++p0; |
312 | 0 | } else { |
313 | 0 | reverseAlign = gFalse; |
314 | 0 | } |
315 | 0 | width = 0; |
316 | 0 | zeroFill = *p0 == '0'; |
317 | 0 | for (; *p0 >= '0' && *p0 <= '9'; ++p0) { |
318 | 0 | width = 10 * width + (*p0 - '0'); |
319 | 0 | } |
320 | 0 | if (width < 0) { |
321 | 0 | width = 0; |
322 | 0 | } |
323 | 0 | if (*p0 == '.') { |
324 | 0 | ++p0; |
325 | 0 | prec = 0; |
326 | 0 | for (; *p0 >= '0' && *p0 <= '9'; ++p0) { |
327 | 0 | prec = 10 * prec + (*p0 - '0'); |
328 | 0 | } |
329 | 0 | } else { |
330 | 0 | prec = 0; |
331 | 0 | } |
332 | 0 | for (ft = (GStringFormatType)0; |
333 | 0 | formatStrings[ft]; |
334 | 0 | ft = (GStringFormatType)(ft + 1)) { |
335 | 0 | if (!strncmp(p0, formatStrings[ft], strlen(formatStrings[ft]))) { |
336 | 0 | break; |
337 | 0 | } |
338 | 0 | } |
339 | 0 | if (!formatStrings[ft]) { |
340 | 0 | break; |
341 | 0 | } |
342 | 0 | p0 += strlen(formatStrings[ft]); |
343 | 0 | if (*p0 != '}') { |
344 | 0 | break; |
345 | 0 | } |
346 | 0 | ++p0; |
347 | | |
348 | | // fetch the argument |
349 | 0 | if (idx > argsLen) { |
350 | 0 | break; |
351 | 0 | } |
352 | 0 | if (idx == argsLen) { |
353 | 0 | if (argsLen == argsSize) { |
354 | 0 | argsSize *= 2; |
355 | 0 | args = (GStringFormatArg *)greallocn(args, argsSize, |
356 | 0 | sizeof(GStringFormatArg)); |
357 | 0 | } |
358 | 0 | switch (ft) { |
359 | 0 | case fmtIntDecimal: |
360 | 0 | case fmtIntHex: |
361 | 0 | case fmtIntOctal: |
362 | 0 | case fmtIntBinary: |
363 | 0 | case fmtSpace: |
364 | 0 | args[argsLen].i = va_arg(argList, int); |
365 | 0 | break; |
366 | 0 | case fmtUIntDecimal: |
367 | 0 | case fmtUIntHex: |
368 | 0 | case fmtUIntOctal: |
369 | 0 | case fmtUIntBinary: |
370 | 0 | args[argsLen].ui = va_arg(argList, Guint); |
371 | 0 | break; |
372 | 0 | case fmtLongDecimal: |
373 | 0 | case fmtLongHex: |
374 | 0 | case fmtLongOctal: |
375 | 0 | case fmtLongBinary: |
376 | 0 | args[argsLen].l = va_arg(argList, long); |
377 | 0 | break; |
378 | 0 | case fmtULongDecimal: |
379 | 0 | case fmtULongHex: |
380 | 0 | case fmtULongOctal: |
381 | 0 | case fmtULongBinary: |
382 | 0 | args[argsLen].ul = va_arg(argList, Gulong); |
383 | 0 | break; |
384 | 0 | #ifdef LLONG_MAX |
385 | 0 | case fmtLongLongDecimal: |
386 | 0 | case fmtLongLongHex: |
387 | 0 | case fmtLongLongOctal: |
388 | 0 | case fmtLongLongBinary: |
389 | 0 | args[argsLen].ll = va_arg(argList, long long); |
390 | 0 | break; |
391 | 0 | #endif |
392 | 0 | #ifdef ULLONG_MAX |
393 | 0 | case fmtULongLongDecimal: |
394 | 0 | case fmtULongLongHex: |
395 | 0 | case fmtULongLongOctal: |
396 | 0 | case fmtULongLongBinary: |
397 | 0 | args[argsLen].ull = va_arg(argList, unsigned long long); |
398 | 0 | break; |
399 | 0 | #endif |
400 | 0 | case fmtDouble: |
401 | 0 | case fmtDoubleTrim: |
402 | 0 | args[argsLen].f = va_arg(argList, double); |
403 | 0 | break; |
404 | 0 | case fmtChar: |
405 | 0 | args[argsLen].c = (char)va_arg(argList, int); |
406 | 0 | break; |
407 | 0 | case fmtString: |
408 | 0 | args[argsLen].s = va_arg(argList, char *); |
409 | 0 | break; |
410 | 0 | case fmtGString: |
411 | 0 | args[argsLen].gs = va_arg(argList, GString *); |
412 | 0 | break; |
413 | 0 | } |
414 | 0 | ++argsLen; |
415 | 0 | } |
416 | | |
417 | | // format the argument |
418 | 0 | arg = args[idx]; |
419 | 0 | switch (ft) { |
420 | 0 | case fmtIntDecimal: |
421 | 0 | formatInt(arg.i, buf, sizeof(buf), zeroFill, width, 10, &str, &len); |
422 | 0 | break; |
423 | 0 | case fmtIntHex: |
424 | 0 | formatInt(arg.i, buf, sizeof(buf), zeroFill, width, 16, &str, &len); |
425 | 0 | break; |
426 | 0 | case fmtIntOctal: |
427 | 0 | formatInt(arg.i, buf, sizeof(buf), zeroFill, width, 8, &str, &len); |
428 | 0 | break; |
429 | 0 | case fmtIntBinary: |
430 | 0 | formatInt(arg.i, buf, sizeof(buf), zeroFill, width, 2, &str, &len); |
431 | 0 | break; |
432 | 0 | case fmtUIntDecimal: |
433 | 0 | formatUInt(arg.ui, buf, sizeof(buf), zeroFill, width, 10, |
434 | 0 | &str, &len); |
435 | 0 | break; |
436 | 0 | case fmtUIntHex: |
437 | 0 | formatUInt(arg.ui, buf, sizeof(buf), zeroFill, width, 16, |
438 | 0 | &str, &len); |
439 | 0 | break; |
440 | 0 | case fmtUIntOctal: |
441 | 0 | formatUInt(arg.ui, buf, sizeof(buf), zeroFill, width, 8, &str, &len); |
442 | 0 | break; |
443 | 0 | case fmtUIntBinary: |
444 | 0 | formatUInt(arg.ui, buf, sizeof(buf), zeroFill, width, 2, &str, &len); |
445 | 0 | break; |
446 | 0 | case fmtLongDecimal: |
447 | 0 | formatInt(arg.l, buf, sizeof(buf), zeroFill, width, 10, &str, &len); |
448 | 0 | break; |
449 | 0 | case fmtLongHex: |
450 | 0 | formatInt(arg.l, buf, sizeof(buf), zeroFill, width, 16, &str, &len); |
451 | 0 | break; |
452 | 0 | case fmtLongOctal: |
453 | 0 | formatInt(arg.l, buf, sizeof(buf), zeroFill, width, 8, &str, &len); |
454 | 0 | break; |
455 | 0 | case fmtLongBinary: |
456 | 0 | formatInt(arg.l, buf, sizeof(buf), zeroFill, width, 2, &str, &len); |
457 | 0 | break; |
458 | 0 | case fmtULongDecimal: |
459 | 0 | formatUInt(arg.ul, buf, sizeof(buf), zeroFill, width, 10, |
460 | 0 | &str, &len); |
461 | 0 | break; |
462 | 0 | case fmtULongHex: |
463 | 0 | formatUInt(arg.ul, buf, sizeof(buf), zeroFill, width, 16, |
464 | 0 | &str, &len); |
465 | 0 | break; |
466 | 0 | case fmtULongOctal: |
467 | 0 | formatUInt(arg.ul, buf, sizeof(buf), zeroFill, width, 8, &str, &len); |
468 | 0 | break; |
469 | 0 | case fmtULongBinary: |
470 | 0 | formatUInt(arg.ul, buf, sizeof(buf), zeroFill, width, 2, &str, &len); |
471 | 0 | break; |
472 | 0 | #ifdef LLONG_MAX |
473 | 0 | case fmtLongLongDecimal: |
474 | 0 | formatInt(arg.ll, buf, sizeof(buf), zeroFill, width, 10, &str, &len); |
475 | 0 | break; |
476 | 0 | case fmtLongLongHex: |
477 | 0 | formatInt(arg.ll, buf, sizeof(buf), zeroFill, width, 16, &str, &len); |
478 | 0 | break; |
479 | 0 | case fmtLongLongOctal: |
480 | 0 | formatInt(arg.ll, buf, sizeof(buf), zeroFill, width, 8, &str, &len); |
481 | 0 | break; |
482 | 0 | case fmtLongLongBinary: |
483 | 0 | formatInt(arg.ll, buf, sizeof(buf), zeroFill, width, 2, &str, &len); |
484 | 0 | break; |
485 | 0 | #endif |
486 | 0 | #ifdef ULLONG_MAX |
487 | 0 | case fmtULongLongDecimal: |
488 | 0 | formatUInt(arg.ull, buf, sizeof(buf), zeroFill, width, 10, |
489 | 0 | &str, &len); |
490 | 0 | break; |
491 | 0 | case fmtULongLongHex: |
492 | 0 | formatUInt(arg.ull, buf, sizeof(buf), zeroFill, width, 16, |
493 | 0 | &str, &len); |
494 | 0 | break; |
495 | 0 | case fmtULongLongOctal: |
496 | 0 | formatUInt(arg.ull, buf, sizeof(buf), zeroFill, width, 8, |
497 | 0 | &str, &len); |
498 | 0 | break; |
499 | 0 | case fmtULongLongBinary: |
500 | 0 | formatUInt(arg.ull, buf, sizeof(buf), zeroFill, width, 2, |
501 | 0 | &str, &len); |
502 | 0 | break; |
503 | 0 | #endif |
504 | 0 | case fmtDouble: |
505 | 0 | formatDouble(arg.f, buf, sizeof(buf), prec, gFalse, &str, &len); |
506 | 0 | break; |
507 | 0 | case fmtDoubleTrim: |
508 | 0 | formatDouble(arg.f, buf, sizeof(buf), prec, gTrue, &str, &len); |
509 | 0 | break; |
510 | 0 | case fmtChar: |
511 | 0 | buf[0] = arg.c; |
512 | 0 | str = buf; |
513 | 0 | len = 1; |
514 | 0 | reverseAlign = !reverseAlign; |
515 | 0 | break; |
516 | 0 | case fmtString: |
517 | 0 | if (arg.s) { |
518 | 0 | str = arg.s; |
519 | 0 | len = (int)strlen(str); |
520 | 0 | } else { |
521 | 0 | str = "(null)"; |
522 | 0 | len = 6; |
523 | 0 | } |
524 | 0 | reverseAlign = !reverseAlign; |
525 | 0 | break; |
526 | 0 | case fmtGString: |
527 | 0 | if (arg.gs) { |
528 | 0 | str = arg.gs->getCString(); |
529 | 0 | len = arg.gs->getLength(); |
530 | 0 | } else { |
531 | 0 | str = "(null)"; |
532 | 0 | len = 6; |
533 | 0 | } |
534 | 0 | reverseAlign = !reverseAlign; |
535 | 0 | break; |
536 | 0 | case fmtSpace: |
537 | 0 | str = buf; |
538 | 0 | len = 0; |
539 | 0 | width = arg.i; |
540 | 0 | break; |
541 | 0 | } |
542 | | |
543 | | // append the formatted arg, handling width and alignment |
544 | 0 | if (!reverseAlign && len < width) { |
545 | 0 | for (i = len; i < width; ++i) { |
546 | 0 | append(' '); |
547 | 0 | } |
548 | 0 | } |
549 | 0 | append(str, len); |
550 | 0 | if (reverseAlign && len < width) { |
551 | 0 | for (i = len; i < width; ++i) { |
552 | 0 | append(' '); |
553 | 0 | } |
554 | 0 | } |
555 | 0 | } |
556 | |
|
557 | 0 | } else if (*p0 == '}') { |
558 | 0 | ++p0; |
559 | 0 | if (*p0 == '}') { |
560 | 0 | ++p0; |
561 | 0 | } |
562 | 0 | append('}'); |
563 | | |
564 | 0 | } else { |
565 | 0 | for (p1 = p0 + 1; *p1 && *p1 != '{' && *p1 != '}'; ++p1) ; |
566 | 0 | append(p0, (int)(p1 - p0)); |
567 | 0 | p0 = p1; |
568 | 0 | } |
569 | 0 | } |
570 | | |
571 | 0 | gfree(args); |
572 | 0 | return this; |
573 | 0 | } |
574 | | |
575 | | #ifdef LLONG_MAX |
576 | | void GString::formatInt(long long x, char *buf, int bufSize, |
577 | | GBool zeroFill, int width, int base, |
578 | 0 | const char **p, int *len) { |
579 | | #else |
580 | | void GString::formatInt(long x, char *buf, int bufSize, |
581 | | GBool zeroFill, int width, int base, |
582 | | const char **p, int *len) { |
583 | | #endif |
584 | 0 | static char vals[17] = "0123456789abcdef"; |
585 | 0 | GBool neg; |
586 | 0 | int start, i, j; |
587 | |
|
588 | 0 | i = bufSize; |
589 | 0 | if ((neg = x < 0)) { |
590 | 0 | x = -x; |
591 | 0 | } |
592 | 0 | start = neg ? 1 : 0; |
593 | 0 | if (x == 0) { |
594 | 0 | buf[--i] = '0'; |
595 | 0 | } else { |
596 | 0 | while (i > start && x) { |
597 | 0 | buf[--i] = vals[x % base]; |
598 | 0 | x /= base; |
599 | 0 | } |
600 | 0 | } |
601 | 0 | if (zeroFill) { |
602 | 0 | for (j = bufSize - i; i > start && j < width - start; ++j) { |
603 | 0 | buf[--i] = '0'; |
604 | 0 | } |
605 | 0 | } |
606 | 0 | if (neg) { |
607 | 0 | buf[--i] = '-'; |
608 | 0 | } |
609 | 0 | *p = buf + i; |
610 | 0 | *len = bufSize - i; |
611 | 0 | } |
612 | | |
613 | | #ifdef ULLONG_MAX |
614 | | void GString::formatUInt(unsigned long long x, char *buf, int bufSize, |
615 | | GBool zeroFill, int width, int base, |
616 | 0 | const char **p, int *len) { |
617 | | #else |
618 | | void GString::formatUInt(Gulong x, char *buf, int bufSize, |
619 | | GBool zeroFill, int width, int base, |
620 | | const char **p, int *len) { |
621 | | #endif |
622 | 0 | static char vals[17] = "0123456789abcdef"; |
623 | 0 | int i, j; |
624 | |
|
625 | 0 | i = bufSize; |
626 | 0 | if (x == 0) { |
627 | 0 | buf[--i] = '0'; |
628 | 0 | } else { |
629 | 0 | while (i > 0 && x) { |
630 | 0 | buf[--i] = vals[x % base]; |
631 | 0 | x /= base; |
632 | 0 | } |
633 | 0 | } |
634 | 0 | if (zeroFill) { |
635 | 0 | for (j = bufSize - i; i > 0 && j < width; ++j) { |
636 | 0 | buf[--i] = '0'; |
637 | 0 | } |
638 | 0 | } |
639 | 0 | *p = buf + i; |
640 | 0 | *len = bufSize - i; |
641 | 0 | } |
642 | | |
643 | | void GString::formatDouble(double x, char *buf, int bufSize, int prec, |
644 | 0 | GBool trim, const char **p, int *len) { |
645 | 0 | GBool neg, started; |
646 | 0 | double x2; |
647 | 0 | int d, i, j; |
648 | |
|
649 | 0 | if ((neg = x < 0)) { |
650 | 0 | x = -x; |
651 | 0 | } |
652 | 0 | x = floor(x * pow(10.0, prec) + 0.5); |
653 | 0 | i = bufSize; |
654 | 0 | started = !trim; |
655 | 0 | for (j = 0; j < prec && i > 1; ++j) { |
656 | 0 | x2 = floor(0.1 * (x + 0.5)); |
657 | 0 | d = (int)floor(x - 10 * x2 + 0.5); |
658 | 0 | if (started || d != 0) { |
659 | 0 | buf[--i] = (char)('0' + d); |
660 | 0 | started = gTrue; |
661 | 0 | } |
662 | 0 | x = x2; |
663 | 0 | } |
664 | 0 | if (i > 1 && started) { |
665 | 0 | buf[--i] = '.'; |
666 | 0 | } |
667 | 0 | if (i > 1) { |
668 | 0 | do { |
669 | 0 | x2 = floor(0.1 * (x + 0.5)); |
670 | 0 | d = (int)floor(x - 10 * x2 + 0.5); |
671 | 0 | buf[--i] = (char)('0' + d); |
672 | 0 | x = x2; |
673 | 0 | } while (i > 1 && x); |
674 | 0 | } |
675 | 0 | if (neg) { |
676 | 0 | buf[--i] = '-'; |
677 | 0 | } |
678 | 0 | *p = buf + i; |
679 | 0 | *len = bufSize - i; |
680 | 0 | } |
681 | | |
682 | 0 | GString *GString::insert(int i, char c) { |
683 | 0 | int j; |
684 | |
|
685 | 0 | if (length > INT_MAX - 1) { |
686 | 0 | gMemError("Integer overflow in GString::insert()"); |
687 | 0 | } |
688 | 0 | resize(length + 1); |
689 | 0 | for (j = length + 1; j > i; --j) |
690 | 0 | s[j] = s[j-1]; |
691 | 0 | s[i] = c; |
692 | 0 | ++length; |
693 | 0 | return this; |
694 | 0 | } |
695 | | |
696 | 0 | GString *GString::insert(int i, GString *str) { |
697 | 0 | int n = str->getLength(); |
698 | 0 | int j; |
699 | |
|
700 | 0 | if (length > INT_MAX - n) { |
701 | 0 | gMemError("Integer overflow in GString::insert()"); |
702 | 0 | } |
703 | 0 | resize(length + n); |
704 | 0 | for (j = length; j >= i; --j) |
705 | 0 | s[j+n] = s[j]; |
706 | 0 | memcpy(s+i, str->getCString(), n); |
707 | 0 | length += n; |
708 | 0 | return this; |
709 | 0 | } |
710 | | |
711 | 0 | GString *GString::insert(int i, const char *str) { |
712 | 0 | int n = (int)strlen(str); |
713 | 0 | int j; |
714 | |
|
715 | 0 | if (length > INT_MAX - n) { |
716 | 0 | gMemError("Integer overflow in GString::insert()"); |
717 | 0 | } |
718 | 0 | resize(length + n); |
719 | 0 | for (j = length; j >= i; --j) |
720 | 0 | s[j+n] = s[j]; |
721 | 0 | memcpy(s+i, str, n); |
722 | 0 | length += n; |
723 | 0 | return this; |
724 | 0 | } |
725 | | |
726 | 0 | GString *GString::insert(int i, const char *str, int lengthA) { |
727 | 0 | int j; |
728 | |
|
729 | 0 | if (lengthA < 0 || length > INT_MAX - lengthA) { |
730 | 0 | gMemError("Integer overflow in GString::insert()"); |
731 | 0 | } |
732 | 0 | resize(length + lengthA); |
733 | 0 | for (j = length; j >= i; --j) |
734 | 0 | s[j+lengthA] = s[j]; |
735 | 0 | memcpy(s+i, str, lengthA); |
736 | 0 | length += lengthA; |
737 | 0 | return this; |
738 | 0 | } |
739 | | |
740 | 0 | GString *GString::del(int i, int n) { |
741 | 0 | int j; |
742 | |
|
743 | 0 | if (i >= 0 && n > 0 && i <= INT_MAX - n) { |
744 | 0 | if (i + n > length) { |
745 | 0 | n = length - i; |
746 | 0 | } |
747 | 0 | for (j = i; j <= length - n; ++j) { |
748 | 0 | s[j] = s[j + n]; |
749 | 0 | } |
750 | 0 | resize(length -= n); |
751 | 0 | } |
752 | 0 | return this; |
753 | 0 | } |
754 | | |
755 | 0 | GString *GString::upperCase() { |
756 | 0 | int i; |
757 | |
|
758 | 0 | for (i = 0; i < length; ++i) { |
759 | 0 | if (islower(s[i] & 0xff)) { |
760 | 0 | s[i] = (char)toupper(s[i] & 0xff); |
761 | 0 | } |
762 | 0 | } |
763 | 0 | return this; |
764 | 0 | } |
765 | | |
766 | 0 | GString *GString::lowerCase() { |
767 | 0 | int i; |
768 | |
|
769 | 0 | for (i = 0; i < length; ++i) { |
770 | 0 | if (isupper(s[i] & 0xff)) { |
771 | 0 | s[i] = (char)tolower(s[i] & 0xff); |
772 | 0 | } |
773 | 0 | } |
774 | 0 | return this; |
775 | 0 | } |
776 | | |
777 | 0 | int GString::cmp(GString *str) { |
778 | 0 | int n1, n2, i, x; |
779 | 0 | char *p1, *p2; |
780 | |
|
781 | 0 | n1 = length; |
782 | 0 | n2 = str->length; |
783 | 0 | for (i = 0, p1 = s, p2 = str->s; i < n1 && i < n2; ++i, ++p1, ++p2) { |
784 | 0 | x = (*p1 & 0xff) - (*p2 & 0xff); |
785 | 0 | if (x != 0) { |
786 | 0 | return x; |
787 | 0 | } |
788 | 0 | } |
789 | 0 | return n1 - n2; |
790 | 0 | } |
791 | | |
792 | 0 | int GString::cmpN(GString *str, int n) { |
793 | 0 | int n1, n2, i, x; |
794 | 0 | char *p1, *p2; |
795 | |
|
796 | 0 | n1 = length; |
797 | 0 | n2 = str->length; |
798 | 0 | for (i = 0, p1 = s, p2 = str->s; |
799 | 0 | i < n1 && i < n2 && i < n; |
800 | 0 | ++i, ++p1, ++p2) { |
801 | 0 | x = (*p1 & 0xff) - (*p2 & 0xff); |
802 | 0 | if (x != 0) { |
803 | 0 | return x; |
804 | 0 | } |
805 | 0 | } |
806 | 0 | if (i == n) { |
807 | 0 | return 0; |
808 | 0 | } |
809 | 0 | return n1 - n2; |
810 | 0 | } |
811 | | |
812 | 131 | int GString::cmp(const char *sA) { |
813 | 131 | int n1, i, x; |
814 | 131 | const char *p1, *p2; |
815 | | |
816 | 131 | n1 = length; |
817 | 181 | for (i = 0, p1 = s, p2 = sA; i < n1 && *p2; ++i, ++p1, ++p2) { |
818 | 78 | x = (*p1 & 0xff) - (*p2 & 0xff); |
819 | 78 | if (x != 0) { |
820 | 28 | return x; |
821 | 28 | } |
822 | 78 | } |
823 | 103 | if (i < n1) { |
824 | 9 | return 1; |
825 | 9 | } |
826 | 94 | if (*p2) { |
827 | 93 | return -1; |
828 | 93 | } |
829 | 1 | return 0; |
830 | 94 | } |
831 | | |
832 | 0 | int GString::cmpN(const char *sA, int n) { |
833 | 0 | int n1, i, x; |
834 | 0 | const char *p1, *p2; |
835 | |
|
836 | 0 | n1 = length; |
837 | 0 | for (i = 0, p1 = s, p2 = sA; i < n1 && *p2 && i < n; ++i, ++p1, ++p2) { |
838 | 0 | x = (*p1 & 0xff) - (*p2 & 0xff); |
839 | 0 | if (x != 0) { |
840 | 0 | return x; |
841 | 0 | } |
842 | 0 | } |
843 | 0 | if (i == n) { |
844 | 0 | return 0; |
845 | 0 | } |
846 | 0 | if (i < n1) { |
847 | 0 | return 1; |
848 | 0 | } |
849 | 0 | if (*p2) { |
850 | 0 | return -1; |
851 | 0 | } |
852 | 0 | return 0; |
853 | 0 | } |